2016-07-28 28 views
1

在Python3中,可以通过两种方式调用实例方法,即obj.ix()Foo.ix(obj)。撇开它是否是个好主意:当使用后者时,是否有办法让实例方法被访问的类通过?调用unbound方法,获取它通过访问的类?

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. 

正如你所看到的,所期望的行为是微不足道的实现与一个类的方法,但似乎没有成为一个方式做同样的一个实例方法。

回答

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'> 
+0

很有意思,谢谢!似乎有不止一种方式去做,但这绝对是一个有效的答案,所以我接受了它。 – kloffy

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" 
相关问题