【问题标题】:Instantiate object attributes with content of parsed/sliced substrings?用解析/切片子字符串的内容实例化对象属性?
【发布时间】:2018-04-05 00:32:20
【问题描述】:

Python 专家,

问题如下:

我有一个用 JSON 进行的大型机 AS/400 提取,被处理成一个“长”单个字符串,以便进一步切片/子字符串(如果这是一个词)。解析结果创建具有多个属性的模型实例。这些属性会生成一个OrderedDict() 以再次序列化(这是因为将来数据的来源可能会发生变化,我需要在此级别维护抽象)。我从最近的研究中了解到,将''(空字符串)的属性/数据维护为None 以在未来进行最佳分析的最佳方式。

for i, line in enumerate(data_json):
    swap_string += line['data']
    if data_json[i] == data_json[-1] or data_json[i+1]['data'][1] == '_':
        swap_list.append(swap_string)
        swap_string = ''

这是原始结果:

_ D 958.860 L B NA0.000 010 N 001 U 0 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 999 T00 000 99 999 -/- 001 BG/CODEBEDINGUNGEN : BG F04/F07/F20;

然后,有了这个字符串,我就有了一个'map'或一个'header'来生成可以序列化切片的对象等等:

slices = ['3:23', '23:24', '26:27', '29:38', '39:42', '43:46', '48:50', '51:52', '53:54', '55:58', '61:67', '72:79']

然后,我请求类实例化并创建这些属性:

def __init__(self, bm=None, kg=None, abm_saa=None, la=None, lt=None,
                   bu_su=None, pos=None, hws=None, sp=None, r=None, p=None,
                   asa=None, em_ab=None, em_bis=None, benennung=None,
                   asb=None, t_a=None, vkfbez=None, pws1=None, qu1=None,
                   pws2=None, qu2=None, da=None, anz=None, t_b=None,
                   bg=None, code=None, pruef=None, add_info=None):
    self.bm = bm
    self.kg = kg
    self.abm_saa = abm_saa...

然后问题来了:

我的问题是:使用带有切片分隔符的列表,如何使用 for 循环将对象实例化为应用列表理解的正确属性?是否也可以使用类中的属性进行循环?另外,使用简单的if 语句将空字符串作为None 应用到对象中?

for data in swap_list:
    for slice_str in slices:
        agr = PdsAGRMZDataModels()
        agr.abm_saa = data[slice_str].strip()
        agr.la = data[slice_str].strip()

【问题讨论】:

  • 感谢格式化@martineau

标签: python string object substring


【解决方案1】:

我没有看到 slices 数组中的值与它们上面显示的原始字符串之间的相关性,但是根据其余的解释,我相信您可以按照以下方式进行:

1) 将 slices 数组转换为可用作字符串范围的数字形式:(如果每行数据的范围都相同,则只执行一次)

ranges = [ (int(r[0]),int(r[1])) for r in [ s.split(":") for s in slices] ]

2) 对于数据集中的每一行,根据范围提取参数值:

params = [ [p,None][p==''] for p in [ line[start:end].strip() for start,end in ranges ] ]

# Note: [p,None][p==''] is a compact alternative to:  None if p == '' else p

3) 使用带有解包 (*) 的参数值列表来实例化您的模型对象:(这假设切片范围与构造函数的参数顺序相同)

agr = PdsAGRMZDataModels(*params)

# Based on your sample data and slices this would produce seemingly
# misaligned data content.  
#
# agr.bm       == '958.860 L B NA0.000'
# agr.kg       == None
# agr.abm_saa  == '0'
# ...

[编辑] 避免位置问题:

如果您想解决参数位置/计数约束,您可以对切片定义使用字典结构,以便提取的数据获得与函数参数匹配的关联名称。

例如:

 slices = { 'kg':(3,23), 'bm':(23,24), 'xyz':(5,52) }

使用 slices 字典,行的数据也可以在字典中生成命名值:

 data = { p:[v,None][v==''] for p,v in [(p,line[r[0]:r[1]].strip()) for p,r in slices.items()] }

然后,您可以使用检查模块来获取 PdsAGRMZDataModels() 构造函数的参数列表,并以正确的顺序将它们映射到您拥有的命名值(并对您没有的值使用 None )。此映射将始终以适当的顺序(独立于源数据)生成正确数量的参数。

[编辑]:getargspec 到 getfullargspec

 import inspect
 params = [data[arg] if arg in data else None for arg in inspect.getfullargspec(PdsAGRMZDataModels).args[1:]]
 # Note that, because we're calling a method, I'm dropping 
 # the first argument which corresponds to "self" and doesn't count.

有了这个,您可以使用任何源数据安全地调用模型构造函数,并且您的解决方案将对 API 更改或输入结构更改更具弹性。如果您从同一数据调用多个不同的函数(具有不同的参数名称),您甚至可以为同一切片指定多个名称。

agr = PdsAGRMZDataModels(*params)
# The constructor gets bm= and kg= in the right order, 
# and None for all other parameters.  
# The xyz value is ignored since PdsAGRMZDataModels() has no such parameter.  

【讨论】:

  • 嗨@Alain T.,感谢您的见解。我从他们那里学到了很多。我还阅读了另一篇引用ClassName(*params) 的帖子的另一个问题是,参数的顺序是否应该与范围(切片)相同?现在发布的问题更具启发性,但仍然是一个有效的疑问。此外,不幸的是,这种方法严重依赖用户。您知道可以提供较少人为干扰过程的替代方法(RegEx、machine_learning 解析工具等)吗?
  • 您编辑中添加的检查方法也是非常好的答案。非常感谢您的宝贵时间。
  • 只是提醒一下:inspect.getargspec 已被弃用。使用inspect.signature 或inspect.getfullargspec。我后者成功了。
猜你喜欢
  • 2021-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
  • 2013-05-18
  • 2021-08-24
  • 1970-01-01
  • 2015-07-13
相关资源
最近更新 更多