[英]Know if + or __add__ called on an object
在Python中,我可以重載對象的__add__
方法(或其他雙下划線稱為“dunder”方法)。 這允許我在使用Python運算符時為我的對象定義自定義行為。
是否有可能從dunder方法中知道方法是通過+
還是通過__add__
?
例如,假設我想創建一個打印"+"
或"__add__"
的對象,具體取決於是否使用+
或是否直接調用__add__
。
class MyAdder(object):
def __add__(self, other):
print method_how_created()
return 0
MyAdder() + 7
# prints "+", returns 0
MyAdder().__add__(7)
# prints "__add__", returns 0
除了像method_how_created
這樣的魔法的存在,是否存在符號到dunder方法的規范映射? 我知道有些列表,例如http://www.python-course.eu/python3_magic_methods.php或基於解析operator
模塊的文檔字符串的解決方案,如下所述: 按符號訪問運算符函數 。 有沒有辦法在函數名和符號之間找到一個比解析文檔字符串或手動創建列表更少hacky的映射?
是的,但你可能不想這樣做,因為這是一個壞主意。 您必須檢查解釋器堆棧。 出於顯而易見的原因,如果從C調用代碼,這將無效。以下是代碼:
import inspect
import dis
class A(object):
def __add__(self, other):
fr = inspect.getouterframes(
inspect.currentframe(), 1)[1][0]
opcode = fr.f_code.co_code[fr.f_lasti]
# opcode = ord(opcode) # Uncomment for Python 2
is_op = opcode == dis.opmap['BINARY_ADD']
if is_op:
print('Called with +')
else:
print('Called with __add__')
A() + 1
A().__add__(1)
這是經過測試並適用於Python 3,並且只需對Python 2稍作修改即可。
在cpython中,您可以通過反匯編引用框架來獲得一些內省能力。 例如:
import dis
import inspect
def method_how_created():
return dis.dis(inspect.currentframe().f_back.f_back.f_code)
class MyAdder(object):
def __add__(self, other):
print method_how_created()
x = MyAdder()
檢查案例x + 7
,您將在反匯編中看到類似的內容:
64 LOAD_NAME 5 (x)
67 LOAD_CONST 5 (7)
70 BINARY_ADD
71 POP_TOP
72 LOAD_CONST 1 (None)
75 RETURN_VALUE
使用魔術方法x.__add__(7)
,您將在反匯編中看到類似的內容:
64 LOAD_NAME 5 (x)
67 LOAD_ATTR 6 (__add__)
70 LOAD_CONST 5 (7)
73 CALL_FUNCTION 1
76 POP_TOP
77 LOAD_CONST 1 (None)
80 RETURN_VALUE
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.