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