python - 新类方法的 __self__ 仍然引用以前的类吗?

标签 python class inheritance types

我想做的事情似乎很奇怪,简而言之,我试图构建一个新类并从另一个类复制实例/静态/类方法而不进行继承(即,我只想要一个只有几个方法的类) 。当我在网上查找时,似乎人们在建议我在插图(新类)中所做的事情,但是当我尝试测试它时,新类中声明的类方法似乎仍然指向以前的类(旧类)类)。

这就是我所做的:


class OldClass(object):
    current_count = 1

    def __init__(self):
        pass

    @classmethod
    def method_class(cls):
        cls.current_count += 1

    def method_normal(self):
        return 2


# new class
class NewClass(object):
    method_class_copy = OldClass.method_class
    method_normal_copy = OldClass.method_normal

检查 __self__ 给出以下结果:

class_self = getattr(NewClass.method_class_copy, '__self__', None)
print(class_self)

它返回:

<class '__main__.OldClass'>

但在实例化后检查实例方法:

instance_self = getattr(NewClass().method_normal_copy, '__self__', None)
print(instance_self)

如您所见,它仍然引用 OldClass,如果我运行类方法 NewClass.method_class_copy()OldClass.current_count 将增加其值我定义的方式。

它返回:

<__main__.NewClass object at 0x000001D8CC1AEA88>
  • 如何构造一个(新)类,其中类方法的 __self__ 实际上引用 NewClass 而不是 OldClass?
  • 为什么实例方法会“自动调整”?

谢谢

最佳答案

这是 descriptor protocol 的效果以及如何classmethod使用它:classmethod 通过查找它来绑定(bind)到它的类。宽松地说,查找 some_cls.some_classmethod 返回方法,其中 cls 参数预先填充到 some_class

由于“普通”方法是通过在实例上查找来绑定(bind)到其实例的,因此在类上查找它们并不会绑定(bind)它们。

>>> class Foo:
...    def some_normalmethod(self): ...
...    @classmethod
...    def some_classmethod(cls): ...
...
>>> Foo.some_classmethod
<bound method Foo.some_classmethod of <class '__main__.Foo'>>
>>> Foo.some_normalmethod
<function __main__.Foo.some_normalmethod(self)>

因此,通过从类中获取classmethod来“复制”它并不能按预期工作(它已经绑定(bind)到该类),而“复制”普通方法却可以工作(它是不绑定(bind)到实例)。


为了“复制”classmethod,提取其底层函数并从中创建一个新的classmethod:

>>> bound_cm = Foo.some_classmethod  # bound classmethod
>>> base_cm = bound_cm.__func__      # function underlying classmethod
>>> class Bar:
...     some_classmethod = classmethod(base_cm)  # new classmethod of same function
...
>>> Bar.some_classmethod
<bound method Foo.some_classmethod of <class '__main__.Bar'>>

请注意,这会创建类方法的“副本”,而不是底层函数。某些元数据,例如名称 Foo.some_classmethod 仍然指向其起源。

如果需要原始classmethod对象,则绕过描述符协议(protocol)可以直接访问而无需绑定(bind)方法。

>>> Foo.__dict__['some_classmethod']
<classmethod at 0x10b6d9d00>
>>> class Qux:
...     some_classmethod = Foo.__dict__['some_classmethod']
...
>>> Qux.some_classmethod
<bound method Foo.some_classmethod of <class '__main__.Qux'>>

关于python - 新类方法的 __self__ 仍然引用以前的类吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64666894/

相关文章:

java - 当只有子类实现可序列化时,序列化如何工作

python - 如何获取PyQt5中QlistWidget中存在的所有项目

python - 树莓派开机时运行Python SimpleHTTPServer

java - 创建类的实例并导出到文件

c++ - C++ 中是否有类似于 Java 的 CompareTo 方法,您可以在其中对数据类型使用 > < = 操作

java - 为什么具体类的一个子类可以声明为抽象的,而父类的一些方法可以被重写并声明为抽象的?

python - 为什么 numpy.sum 没有给我正确的结果?

python - 将类变量重定向到类函数

C++ 多个具有相同名称的类

c# - 构造函数重载异常