这是一个不寻常的问题,但我想__slots__
根据我碰巧添加到类中的任何属性动态生成类的属性。
例如,如果我有一堂课:
class A(object):
one = 1
two = 2
__slots__ = ['one', 'two']
我想动态地执行此操作,而不是手动指定参数,我该怎么做?
这是一个不寻常的问题,但我想__slots__
根据我碰巧添加到类中的任何属性动态生成类的属性。
例如,如果我有一堂课:
class A(object):
one = 1
two = 2
__slots__ = ['one', 'two']
我想动态地执行此操作,而不是手动指定参数,我该怎么做?
在您尝试定义slot时,该类尚未构建,因此您无法从 A 类中动态定义它。
要获得您想要的行为,请使用元类来内省 A 的定义并添加插槽属性。
class MakeSlots(type):
def __new__(cls, name, bases, attrs):
attrs['__slots__'] = attrs.keys()
return super(MakeSlots, cls).__new__(cls, name, bases, attrs)
class A(object):
one = 1
two = 2
__metaclass__ = MakeSlots
需要注意的一件非常重要的事情——如果这些属性保留在类中,那么__slots__
生成将是无用的……好吧,也许不是无用的——它将使类属性只读;可能不是你想要的。
简单的方法是说,“好的,我将它们初始化为 None,然后让它们消失。” 优秀的!这是一种方法:
class B(object):
three = None
four = None
temp = vars() # get the local namespace as a dict()
__slots__ = temp.keys() # put their names into __slots__
__slots__.remove('temp') # remove non-__slots__ names
__slots__.remove('__module__') # now remove the names from the local
for name in __slots__: # namespace so we don't get read-only
del temp[name] # class attributes
del temp # and get rid of temp
如果您想保留这些初始值,则需要做更多的工作......这是一种可能的解决方案:
class B(object):
three = 3
four = 4
def __init__(self):
for key, value in self.__init__.defaults.items():
setattr(self, key, value)
temp = vars()
__slots__ = temp.keys()
__slots__.remove('temp')
__slots__.remove('__module__')
__slots__.remove('__init__')
__init__.defaults = dict()
for name in __slots__:
__init__.defaults[name] = temp[name]
del temp[name]
del temp
如您所见,没有元类也可以做到这一点——但谁想要所有的样板文件?元类绝对可以帮助我们清理它:
class MakeSlots(type):
def __new__(cls, name, bases, attrs):
new_attrs = {}
new_attrs['__slots__'] = slots = attrs.keys()
slots.remove('__module__')
slots.remove('__metaclass__')
new_attrs['__weakref__'] = None
new_attrs['__init__'] = init = new_init
init.defaults = dict()
for name in slots:
init.defaults[name] = attrs[name]
return super(MakeSlots, cls).__new__(cls, name, bases, new_attrs)
def new_init(self):
for key, value in self.__init__.defaults.items():
setattr(self, key, value)
class A(object):
__metaclass__ = MakeSlots
one = 1
two = 2
class B(object):
__metaclass__ = MakeSlots
three = 3
four = 4
现在所有的乏味都保留在元类中,并且实际的类很容易阅读和(希望!)理解。
如果您需要在这些类中添加除属性之外的任何其他内容,我强烈建议您将任何内容放在 mixin 类中——将它们直接放在最终类中会使元类更加复杂。