如何在实例化时有条件地将混合添加到当前 class 中?
How can I conditionally add in a mixin to the current class on instantiation?
我想要一个 class 可以根据传递给构造函数的参数添加混合。这是我试过的:
class MixinOne(object):
def print_name(self):
print("{} is using MixinOne.".format(self.name))
class MixinTwo(object):
def print_name(self):
print("{} is using MixinTwo.".format(self.name))
class Sub(object):
def __new__(cls, *args, **kwargs):
mixin = args[1]
if mixin == 'one':
bases = (MixinOne,) + cls.__bases__
elif mixin == 'two':
bases = (MixinTwo,) + cls.__bases__
return object.__new__(type('Sub', bases, dict(cls.__dict__)))
def __init__(self, name, mixin):
print('In Sub.__init__')
self.name = name
唯一的问题似乎是 __init__
没有被调用,所以 print_name
方法将不起作用。
- 如何让
__init__
在 Sub
上触发?
或
- 有更好的方法吗?
__init__
仅在 __new__
returns class 的实例时调用。您的动态 class 继承自混入和 Sub
的 父级 ,但不是 Sub
本身。如果你设置 bases = (MixinOne, cls)
.
它可能会起作用
写一个工厂函数(或class方法)而不是重载Sub
的构造。更好的是,只需创建一些 subclasses 而不是在运行时创建 classes。 :)
这是使用 meta类 的好地方。您可以将自定义混合包含代码放入元数据中,然后您的 Sub
类 不需要样板:
class AutoMixinMeta(type):
def __call__(cls, *args, **kwargs):
try:
mixin = kwargs.pop('mixin')
name = "{}With{}".format(cls.__name__, mixin.__name__)
cls = type(name, (mixin, cls), dict(cls.__dict__))
except KeyError:
pass
return type.__call__(cls, *args, **kwargs)
class Sub(metaclass = AutoMixinMeta):
def __init__(self, name):
self.name = name
现在您可以创建 Sub
个对象并指定 mixin 如下:
>>> s = Sub('foo', mixin=MixinOne)
>>> s.print_name()
foo is using MixinOne.
它会自动从 kwargs 字典中拉出来,这样 __init__
方法就可以完全不知道它的存在。
注意:Python2中的元类声明语法略有不同:
class Sub(object):
__metaclass__ = AutoMixinMeta
def __init__(self, name):
self.name = name
我想要一个 class 可以根据传递给构造函数的参数添加混合。这是我试过的:
class MixinOne(object):
def print_name(self):
print("{} is using MixinOne.".format(self.name))
class MixinTwo(object):
def print_name(self):
print("{} is using MixinTwo.".format(self.name))
class Sub(object):
def __new__(cls, *args, **kwargs):
mixin = args[1]
if mixin == 'one':
bases = (MixinOne,) + cls.__bases__
elif mixin == 'two':
bases = (MixinTwo,) + cls.__bases__
return object.__new__(type('Sub', bases, dict(cls.__dict__)))
def __init__(self, name, mixin):
print('In Sub.__init__')
self.name = name
唯一的问题似乎是 __init__
没有被调用,所以 print_name
方法将不起作用。
- 如何让
__init__
在Sub
上触发?
或
- 有更好的方法吗?
__init__
仅在__new__
returns class 的实例时调用。您的动态 class 继承自混入和Sub
的 父级 ,但不是Sub
本身。如果你设置bases = (MixinOne, cls)
. 它可能会起作用
写一个工厂函数(或class方法)而不是重载
Sub
的构造。更好的是,只需创建一些 subclasses 而不是在运行时创建 classes。 :)
这是使用 meta类 的好地方。您可以将自定义混合包含代码放入元数据中,然后您的 Sub
类 不需要样板:
class AutoMixinMeta(type):
def __call__(cls, *args, **kwargs):
try:
mixin = kwargs.pop('mixin')
name = "{}With{}".format(cls.__name__, mixin.__name__)
cls = type(name, (mixin, cls), dict(cls.__dict__))
except KeyError:
pass
return type.__call__(cls, *args, **kwargs)
class Sub(metaclass = AutoMixinMeta):
def __init__(self, name):
self.name = name
现在您可以创建 Sub
个对象并指定 mixin 如下:
>>> s = Sub('foo', mixin=MixinOne)
>>> s.print_name()
foo is using MixinOne.
它会自动从 kwargs 字典中拉出来,这样 __init__
方法就可以完全不知道它的存在。
注意:Python2中的元类声明语法略有不同:
class Sub(object):
__metaclass__ = AutoMixinMeta
def __init__(self, name):
self.name = name