具有类型和超级的动态继承
dynamic inheritance with type and super
我正在寻找一种动态继承父 class 及其属性和方法的方法,方法是使用 type
创建 class 并使用 super
继承,像这样:
class A:
def __init__(self,a,b):
self.a = a
self.b = b
def some_method(self,q):
return (self.a + self.b)**q
def B_init(self,**kwargs):
super().__init__(**kwargs)
def another_method(self,):
return 1
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'__init__':B_init,
'another_method':another_method
}
)
然后可以调用...
model = class_B_factory(A)(a = 1, b = 5)
print(model.some_method(2)) # outputs to (1 + 5)**2 = 36
我不确定如何进行。我认为我不需要自定义 metaclass 因为我很确定你不能在创建 self
的同时调用父 class' __init__
方法进行中。我还尝试覆盖 class_B_factory
范围之外的默认 __init__
方法,如下所示:
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'another_method':another_method
}
)
B = class_B_factory(A)
def B_init(self,**kwargs):
super(B,self).__init__(**kwargs)
B.__init__ = B_init
model = B(a = 1, b = 5)
因为我认为 type
不需要 __init__
马上,因为它只在实例化期间需要。但是后来我得到 TypeError: __init__() got an unexpected keyword argument
错误,这似乎没有用,而且它也不干净。
编辑:我尝试通过以下方法在工厂外部定义方法,但仍然没有成功。不知道如何解决它。 Python 实例化可能有问题?
class A:
...
def B_init(self, produced_class = None, **kwargs):
super(produced_class,self).__init__(**kwargs)
def another_method(self, q, parent_class = None):
if parent_class is not None:
return 3 * parent_class.some_method(self,q) # I expect any parent_class passed to have a method called some_method
return 1
def class_B_factory(parent_class, additional_methods):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class = parent_class) # freeze the parent_class argument, which is a cool feature
methods[name] = method
newcls = type(
'B',
(parent_class,),
methods # would not contain B_init
)
newcls.__init__ = partial(B_init, produced_class = newcls) # freeze the produced class that I am trying to fabricate into B_init here
return newcls
model = class_B_factory(parent_class = A, additional_methods = {"another_method": another_method})
print(signature(model.__init__).parameters) # displays OrderedDict([('self', <Parameter "self">),...]) so it contains self!
some_instance_of_model = model(a = 1, b = 5) # throws TypeError: B_init() missing 1 required positional argument: 'self'
super()
的无参数形式依赖于将其物理放置在 class 主体内 - Python 机器将在引擎盖下创建一个 __class__
引用“物理”class(大致相当于非局部变量)的单元格变量,并将其作为 super()
调用中的第一个参数。
对于未在 class
语句中编写的方法,必须求助于显式将参数放置到 super
,这些是子 class 和实例 (self) .
在代码中更简单的方法是在工厂函数中定义方法,这样它们就可以共享一个非局部变量,其中包含在超级调用中新创建的 class:
def class_B_factory(parent_class):
def B_init(self,**kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
super(newcls, self).__init__(**kwargs)
def another_method(self,):
return 1
newcls = type(
'B',
(parent_class, some_other_parent_class),
{'__init__':B_init,
'another_method':another_method
}
return newcls
如果您必须在工厂函数之外定义方法(这很可能),您必须以某种形式将父 class 传递给它们。最直接的方法是添加命名参数(例如 __class__
或“parent_class”),并在工厂内部使用 functools.partial
将 parent_class 传递给所有方法懒惰的方式:
from functools import partial
from inspect import signature
class A:
...
# the "parent_class" argument name is given a special treatement in the factory function:
def B_init(self, *, parent_class=None, **kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
super([parent_class, self).__init__(**kwargs)
def another_method(self,):
return 1
def class_B_factory(parent_class, additional_methods, ...):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class=parent_class)
# we populate another dict instead of replacing methods
# so that we create a copy and don't modify the dict at the calling place.
methods[name] = method
newcls = type(
'B',
(parent_class, some_other_parent_class),
methods
)
return newcls
new_cls = class_B_factory(B, {"__init__": B_init, "another_method": another_method})
我正在寻找一种动态继承父 class 及其属性和方法的方法,方法是使用 type
创建 class 并使用 super
继承,像这样:
class A:
def __init__(self,a,b):
self.a = a
self.b = b
def some_method(self,q):
return (self.a + self.b)**q
def B_init(self,**kwargs):
super().__init__(**kwargs)
def another_method(self,):
return 1
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'__init__':B_init,
'another_method':another_method
}
)
然后可以调用...
model = class_B_factory(A)(a = 1, b = 5)
print(model.some_method(2)) # outputs to (1 + 5)**2 = 36
我不确定如何进行。我认为我不需要自定义 metaclass 因为我很确定你不能在创建 self
的同时调用父 class' __init__
方法进行中。我还尝试覆盖 class_B_factory
范围之外的默认 __init__
方法,如下所示:
def class_B_factory(parent_class):
return type(
'B',
(parent_class, some_other_parent_class),
{'another_method':another_method
}
)
B = class_B_factory(A)
def B_init(self,**kwargs):
super(B,self).__init__(**kwargs)
B.__init__ = B_init
model = B(a = 1, b = 5)
因为我认为 type
不需要 __init__
马上,因为它只在实例化期间需要。但是后来我得到 TypeError: __init__() got an unexpected keyword argument
错误,这似乎没有用,而且它也不干净。
编辑:我尝试通过以下方法在工厂外部定义方法,但仍然没有成功。不知道如何解决它。 Python 实例化可能有问题?
class A:
...
def B_init(self, produced_class = None, **kwargs):
super(produced_class,self).__init__(**kwargs)
def another_method(self, q, parent_class = None):
if parent_class is not None:
return 3 * parent_class.some_method(self,q) # I expect any parent_class passed to have a method called some_method
return 1
def class_B_factory(parent_class, additional_methods):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class = parent_class) # freeze the parent_class argument, which is a cool feature
methods[name] = method
newcls = type(
'B',
(parent_class,),
methods # would not contain B_init
)
newcls.__init__ = partial(B_init, produced_class = newcls) # freeze the produced class that I am trying to fabricate into B_init here
return newcls
model = class_B_factory(parent_class = A, additional_methods = {"another_method": another_method})
print(signature(model.__init__).parameters) # displays OrderedDict([('self', <Parameter "self">),...]) so it contains self!
some_instance_of_model = model(a = 1, b = 5) # throws TypeError: B_init() missing 1 required positional argument: 'self'
super()
的无参数形式依赖于将其物理放置在 class 主体内 - Python 机器将在引擎盖下创建一个 __class__
引用“物理”class(大致相当于非局部变量)的单元格变量,并将其作为 super()
调用中的第一个参数。
对于未在 class
语句中编写的方法,必须求助于显式将参数放置到 super
,这些是子 class 和实例 (self) .
在代码中更简单的方法是在工厂函数中定义方法,这样它们就可以共享一个非局部变量,其中包含在超级调用中新创建的 class:
def class_B_factory(parent_class):
def B_init(self,**kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
super(newcls, self).__init__(**kwargs)
def another_method(self,):
return 1
newcls = type(
'B',
(parent_class, some_other_parent_class),
{'__init__':B_init,
'another_method':another_method
}
return newcls
如果您必须在工厂函数之外定义方法(这很可能),您必须以某种形式将父 class 传递给它们。最直接的方法是添加命名参数(例如 __class__
或“parent_class”),并在工厂内部使用 functools.partial
将 parent_class 传递给所有方法懒惰的方式:
from functools import partial
from inspect import signature
class A:
...
# the "parent_class" argument name is given a special treatement in the factory function:
def B_init(self, *, parent_class=None, **kwargs):
nonlocal newcls # <- a bit redundant, but shows how it is used here
super([parent_class, self).__init__(**kwargs)
def another_method(self,):
return 1
def class_B_factory(parent_class, additional_methods, ...):
methods = {}
for name, method in additional_methods.items():
if "parent_class" in signature(method).parameters:
method = partial(method, parent_class=parent_class)
# we populate another dict instead of replacing methods
# so that we create a copy and don't modify the dict at the calling place.
methods[name] = method
newcls = type(
'B',
(parent_class, some_other_parent_class),
methods
)
return newcls
new_cls = class_B_factory(B, {"__init__": B_init, "another_method": another_method})