2

Python では、それ自体が呼び出された場合に結果をコンソールにきれいに出力する関数を書きたいと思います (ほとんどの場合、対話型またはデバッグ用)。この質問の目的のために、何かのステータスをチェックするとしましょう。私がちょうど呼び出す場合

check_status()

私は次のようなものを見たいです:

Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
=================================
System operational: ... ok
Time to ion canon charge is 9m 21s
Booster rocket in AFTERBURNER state
Range check is optimal
Rocket fuel is 10h 19m 40s to depletion
Beer served is type WICKSE LAGER, chill optimal
Suggested catchphrase is 01_FIGHTING_SPIRIT_GOGOGO
Virtual ... on

ただし、変数割り当てのコンテキストで呼び出す場合は、出力をリストとして渡すことも必要です。

not_robot_stat = check_status()
print not_robot_stat
>>> {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'}

それで...関数内で、その出力が割り当てられているかどうかを動的に知る方法はありますか? パラメータの受け渡しに頼ったり、専用の別の関数を作成したりせずに、これを実行できるようにしたいと考えています。私は少しグーグルで調べましたが、バイトコードで遊ぶことに頼らなければならないように見えることはほとんどありません。それは本当に必要ですか?

4

7 に答える 7

5

新しいソリューション

これは、関数の結果がそれ自体のバイトコードを調べることによって割り当てに使用されるときにソリューションが検出する新しいものです。バイトコードの書き込みは行われず、定義にオペコードモジュールを使用するため、Pythonの将来のバージョンとも互換性があるはずです。

import inspect, dis, opcode

def check_status():

    try:
        frame = inspect.currentframe().f_back
        next_opcode = opcode.opname[ord(frame.f_code.co_code[frame.f_lasti+3])]
        if next_opcode == "POP_TOP": 
            # or next_opcode == "RETURN_VALUE":
            # include the above line in the if statement if you consider "return check_status()" to be assignment
            print "I was not assigned"
            print "Pretty printer status check 0.02v"
            print "NOTE: This is so totally not written for giant robots"
            return
    finally:
        del frame    

    # do normal routine

    info = {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

    return info

# no assignment    
def test1():
    check_status()

# assignment
def test2():
    a = check_status()

# could be assignment (check above for options)
def test3():
    return check_status()

# assignment
def test4():
    a = []
    a.append(check_status())
    return a

解決策1

これは、python-iまたはPDBでデバッグしているときに関数を呼び出すたびに検出する古いソリューションです。

import inspect

def check_status():
    frame = inspect.currentframe()
    try:
        if frame.f_back.f_code.co_name == "<module>" and frame.f_back.f_code.co_filename == "<stdin>":
            print "Pretty printer status check 0.02v"
            print "NOTE: This is so totally not written for giant robots"
    finally:
        del frame

    # do regular stuff   
    return {'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

def test():
    check_status()


>>> check_status()
Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

>>> a=check_status()
Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots

>>> a
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5}

test()
>>>
于 2009-05-02T01:35:18.753 に答える
4

ただし、出力をリストとして渡すこともできます。

「出力を辞書として返す」という意味です-注意してください;-)

できることの1つは、Pythonインタープリターの機能を使用して、任意の式の結果を文字列に自動的に変換することです。これを行うには、そのカスタムサブクラスを作成し、dictそれ自体を文字列に変換するように求められたときに、必要なフォーマットを実行します。例えば、

class PrettyDict(dict):
    def __str__(self):
        return '''Pretty printer status check 0.02v
NOTE: This is so totally not written for giant robots
=================================
System operational: ... %s
Time to ion canon charge is %dm %ds
Booster rocket in %s state
 (other stuff)
''' % (self.conf_op and 'ok' or 'OMGPANIC!!!',
       self.t_canoncharge / 60, self.t_canoncharge % 60, 
       BOOSTER_STATES[self.booster_charge],
       ... )

もちろん、コードを書くためのよりきれいな方法を思い付くことができるかもしれませんが、基本的な考え方は、__str__メソッドがオブジェクトの状態を表すきれいに印刷された文字列を作成し、それを返すことです。次に、関数PrettyDictからaを返す場合、入力するとcheck_status()

>>> check_status()

あなたが見るだろう

きれいなプリンターステータスチェック0.02v
注:これは巨大なロボットのために書かれたものではありません
=================================
システムの運用:...わかりました
イオンカノンチャージまでの時間は9分21秒です
アフターバーナー状態のブースターロケット
範囲チェックが最適です
ロケット燃料は10時間19分40秒で枯渇します
提供されるビールはタイプWICKSELAGERで、最適な冷気
推奨されるキャッチフレーズは01_FIGHTING_SPIRIT_GOGOGOです。
バーチャル...オン

唯一の落とし穴は

>>> not_robot_stat = check_status()
>>> print not_robot_stat

関数の一部として文字列への同じ変換が行われるため、同じことが得られますprint。しかし、これを実際のアプリケーションで使用する場合、それが問題になるとは思えません。戻り値を純粋なdictとして本当に見たい場合は、次のようにすることができます。

>>> print repr(not_robot_stat)

代わりに、それはあなたに表示する必要があります

{'cond_op':1、't_canoncharge':1342、'stage_booster':5、'range_est_sigma':0.023、'fuel_est':32557154、'beer_type':31007、'beer_temp':2、'catchphrase_suggestion':1023、 ' virtual_on':'地獄はい'}

重要なのは、他の投稿者が言っているように、Pythonの関数がその戻り値で何が行われるかを知る方法がないということです(編集:わかりました、おそらく奇妙なバイトコードハッキングの方法があるでしょうが、しないでください 'それを行う)-しかし、重要な場合にはそれを回避することができます。

于 2009-05-02T01:32:18.353 に答える
3

これには使用例はありません。Python は、すべてのインタラクティブな結果を という名前の特別な変数に割り当てます_

以下をインタラクティブに実行できます。よく働く。面白いビジネスはありません。

>>> check_status()
{'cond_op': 1, 't_canoncharge': 1342, 'stage_booster': 5, 'range_est_sigma': 0.023, 'fuel_est': 32557154, 'beer_type': 31007, 'beer_temp': 2, 'catchphrase_suggestion': 1023, 'virtual_on': 'hell yes'}

>>> pprint.pprint( _ )
{'beer_temp': 2,
 'beer_type': 31007,
 'catchphrase_suggestion': 1023,
 'cond_op': 1,
 'fuel_est': 32557154,
 'range_est_sigma': 0.023,
 'stage_booster': 5,
 't_canoncharge': 1342,
 'virtual_on': 'hell yes'}
于 2009-05-02T01:42:49.217 に答える
2

関数がその戻り値がどのように使用されているかを知る方法はありません。

おっしゃるとおり、悪質なバイトコードのハッキングによって可能になるかもしれませんが、それは非常に複雑で、おそらく壊れやすいものです。より単純な明示的なルートに進みます。

于 2009-05-02T01:15:11.857 に答える
2

これを行う方法があったとしても、それは悪い考えです。呼び出し元のコンテキストに応じて異なる動作をするものをデバッグしようとすることを想像してみてください。今から 6 か月後、これが大きすぎて一度に頭に入れておくことができないシステムの一部に埋もれていると想像してみてください。

複雑にしないでおく。明示的は暗黙的よりも優れています。pretty-print 関数を作成して (または pprint モジュールを使用して)、結果に対して呼び出すだけです。インタラクティブな Python セッションでは、_ を使用して最後の式の値を取得できます。

于 2009-05-02T05:01:11.957 に答える
0

あなたが望むことをする唯一の方法は確かに「バイトコードで遊ぶ」ことです-その情報を回復する他の方法はありません。もちろん、はるかに優れた方法は、2つの別個の関数を提供することです。1つはdictとしてステータスを取得し、もう1つは最初の関数を呼び出してフォーマットします。

あるいは(優れたアーキテクチャではありませんが)、オプションのパラメータを使用してこれら2つのまったく異なる方法で動作する単一の関数を使用することもできます。関数には1つの関数が必要であるため、これは優れていません。これらのようなもの。

于 2009-05-02T01:18:41.367 に答える
0

関数呼び出しと代入は完全に独立した操作であり、お互いを認識していないため、少なくとも通常の構文手順ではこれを行う方法はありません。

これに対する最も簡単な回避策は、フラグを引数としてcheck_status関数に渡し、それに応じて処理することです。

def check_status(return_dict=False) :
    if return_dict :
        # Return stuff here.
    # Pretty Print stuff here.

その後...

check_status() # Pretty print
not_robot_stat = check_status(True) # Get the dict.

編集:私はあなたが割り当てるよりも頻繁にかなり印刷していると思いました。そうでない場合は、デフォルト値と渡した値を入れ替えてください。

于 2009-05-02T01:16:21.480 に答える