我一直在研究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)
没有分配给裸名时,您将无法更改。
您可以更改如果左侧的分配目标是对象的属性或项目会发生的情况。您可以用a[blah] = ...
覆盖__setitem__
,并用a.blah = ...
覆盖__setattr__
(尽管您只能钩在a
上,而不能在分配的对象上)。但是您不能覆盖或以任何方式影响a = ...
。
请注意,根据“将要发生的事情”进行右侧的侧面更改将变得更加陌生,而且非常糟糕。那意味着
someFunc(MyClass().method())
可以不同于
a = MyClass().method()
someFunc(a)
在Python中,名称只是附加到对象的标签。对象不知道附加了哪些标签,这是一件好事。您可能将结果分配给中间变量以仅使后续行更易读,而又不希望该分配改变该计算的结果。
直接调用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
是。* 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