假設我有這個類:
class A。
def __init__(self, a):
self.a = a
@classmethod: self.a = a.
def foo(self)。
return 'hello world!'。
我使用@classmethod,這樣我就可以直接呼叫函式而不用呼叫類:
>>> A.foo()
'hello world!'
>>> A.foo()
但現在我想知道,因為我仍然可以通過呼叫類來訪問它:
A(1).foo()
'hello world!'。
我是否可以讓它在函式foo被呼叫時引發一個錯誤。而只讓它在不呼叫類的情況下被呼叫,如A.foo()。
所以如果我這樣做:
A(1) .foo()
它應該給出一個錯誤。
uj5u.com熱心網友回復:
classmethod, staticmethod以及事實上普通方法的查找/系結的功能是通過descriptors實作。同樣地,我們可以定義一個描述符,禁止對實體進行查找/系結。
這種描述符的天真實作會檢查它是否通過一個實體進行查找,并在這種情況下引發錯誤:
class NoInstanceMethod。
"""Descriptor to forbid that other descriptor can be looked up on an instance"""。
def __init__(self, descr, name=None)。
self.descr = descr
self.name = name
def __set_name__(self, owner, name):
self.name = name
def __get__(self, instance, owner):
# enforce the instance cannot look up the attribute at all[/span]。
if instance is not None。
raise AttributeError(f"{instance}沒有屬性{self.name!r}")
# invoke any descriptor we are wrapping.
return self.descr.__get__(instance, owner)
這可以應用于其他描述符之上,以防止它們在實體上被查找到。特別是,它可以與classmethod或staticmethod相結合,以防止在實體中使用它們:
class A。
def __init__(self, a):
self.a = a
@NoInstanceMethod。
@classmethod[/span]。
def foo(self)。
return 'hello world!'。
A.foo() # Stdout: hello world!
A(1).foo() # AttributeError: <__main__.A object at 0x115469c70> has no attribute 'foo'/span>
上面的NoInstanceMethod是 "天真 "的,因為它沒有照顧到將__get__以外的描述符呼叫傳播到它所包裝的描述符。例如,我們可以通過傳播 __set_name__ 呼叫來讓被包裹的描述符知道它的名字。
由于描述符可以自由地(不)實作任何描述符的方法,因此可以支持這種做法,但需要適當的錯誤處理。擴展NoInstanceMethod以支持實踐中需要的任何描述符方法。
uj5u.com熱心網友回復:
一個變通的方法是在類物件初始化時覆寫其值,以確保它不會從self中被呼叫。
class A:
strictly_class_methods = [
"foo"。
]
def __init__(self, a):
self.a = a
for方法 in self.STRICTLY_CLASS_METHODS。
delattr(self, method)
@classmethod
def foo(cls)。
return 'hello world!'.
try:
print(A.foo())
print(A(1) .foo()
except AttributeError as error:
print(f "Exception occurred: AttributeError {error}")
輸出
hello world!
例外發生了。AttributeError foo
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/326634.html
標籤:
