如何在Python中动态创建类变量

38

我需要创建一堆类变量,我希望通过遍历列表来实现:

vars=('tx','ty','tz') #plus plenty more

class Foo():
    for v in vars:
        setattr(no_idea_what_should_go_here,v,0)

这可行吗?我不想在实例中创建它们(使用__init__函数中的self),而是想将它们作为类变量。


2
为什么不把它们保存在字典中? - DrTyrsa
你想在不同的实例之间共享这些变量吗? - luc
不确定。很可能是这样的。需求来自一个API,我不知道它们在那里如何使用。 - pawel
这个能在__new__中被调用吗? - 9 Guy
7个回答

61

您可以在创建类后立即运行插入代码:

class Foo():
     ...

vars=('tx', 'ty', 'tz')  # plus plenty more
for v in vars:
    setattr(Foo, v, 0)

此外,在创建类时,您可以动态存储变量:

class Bar:
    locals()['tx'] = 'texas'

啊,太酷了。我会试一下看看我使用的API是否能够处理它。谢谢伙计! - pawel
如果您已覆盖__setattr__(),会发生什么? - JasonGabler
更新...我想通了。在__setattr__()内,您可以调用 super(ThisClass, self).__setattr__(varname, varvalue) - JasonGabler
1
关于答案的最后一部分,locals()['tx'] = 'texas'。应该说,Python文档明确警告不要这样做:注意:不应修改此字典的内容;更改可能不会影响解释器使用的局部和自由变量的值。 链接:https://docs.python.org/3/library/functions.html#locals - Håkon T.
类字典的本地变量是可修改的。函数的本地变量将被忽略。 - Raymond Hettinger

10

虽然有些晚了,但是使用 type 类构造函数

Foo = type("Foo", (), {k: 0 for k in ("tx", "ty", "tz")})

9

如果由于任何原因您不能使用Raymond的答案在类创建后进行设置,那么您可以使用元类:

class MetaFoo(type):
    def __new__(mcs, classname, bases, dictionary):
        for name in dictionary.get('_extra_vars', ()):
            dictionary[name] = 0
        return type.__new__(mcs, classname, bases, dictionary)

class Foo(): # For python 3.x use 'class Foo(metaclass=MetaFoo):'
    __metaclass__=MetaFoo # For Python 2.x only
    _extra_vars = 'tx ty tz'.split()

你的解决方案中硬编码了“_extra_vars”的值,因此这不起作用。 - MSS
@MSS,您不必使用'tx ty tz'.split(),您可以替换为自己的表达式,该表达式可以引用变量。 - Duncan

1

setattr(object, name, value) 这是getattr()的对应函数。它需要一个对象,一个字符串和一个任意值作为参数。该字符串可以是现有属性或新属性的名称。如果对象允许,函数会将值赋给该属性。 例如,setattr(x, 'name', value)等同于x.name = value


1
locals()版本在类中对我不起作用。 以下内容可用于动态创建类的属性:
class namePerson:
    def __init__(self, value):
        exec("self.{} = '{}'".format("name", value)

me = namePerson(value='my name')
me.name # returns 'my name'

这是一个非常错误的方法。你正在设置一个实例变量,而不是一个类变量。另外,为什么不直接使用 setattr - user5538922

0
你需要的函数是:
setattr(obj, name, value)
这允许你为给定的类(可以是self)设置命名属性。
这个函数的内置文档非常自我解释:
Signature: setattr(obj, name, value, /)
Docstring:
Sets the named attribute on the given object to the specified value.

setattr(x, 'y', v) is equivalent to ``x.y = v''
Type:      builtin_function_or_method

示例用法

其中一个用途是使用字典来设置多个类属性,我的情况是从 xpath 定义中。我认为这样做可以通过将可能更脆弱的 xpath 定义集中在一起来提高可维护性:

class Person:
    def _extract_fields(self):
        ''' Process the page using XPath definitions '''
        logging.debug("_extract_fields(): {}".format(repr(self)))
        # describe how to extract data from the publicly available site
        # (kept together for maintainability)
        fields = {
            'staff_name':
            '//div[@id="staff_name"]//text()',
            'staff_dob':
            '(//div[@id="staff_dob"]//text())[1]'
        }
        # populate named class attributes from the dict
        for key in fields:
            setattr(self, key, self._parsed_content.xpath(fields[key]))

    def __init__(self):
        self._extract_fields()

0

您可以在变量名前加上“foo.”(或者您的类名)来创建全局变量:

vars=('tx','ty','tz') #plus plenty more

class Foo():
    pass

foo = Foo() # Instance the class

for i in vars:
    globals () ["foo." + i] = value

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接