任何表示对象赋值的方法?

时间:2012-09-05 03:35:42

标签: python oop magic-methods

我一直在研究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)

3 个答案:

答案 0 :(得分:4)

没有。您无法更改分配给裸名称时发生的情况。

如果左侧的分配目标是对象的属性或项目,可以更改发生的情况。您可以使用a[blah] = ...覆盖__setitem__,使用a.blah = ...覆盖__setattr__(尽管您只能在a上覆盖这些内容,而不是在被分配的对象上。但是你无法覆盖或以任何方式影响a = ...

请注意,根据“将要发生的事情”改变正确的 - 手边会更加奇怪,而且非常糟糕。这意味着

someFunc(MyClass().method())

可能与

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

在Python中,名称只是附加到对象的标签。对象无法知道贴在哪些标签上,这是件好事。您可以将计算结果分配给中间变量,以使后续行更具可读性,并且您不希望该分配更改该计算的结果。

答案 1 :(得分: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)

*尽管正如公认的答案所指出,这样做“非常糟糕”。 它也很脆弱,因为它可能会受到字节码优化的影响。另请参见:Nested dictionary that acts as defaultdict when setting items but not when getting items

答案 2 :(得分:0)

直接调用MyClass(*params).method()并将其分配给变量之间应该存在 no 之间的区别。您可能在这里看到的是您的解释器自动打印返回结果,这就是为什么它似乎在变量值包含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