在 Python 中即时向 class 添加方法(角色)——有危险吗?
Adding methods (roles) to a class on the fly in Python - dangers?
我正在学习 python,并且与 class 一起玩得很开心。由于我习惯于在其他情况下使用 roles or traits 并发现它们非常有用,因此我正在研究同一类事情 - 将 class 添加到另一个 class' 继承链。像这样:
class A():
def foo(self):
print('foo')
class B():
def bar(self):
print('bar')
a = A()
b = B()
a.foo()
b.bar()
class C(A, B):
pass
class Z():
def baz(self):
print('baz')
C = type("C", (C, Z), {})
c = C()
c.foo()
c.bar()
c.baz()
在现实生活中 C
可能已经在别处定义了,不一定由我定义。
似是而非:有没有我可能没有意识到的隐患?显然:重新定义现有方法 - 但还有别的吗?
这只是正常的继承。您似乎误解了这一点,因为您将 subclass 命名为其基础 class 之一,即 C
.
但是
C = type("C", (C, Z), {})
等同于:
class C(C, Z):
pass
注意,很重要,如果存在原C的实例:
>>> class A():
... def foo(self):
... print('foo')
...
>>>
>>> class B():
... def bar(self):
... print('bar')
...
>>> class C(A, B):
... pass
...
>>> old_c_instance = C()
它不会被认为是新 C:
的一个实例
>>> class Z():
... def baz(self):
... print('baz')
...
>>> C = type("C", (C, Z), {})
>>> isinstance(old_c_instance, C)
False
注意,旧的C是可以恢复的,它将是方法解析顺序中的第二个class(基础的第一个):
>>> OldC = C.mro()[1]
>>> OldC
<class '__main__.C'>
>>> C
<class '__main__.C'>
>>> isinstance(old_c_instance, OldC)
True
所以这只是一个容易混淆的命名子示例class。
注意,这里的模式是“Mixin模式”。如 wiki-link 中所述,特征基本上类似于混合,但它们通常不携带实例状态。好吧,你可以 从你的 mixin 中省略 ,现在你基本上有一个特征......使用继承。
请注意,您 可以 实际上在 Python 中动态添加方法:
class A():
def foo(self):
print('foo')
class B():
def bar(self):
print('bar')
class C(A, B):
pass
然后,像这样:
def baz(self):
print('baz')
def qux(self):
print('qux')
for func in [baz, qux]:
setattr(C, func.__name__, func)
C().baz()
C().qux()
这避免了继承和创建新的 class。 Python.
中的许多元编程都非常普通
我正在学习 python,并且与 class 一起玩得很开心。由于我习惯于在其他情况下使用 roles or traits 并发现它们非常有用,因此我正在研究同一类事情 - 将 class 添加到另一个 class' 继承链。像这样:
class A():
def foo(self):
print('foo')
class B():
def bar(self):
print('bar')
a = A()
b = B()
a.foo()
b.bar()
class C(A, B):
pass
class Z():
def baz(self):
print('baz')
C = type("C", (C, Z), {})
c = C()
c.foo()
c.bar()
c.baz()
在现实生活中 C
可能已经在别处定义了,不一定由我定义。
似是而非:有没有我可能没有意识到的隐患?显然:重新定义现有方法 - 但还有别的吗?
这只是正常的继承。您似乎误解了这一点,因为您将 subclass 命名为其基础 class 之一,即 C
.
但是
C = type("C", (C, Z), {})
等同于:
class C(C, Z):
pass
注意,很重要,如果存在原C的实例:
>>> class A():
... def foo(self):
... print('foo')
...
>>>
>>> class B():
... def bar(self):
... print('bar')
...
>>> class C(A, B):
... pass
...
>>> old_c_instance = C()
它不会被认为是新 C:
的一个实例>>> class Z():
... def baz(self):
... print('baz')
...
>>> C = type("C", (C, Z), {})
>>> isinstance(old_c_instance, C)
False
注意,旧的C是可以恢复的,它将是方法解析顺序中的第二个class(基础的第一个):
>>> OldC = C.mro()[1]
>>> OldC
<class '__main__.C'>
>>> C
<class '__main__.C'>
>>> isinstance(old_c_instance, OldC)
True
所以这只是一个容易混淆的命名子示例class。
注意,这里的模式是“Mixin模式”。如 wiki-link 中所述,特征基本上类似于混合,但它们通常不携带实例状态。好吧,你可以 从你的 mixin 中省略 ,现在你基本上有一个特征......使用继承。
请注意,您 可以 实际上在 Python 中动态添加方法:
class A():
def foo(self):
print('foo')
class B():
def bar(self):
print('bar')
class C(A, B):
pass
然后,像这样:
def baz(self):
print('baz')
def qux(self):
print('qux')
for func in [baz, qux]:
setattr(C, func.__name__, func)
C().baz()
C().qux()
这避免了继承和创建新的 class。 Python.
中的许多元编程都非常普通