0

我一直在研究 Python 中的魔术方法,并且一直想知道是否有办法概述以下具体操作:

a = MyClass(*params).method()

相对:

MyClass(*params).method()

从某种意义上说,也许,我可能想要返回一个已在'\n'字符上拆分的列表,而不是将原始列表转储到a保持'\n'不变的变量中。

有没有办法询问 Python 的下一个动作是否即将向变量返回一个值,并改变动作,如果是这样的话?我刚在想:

class MyClass(object):
    def __init__(params):
        self.end = self.method(*params)

    def __asgn__(self):
        return self.method(*params).split('\n')

    def __str__(self):
        """this is the fallback if __asgn__ is not called"""
        return self.method(*params)
4

3 回答 3

4

不可以。您无法更改分配给裸名时发生的情况。

如果左侧的分配目标是对象的属性或项,您可以更改发生的情况。您可以覆盖a[blah] = ...with__setitem__a.blah = ...with __setattr__(尽管您只能连接到这些 on a,而不是正在分配的对象上)。但是您不能覆盖或以任何方式影响a = ...

请注意,根据“将要发生”的情况进行右侧更改会更奇怪,而且非常糟糕。那将意味着

someFunc(MyClass().method())

可能不同于

a = MyClass().method()
someFunc(a)

在 Python 中,名称只是附加到对象的标签。对象不知道它们附有什么标签,这是一件好事。您可能会将计算结果分配给中间变量,以使后续行更具可读性,并且您不希望该分配更改该计算的结果。

于 2012-09-05T03:37:32.140 回答
1

直接调用和将其分配给变量应该没有区别。MyClass(*params).method()您可能会在此处看到您的解释器自动打印返回结果,这就是为什么当变量值包含 EOL 标记时它似乎被拆分的原因。

无法覆盖对变量的默认分配。但是,通过使用对象,您可以轻松地提供自己的挂钩:

class Assigner(object):
    def __init__(self, assignment_callback):
        self.assignment = assignment_callback

    def __setattr__(self, key, value):
        if hasattr(self, 'assignment'):
            value = self.assignment(value)
        super(Assigner, self).__setattr__( key, value )       

def uppercase(value):
    # example function to perform on each attribute assignment
    return value.upper()

然后在您的代码中,而不是直接分配给变量,而是分配给对象的属性:

>>> my = Assigner(uppercase)
>>> my.a = 'foo'
>>> print my.a
FOO
于 2012-09-05T04:02:50.043 回答
1

是的。* Python 允许检查自己的堆栈,可用于查看下一条指令。

#!/usr/bin/env python3
import dis
import inspect
from itertools import dropwhile

class MyClass(object):
    def method(self):
        # inspect the stack to get calling line of code
        frame = inspect.stack()[1].frame
        # disassemble stack frame
        ins = dis.get_instructions(frame.f_code)
        # move to last instruction
        ins = dropwhile(lambda x: x.offset < frame.f_lasti, ins)
        # the last call would have been to this method/function
        current_instruction = ins.__next__()
        assert current_instruction.opname.startswith('CALL_') 
        # peek ahead at the next instruction
        next_instruction = ins.__next__()
        # vary behaviour depending on the next instruction
        if next_instruction.opname.startswith('STORE_'):
            return "returning to assignment"
        elif next_instruction.opname.startswith('CALL_'):
            return "returning to function/method call"
        elif next_instruction.opname == 'POP_TOP':
            print("return value thrown away")
            return "return ignored"
        elif next_instruction.opname == 'PRINT_EXPR':
            return "return to interactive console"
        else:
            return "return to {}".format(next_instruction.opname)

这将导致以下行为:

a = MyClass().method()
print(a)
# returning to assignment

def someFunc(x):
    return x.split()

b = someFunc(MyClass().method())
print(b)
# ['returning', 'to', 'function/method', 'call']

MyClass().method()
# return value thrown away       (if called as program)
# return to interactive console  (if run interactively)

*尽管正如公认的答案所指出的那样,这样做是“非常糟糕的”。它也很脆弱,因为它可能会受到字节码优化的影响。另请参阅:嵌套字典,在设置项目时充当默认字典,但在获取项目时不充当

于 2020-04-13T12:39:14.300 回答