2016-07-28 24 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"