我试图动态添加类属性,但不是在实例级别。例如。我可以手动做什么:
class Foo(object):
a = 1
b = 2
c = 3
我希望能够做到:
class Foo(object):
dct = {'a' : 1, 'b' : 2, 'c' : 3}
for key, val in dct.items():
<update the Foo namespace here>
我希望能够在没有从类外部调用类(因此它是可移植的)或没有其他类/装饰器的情况下执行此操作。这可能吗?
答案 0 :(得分:4)
从您的示例代码判断,您希望在创建类的同时执行此操作。在这种情况下,假设您正在使用CPython,则可以使用locals()
。
class Foo(object):
locals().update(a=1, b=2, c=3)
这是有效的,因为在定义类时,locals()
引用类名称空间。它是特定于实现的行为,可能无法在更高版本的Python或替代实现中使用。
使用类工厂的不太脏的hacky版本如下所示。基本思想是通过type()
构造函数将字典转换为类,然后将其用作新类的基类。为了方便用最少的语法定义属性,我使用**
约定来接受属性。
def dicty(*bases, **attrs):
if not bases:
bases = (object,)
return type("<from dict>", bases, attrs)
class Foo(dicty(a=1, b=2, c=3)):
pass
# if you already have the dict, use unpacking
dct = dict(a=1, b=2, c=3)
class Foo(dicty(**dct)):
pass
这实际上只是自己调用type()
的语法糖。这很好,例如:
class Foo(type("<none>", (object,), dict(a=1, b=2, c=3))):
pass
答案 1 :(得分:2)
你的意思是这样的:
def update(obj, dct):
for key, val in dct.items():
obj.setattr(key, val)
然后去吧
update(Foo, {'a': 1, 'b': 2, 'c': 3})
这很有效,因为类也只是一个对象;)
如果你想将所有内容都移到课堂上,那么试试这个:
class Foo(object):
__metaclass__ = lambda t, p, a: return type(t, p, a['dct'])
dct = {'a': 1, 'b': 2, 'c': 3}
这将创建一个新类,成员位于dct
,但所有其他属性都不会出现 - so ,您想要将最后一个参数更改为{{1}包括你想要的东西。我在这里找到了如何做到这一点:What is a metaclass in Python?
答案 2 :(得分:1)
接受的答案是一个很好的方法。但是,一个缺点是你最终在MRO继承链中有一个额外的父对象,这个对象实际上并不是必需的,甚至可能会让人感到困惑:
>>> Foo.__mro__
(<class '__main__.Foo'>, <class '__main__.<from dict>'>, <class 'object'>)
另一种方法是使用装饰器。像这样:
def dicty(**attrs):
def decorator(cls):
vars(cls).update(**attrs)
return cls
return decorator
@dicty(**some_class_attr_namespace)
class Foo():
pass
通过这种方式,您可以避免继承链中的其他对象。 @decorator
语法只是一种很好的说法:
Foo = dicty(a=1, b=2, c=3)(Foo)