[英]Make a method that is both a class method and an instance method
Python中有沒有辦法定義既是類方法又是實例方法的方法,使得cls
和self
都是接收者。 特別是,我正在尋找一種方法,該方法(1)知道在類( Foo.method(value)
)上調用時調用了哪個類,以及(2)知道在實例上調用時調用了哪個實例。 ( foo.method()
)。
例如,我可以設想這樣的工作:
class Foo:
def __str__(self): return 'Foo()'
@classinstancemethod
def method(cls, self):
print(cls, self)
class Bar(Foo):
def __str__(self): return 'Bar()'
Foo().method() # <class '__main__.Foo'> Foo()
Bar().method() # <class '__main__.Bar'> Bar()
Foo.method(Foo()) # <class '__main__.Foo'> Foo()
Foo.method(Bar()) # <class '__main__.Foo'> Bar()
Bar.method(Foo()) # <class '__main__.Bar'> Foo()
請注意,我知道可以像Foo.foo(value)
這樣調用未修飾的方法,但這不是我想要的,因為它沒有獲取cls
變量。 而且,如果沒有cls
變量,則該方法不知道它剛剛調用了哪個類。 它可能被稱為Bar.method(value)
,現在將有辦法知道value
是否是Foo
的實例。 未修飾的方法更像靜態方法和實例方法,而不是類方法和實例方法。
您不需要為此的裝飾器。 這就是方法已經起作用的方式。 實例作為第一個參數傳遞-隱式地從實例調用方法,並從類顯式調用-在實例可用的情況下,您可以通過在實例上調用type
來檢索類:
class Foo(object):
def __repr__(self): return 'Foo()'
def method(self):
print((type(self), self))
class Bar(Foo):
def __repr__(self): return 'Bar()'
另外,在__str__
(或__repr__
)特殊方法中,您應該返回一個字符串,而不是print。
我使用__repr__
因為在容器對象(此處為元組)中不調用__str__
來打印實例。
更新 :
考慮到上述方法中類/實例打印的問題,您可以改用描述符來正確管理方法中正確的類和實例選擇:
class classinstancemethod():
def __get__(self, obj, cls):
def method(inst=None):
print(cls, inst if inst else obj)
return method
class Foo(object):
method = classinstancemethod()
def __str__(self): return 'Foo()'
class Bar(Foo):
def __str__(self): return 'Bar()'
這可以通過將classinstancemethod
實現為自定義描述符來解決。
簡而言之,描述符必須定義一個__get__
方法,當它作為屬性訪問時將被調用(例如Foo.method
或Foo().method
)。 該方法將實例和類作為參數傳遞給它,並返回一個綁定方法(即,它返回一個帶有cls
和self
參數的方法)。 調用此綁定方法時,它將已烘焙的cls
和self
參數轉發到實際方法。
class classinstancemethod:
def __init__(self, method, instance=None, owner=None):
self.method = method
self.instance = instance
self.owner = owner
def __get__(self, instance, owner=None):
return type(self)(self.method, instance, owner)
def __call__(self, *args, **kwargs):
instance = self.instance
if instance is None:
if not args:
raise TypeError('missing required parameter "self"')
instance, args = args[0], args[1:]
cls = self.owner
return self.method(cls, instance, *args, **kwargs)
結果:
class Foo:
def __repr__(self): return 'Foo()'
@classinstancemethod
def method(cls, self):
print((cls, self))
class Bar(Foo):
def __repr__(self): return 'Bar()'
Foo().method() # (<class '__main__.Foo'>, 'Foo()')
Bar().method() # (<class '__main__.Bar'>, 'Bar()')
Foo.method(Foo()) # (<class '__main__.Foo'>, 'Foo()')
Foo.method(Bar()) # (<class '__main__.Foo'>, 'Bar()')
Bar.method(Foo()) # (<class '__main__.Bar'>, 'Foo()')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.