是否真的“然而,当首次定义类时,这组方法是固定的”?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否真的“然而,当首次定义类时,这组方法是固定的”?相关的知识,希望对你有一定的参考价值。

来自Programming Language Pragmatics, by Scott

对于类的内容(成员),Python和Ruby都比php或更传统的面向对象语言更灵活。只需分配给Python对象,就可以将新字段添加到Python对象中:my_object.new_field = value。但是,在首次定义类时,这组方法是固定的。在Ruby中,只有方法在类外可见(“put”和“get”方法必须用于访问字段),并且必须显式声明所有方法。但是,可以修改现有的类声明,添加或覆盖方法。甚至可以在逐个对象的基础上执行此操作。因此,同一类的两个对象可能不会显示相同的行为。

然而,“当首次定义类时,这组方法是否已修复”是什么意思?

我似乎找到了一个反例:

>>> class E:
...     pass
... 
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>})
>>> def myfun():
...     pass
... 
>>> E.mf=myfun
>>> E.__dict__
mappingproxy({'__module__': '__main__', '__dict__': <attribute '__dict__' of 'E' objects>, '__doc__': None, '__weakref__': <attribute '__weakref__' of 'E' objects>, 'mf': <function myfun at 0x7f6561daba60>})
答案

就像问题中所示:向类对象添加一个函数是很简单的,它的行为就像任何方法一样:

def fake_method(self,idx):
    print(self, idx)

class MyClass(object):
    pass

MyClass.new_method = fake_method

n = MyClass()
n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E90860> 10

您还可以向实例添加“类似方法”的“可调用属性”:

import types

def fake_method(self,idx):
    print(self, idx)

class MyClass(object):
    pass

n = MyClass()
n.new_method = types.MethodType(fake_method, n)

n.new_method(10)
# <__main__.MyClass object at 0x000001BBA6E9C2E8> 10

这里需要types.MethodType,因为否则它会表现得像staticmethod

我的总结:要么我错过了引用的一些关键点,要么是错的。

另一答案

在实例级别,可以直接修改字段,如上所述。

在类/模块级别,有一个名为monkey patching的非官方机制。基本上,您将获得类/模块的引用(?),并覆盖该函数。

但是,我不清楚是否可以覆盖静态方法。并且修改仅在完成猴子补丁的本地范围内有效,我相信。因此,您不应期望导入相同类/模块的其他脚本共享Monkey补丁,除非它们也明确应用补丁。当然,您也可以创建一个包装器模块。

我不认为这是Python社区提倡的。很长一段时间内很难将补丁保持在轨道上。

更多信息:What is a monkey patch?

以上是关于是否真的“然而,当首次定义类时,这组方法是固定的”?的主要内容,如果未能解决你的问题,请参考以下文章

是否真的需要缓存?

安全设置是否真的有效?

是否真的所有 ExtJS 组件都没有点击事件

“秀恩爱”是否真的会“分得快”?

python应用情况怎么样?是否真的值得学习?

你是否真的适合搞NDK开发?