是否有表示对象分配的方法?

问题描述 投票:0回答:3

我一直在研究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)
python oop magic-methods
3个回答
4
投票

没有分配给裸名时,您将无法更改。

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

请注意,根据“将要发生的事情”进行右侧的侧面更改将变得更加陌生,而且非常糟糕。那意味着

someFunc(MyClass().method())

可以不同于

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

在Python中,名称只是附加到对象的标签。对象不知道附加了哪些标签,这是一件好事。您可能将结果分配给中间变量以仅使后续行更易读,而又不希望该分配改变该计算的结果。


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

0
投票

是。* 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

© www.soinside.com 2019 - 2024. All rights reserved.