在Python中动态创建具有特定类型的变量

在Python中动态创建具有特定类型的变量,python,Python,在读取带有值的文本文件时,我想动态创建变量 我将这些值存储在一个列表中: values = list(content[startline].split() for i in range(_n_lines)) content是一个行列表 变量名存储在元组的元组中,具体取决于我正在读取的块: variable_names = ( ('_idx_brg', 'stn', 'stn_rel', '_n_lines', '_brg_type'), ('D', 'L', 'Cb', 'vi

在读取带有值的文本文件时,我想动态创建变量

我将这些值存储在一个列表中:

values = list(content[startline].split() for i in range(_n_lines))
content
是一个行列表

变量名存储在元组的元组中,具体取决于我正在读取的块:

variable_names = (
    ('_idx_brg', 'stn', 'stn_rel', '_n_lines', '_brg_type'),
    ('D', 'L', 'Cb', 'visc'),
    ('stiff', 'damp'),
    ('damp_model', ''))
默认情况下,我将值转换为浮点值:

for irow,row in enumerate(variable_names):
    for icol,col in enumerate(row):
        if col:
            val = float(values[irow][icol])
            setattr(self, col, val)
这是我的问题:

在某些情况下,我需要一个不同的类型,我想避免另一个列表列表。 是否有一种简洁的方法为每个变量提供一个类型? 我曾想过将信息放入
变量名
,但这对我来说似乎是错误的

我很乐意接受任何建议。同样对于我已经使用的部分

*编辑@Rory

下面是一个示例输入文本块

6 28 0 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Some comments here
12.527 4.6 0.0365 3.5 0 0 0 0 0 0
0 0  0  0 0 0 0 0 0 0
0  0  0  0 0 0 0 0 0 0
0  0  0  0 0 0 0 0 0 0
输入文件有几个类似这样的块,当然还有一些块采用另一种格式。块的标识在脚本的其他地方完成

正如你所看到的,我并不总是阅读整个街区


好的,不必深入了解嵌套的细节,您可以通过使用元组将变量类型附加到名称

我已经在您的两个变量名上完成了此操作:
('uidx_brg',str),('stn','int')

您不需要使用
zip
,而是需要将其挂接到嵌套元组,并且还需要添加错误处理,以防文件中的字符串值不符合预期的变量类型

import builtins
import pdb

def set_attr(tgt, names, values):

    try:
        for name, value in zip(names, values):
            cls_ = None
            if isinstance(name, str):
                setattr(tgt, name, float(value))
            elif isinstance(name, tuple):
                name, cls_ = name
                if callable(cls_):
                    setattr(tgt, name, cls_(value))
                elif isinstance(cls_, str):
                    cls_ = globals().get(cls_) or getattr(builtins, cls_)
                    setattr(tgt, name, cls_(value))
                else:
                    raise ValueError("variable types have to be a string or callable like `int`,`float`, etc")
    except (ValueError,TypeError,AttributeError) as e: 
        print(f"  somethings wrong:\n{dict(exception=e, name=name, cls_=cls_, value=value)}")
        #raise 

    #pragma: no cover pylint: disable=unused-variable
    except (Exception,) as e: 
        if 1: 
            pdb.set_trace()
        raise

class Foo:
    pass

variable_names = ('_idx_brg', 'stn', 'stn_rel', '_n_lines', '_brg_type')
values = (1.0, 1, 1.2, 1.3, 1.4, 1.5)

foo = Foo()

print("\n\nsetting for foo")
set_attr(foo, variable_names, values) 

print("\n\nfoo:", vars(foo))

variable_names2 = (('_idx_brg',str), ('stn','int'), 'stn_rel', '_n_lines', ('_brg_type','xxx'))

bar = Foo()

print("\n\nsetting for bar:")
set_attr(bar, variable_names2, values) 

print("\n\nbar:", vars(bar))

输出:

foo的设置
foo:{u idx_brg':1.0,'stn':1.0,'stn_rel':1.2,'u n_line':1.3,'u brg_type':1.4}
条形图的设置:
有些事情不对劲:
{'exception':AttributeError(“模块'builtins'没有属性'xxx'”),'name':'\u brg\u type','cls\uu':'xxx','value':1.4}
条:{u idx_brg':'1.0','stn':1','stn_rel':1.2','u n_line':1.3}

从你的最后一段我得到的印象是,你可以控制文件格式。既然如此,我建议你考虑一下YAML。

对于YAML以及数字、字符串、数组和对象,YAML支持自定义类

以下内容表明您希望对象是Meh对象。查看pyyaml文档了解更多详细信息


我还得到这样的印象:您实际上是在为自己的格式编写自己的解析器。一般来说,最好使用经过战斗考验的现成解析器,以及经过战斗考验的成熟格式。这是减少bug的一个途径,您可以站在编写解析器的巨人的肩膀上,修复多年来发现的任何bug。

Python使用动态类型,您不需要提供变量类型。@Barmar是对的,但当您读取纯文本文件时,
values
中的条目将是字符串。当您使用它们时,或者通过调用一些具有实际类型变量列表的“清理”函数,转换它们可能会更容易。也许你可以展示一下你在做什么,然后决定一个好的解决方案。你是否选择了像JSON/FEY这样的更大的自动存储选项呢?“戴维,不幸的是我不太喜欢熊猫、JSON或羽毛。但我会检查一下,我的剧本比较长。我读取的文本文件是模拟软件的输入文件。该脚本是一种包装器,用于为优化软件提供输入。优化软件读取和处理输入文件,并运行仿真软件。输入文件相当大,由几个块组成。对于每个块,我想收集必须作为特定类型读取的每个参数。尤其是整数对于索引非常重要。您是提供了输入文件还是自己创建的?一般来说,我同意您的看法,如果OP可以使用现有的解析器,那就更好了。我在回答时没有注意到这种可能性。然而<代码>东西:!Meh
让我觉得你建议使用
yaml.load
而不是
yaml.safe\u load
,如果你没有完全控制yaml文件,即使这样也是不可靠的(比如说一个坏演员写一个不受保护的,因为非代码,yaml)。不过,总的来说,使用预定义格式是一个很好的建议,只要你不使用不安全的功能。我无法控制文件格式。我不知道如何使用yaml解决我的问题。这似乎使我的问题更复杂了。值得一提的是,
variable\u names
的格式稍后将用于获取变量的特定行和列,以便将其写回完全相同的位置。不,一定要使用safe\u load()。但是,可以设置Meh类,使其能够被safe_load()识别。我相信这是一种通过从某个基类派生并设置某个属性来将其标记为安全的情况。啊,尼斯,他不知道有一个选项可以
safe\u load
自定义数据类型。我以后会记住这一点。我喜欢你的解决方案。我只是不需要将类型作为字符串传递。有没有办法使用yaml(如Rory建议的)解决我的问题?我不知道。否则,我将坚持您的解决方案@JL Peyret


setting for foo


foo: {'_idx_brg': 1.0, 'stn': 1.0, 'stn_rel': 1.2, '_n_lines': 1.3, '_brg_type': 1.4}


setting for bar:
  somethings wrong:
{'exception': AttributeError("module 'builtins' has no attribute 'xxx'"), 'name': '_brg_type', 'cls_': 'xxx', 'value': 1.4}


bar: {'_idx_brg': '1.0', 'stn': 1, 'stn_rel': 1.2, '_n_lines': 1.3}
                   From your last paragraph I get the impression that you can control the file format. That being the case, I'd suggest you consider yaml.

With YAML, as well as numbers, strings, arrays and objects, yaml supports custom classes.

The following would indicate that you want thing to be a Meh object. Check out the pyyaml docs for more detail.

thing: !Meh
    foo: bar
    ping: echo