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__(ただし、これらはにのみフックでき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)

*受け入れられた答えが指摘しているように、そうすることは「非常に悪い」です。また、バイトコードの最適化の影響を受ける可能性があるため、脆弱です。参照:アイテムを設定するときはdefaultdictとして機能するが、アイテムを取得するときは機能しないネストされた辞書

于 2020-04-13T12:39:14.300 に答える