知道是否在obj上调用了+或

2024-10-08 19:24:44 发布

您现在位置:Python中文网/ 问答频道 /正文

在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模块的docstring的解决方案,如这里所述:Access operator functions by symbol。有没有一种方法可以找到函数名和符号之间的映射,比解析docstring或手动创建一个列表稍微简单一点?在


Tags: 对象方法add列表定义符号printsoperator
2条回答

是的,但你可能不想这么做,因为这是个坏主意。你必须检查解释器堆栈。由于明显的原因,如果从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)

这是在python3上测试和工作的,只需要对python2稍作修改。在

在cpython中,通过分解referer框架,您有一些自省的能力。例如:

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,您将在反汇编中看到如下内容:

^{pr2}$

使用魔术方法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        

相关问题 更多 >

    热门问题