我想了解Python类和对象是如何工作的。在Perl中,很简单,在一个sub中定义的每个package都可以称为静态、类或对象方法(CLASS::func、CLASS->func或$obj->func)。乍一看,Python类看起来像一个带有bless-ed散列( Python类中的__dict__属性)的Perl类。但在Python中,我有点困惑。因此,为了更好地理解,我尝试对一个空类进行猴子补丁,添加了3个完全类似静态、类和对象方法的属性,但我无法得到它。
首先,我创建了一个普通类以获得基本结果:
def say(msg, x):
print('*', msg, 'x =', x, 'type(x) =', type(x))
class A():
@staticmethod
def stt_m(x):
say('stt_m', x)
@classmethod
def cls_m(x):
say('cls_m', x)
def obj_m(x):
say('obj_m', x)然后,我创建了一个函数(称为test),它尝试用一个参数调用所有方法,如果失败(因为第一个参数可以是类或对象本身),尝试再次调用,在输出行前面不打印'X‘,然后打印检测到的类型:
def test(obj):
# Detect if obj is a class or an instantiated object
what = 'Class' if type(obj) == type else 'Object'
print()
# Try to call static, class and object method getting attributes
for a in ('stt_m', 'cls_m', 'obj_m'):
meth = getattr(obj, a)
try:
meth(111)
except:
print('X', end='')
meth()
print(' ', what, a, meth)使用默认的test类及其对象调用A:
test(A)
test(A())结果是:
* stt_m x = 111 type(x) = <class 'int'>
Class stt_m <function A.stt_m at 0x7fb37e63c8c8>
X* cls_m x = <class '__main__.A'> type(x) = <class 'type'>
Class cls_m <bound method A.cls_m of <class '__main__.A'>>
* obj_m x = 111 type(x) = <class 'int'>
Class obj_m <function A.obj_m at 0x7fb37e63c9d8>
* stt_m x = 111 type(x) = <class 'int'>
Object stt_m <function A.stt_m at 0x7fb37e63c8c8>
X* cls_m x = <class '__main__.A'> type(x) = <class 'type'>
Object cls_m <bound method A.cls_m of <class '__main__.A'>>
X* obj_m x = <__main__.A object at 0x7fb37e871748> type(x) = <class '__main__.A'>
Object obj_m <bound method A.obj_m of <__main__.A object at 0x7fb37e871748>>因此,调用具有类或对象前缀的staticmethod时,它们的行为为普通(命名空间)函数(接受1个参数)。无论以哪种方式调用classmethod,传递的第一个参数都是类对象。从类调用objectmethod作为正常函数,如果从对象调用,则第一个参数是对象本身。这以后看上去有点奇怪,但我可以接受。
现在,让我们尝试对一个空类进行猴子修补:
class B():
pass
B.stt_m = lambda x: say('stt_m', x)
B.cls_m = types.MethodType(lambda x: say('cls_m', x), B)
B.obj_m = types.MethodType(lambda x: say('obj_m', x), B())
test(B)
test(B())结果是:
* stt_m x = 111 type(x) = <class 'int'>
Class stt_m <function <lambda> at 0x7fbf05ec7840>
X* cls_m x = <class '__main__.B'> type(x) = <class 'type'>
Class cls_m <bound method <lambda> of <class '__main__.B'>>
X* obj_m x = <__main__.B object at 0x7fbf0d7dd978> type(x) = <class '__main__.B'>
Class obj_m <bound method <lambda> of <__main__.B object at 0x7fbf0d7dd978>>
X* stt_m x = <__main__.B object at 0x7fbf06375e80> type(x) = <class '__main__.B'>
Object stt_m <bound method <lambda> of <__main__.B object at 0x7fbf06375e80>>
X* cls_m x = <class '__main__.B'> type(x) = <class 'type'>
Object cls_m <bound method <lambda> of <class '__main__.B'>>
X* obj_m x = <__main__.B object at 0x7fbf0d7dd978> type(x) = <class '__main__.B'>
Object obj_m <bound method <lambda> of <__main__.B object at 0x7fbf0d7dd978>>根据这种模式,stt_m的行为类似于普通类的对象方法,而cls_m和obj_m的行为类似于普通类的类方法。
我能用这种方式给静态方法打个补丁吗?
发布于 2022-02-20 20:33:47
您可以在类上安装猴子补丁方法,但是它是这样完成的:
B.stt_m = staticmethod(lambda x: say('stt_m', x))
B.cls_m = classmethod(lambda x: say('cls_m', x))
B.obj_m = lambda x: say('obj_m', x)您的B.cls_m版本是可以的,但是您的B.stt_m创建了一个正常的方法,您的B.obj_m将一个实例方法附加到一个新创建的B()上,但是这个B()被丢弃了,并且测试了一个没有额外方法的新B()。
在Python中通常不需要使用types.MethodType:
types.MethodType(function, object_)等于
function.__get__(object_)这是比较好一点,虽然也非常罕见。
此外,在Python的新版本中,
print('*', msg, 'x =', x, 'type(x) =', type(x))可以直接写成
print(f"* {msg} {x = } {type(x) = }")https://stackoverflow.com/questions/71197957
复制相似问题