在Python3中,可以通过两种方式调用实例方法:obj.ix()
或Foo.ix(obj)
。撇开这是否是一个好主意:当使用后者时,有没有办法获得实例方法被访问的类?
class Foo(object):
@classmethod
def cx(cls, obj):
print(cls.X)
def ix(self):
# Any way to get the class that ix was accessed through?
print(self.X)
class AFoo(Foo):
X = "A"
class BFoo(Foo):
X = "B"
a = AFoo()
AFoo.cx(a) # Prints "A"
AFoo.ix(a) # Prints "A"
b = BFoo()
BFoo.cx(b) # Prints "B"
BFoo.ix(b) # Prints "B"
AFoo.cx(b) # Prints "A"
AFoo.ix(b) # Prints "B" -> I would like "A", like classmethod.
BFoo.cx(a) # Prints "B"
BFoo.ix(a) # Prints "A" -> I would like "B", like classmethod.
正如您所看到的,使用类方法实现所需的行为是微不足道的,但似乎没有办法对实例方法执行相同的操作。
答案 0 :(得分:2)
不。此信息不会保留。如果您需要该信息,则必须编写自定义描述符以实现新的方法类型。例如:
import functools
class CrazyMethod:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
if instance is None:
return functools.partial(self.func, owner)
return functools.partial(self.func, instance, instance)
class Foo:
@CrazyMethod
def foo(accessed_through, self):
print(accessed_through)
class Bar(Foo): pass
obj = Bar()
obj.foo() # <__main__.Bar object at 0xb727dd4c>
Bar.foo(obj) # <class '__main__.Bar'>
Foo.foo(obj) # <class '__main__.Foo'>
答案 1 :(得分:1)
我已经接受了user2357112的回答,但万一有人感兴趣我找到了另一种方法(基于A class method which behaves differently when called as an instance method?):
import types
class Foo(object):
@classmethod
def x(cls, obj):
print(cls.X)
def __init__(self):
self.x = types.MethodType(type(self).x, self)
class AFoo(Foo):
X = "A"
class BFoo(Foo):
X = "B"
a = AFoo()
b = BFoo()
a.x() # Prints "A"
AFoo.x(a) # Prints "A"
AFoo.x(b) # Prints "A"
b.x() # Prints "B"
BFoo.x(b) # Prints "B"
BFoo.x(a) # Prints "B"