【问题标题】:Adding methods (roles) to a class on the fly in Python - dangers?在 Python 中动态地向类中添加方法(角色)——危险吗?
【发布时间】:2021-11-16 13:49:15
【问题描述】:

我正在学习 python,并在课堂上玩得很开心。因为我习惯了roles 或traits 在其他上下文中并发现它们非常有用,所以我正在研究同样的事情——将一个类添加到另一个类的继承链中。像这样:

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 可能已经在其他地方定义过,不一定是我自己定义的。

似乎太顺利以至于难以置信:任何我可能没有意识到的隐患?显然:重新定​​义现有方法 - 但还有什么?

【问题讨论】:

  • 我没有投反对票,但我不明白你在问什么。这是 jsut 继承 AFAIKT。你在这里创建了 两个 不同的名为“C”的类......不知道你为什么不只是做class C(C, Z): pass。或者更合理的是,class D(C, Z): pass
  • 您正在重新定义C,而不是动态添加方法。检查更改前后的id(C) 以进行比较。添加新方法将是猴子补丁,即C.baz = lambda self: print('baz')。
  • @juanpa.arrivillaga - 为什么有两个不同的类? “旧”C 类还存在吗?至于为什么 - 正如我在问题中所说:我不“拥有”原始 C 类,我保留 100% 的行为,我只想添加一些特征(见链接)。
  • @Selcuk - 重新定义为“做 C 曾经做过的所有事情,并将这些事情放在首位” - 对吧?并感谢 ``ìd(C)``` 提示 - 这是你无法通过谷歌搜索找到的类型
  • “旧”C 仍然存在但无法访问。你可以在type 技巧之前做类似OldC = C 的事情,它可以作为OldC 访问。是的,你在扩展C,同时仍然混淆命名子类C,所以它与@juanpa.arrivillaga 提到的没有什么不同(即class C(C, Z): pass)。

标签: python traits roles


【解决方案1】:

这只是正常的继承。您似乎误解了这一点,因为您将子类命名为与其基类之一相同,即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可以恢复,它将是方法解析顺序中的第二个类(base的第一个):

>>> OldC = C.mro()[1]
>>> OldC
<class '__main__.C'>
>>> C
<class '__main__.C'>
>>> isinstance(old_c_instance, OldC)
True

所以这只是一个容易混淆的子类的例子。

注意,这里的模式是“混合模式”。如 wiki-link 中所述,traits 基本上类似于 mixin,但它们通常不携带实例状态。好吧,你可以从你的 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()

这避免了继承和创建新类。很多元编程在 Python 中是非常普通的。

【讨论】:

    猜你喜欢
    • 2011-04-19
    • 2015-04-10
    • 1970-01-01
    • 2013-12-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-01
    • 1970-01-01
    • 2011-12-31
    相关资源
    最近更新 更多