235

Pythonで関数を前方宣言することは可能ですか? cmp宣言する前に 、独自の関数を使用してリストを並べ替えたい。

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

cmp_configs呼び出しの後にメソッドの定義を配置するようにコードを編成しました。次のエラーで失敗します。

NameError: name 'cmp_configs' is not defined

cmp_configsメソッドを使用する前に「宣言」する方法はありますか? それは私のコードをきれいに見せますか?

この問題が発生しないように、コードを再編成する必要があると言う誘惑に駆られる人もいると思います。ただし、これがおそらく避けられない場合もあります。たとえば、何らかの形式の再帰を実装する場合などです。この例が気に入らない場合は、関数を前方宣言することが本当に必要なケースがあると仮定してください。

Python で関数の前方宣言が必要になる次のケースを考えてみましょう。

def spam():
    if end_condition():
        return end_result()
    else:
        return eggs()

def eggs():
    if end_condition():
        return end_result()
    else:
        return spam()

whereend_conditionend_resultは以前に定義されています。

コードを再編成し、常に呼び出しの前に定義を配置する唯一の解決策はありますか?

4

16 に答える 16

164

できることは、呼び出しを独自の関数にラップすることです。

となることによって

foo()

def foo():
    print "Hi!"

壊れますが、

def bar():
    foo()

def foo():
    print "Hi!"

bar()

正常に動作します。

の一般的なルールPythonは、関数をコードの上位で定義する必要があるということではなくPascal( のように)、使用する前に定義する必要があるということです。

それが役立つことを願っています。

于 2009-10-19T19:36:32.520 に答える
105

次の方法でスクリプトを開始する場合:

if __name__=="__main__":
   main()

そうすれば、おそらく「前方宣言」などについて心配する必要はありません。ご覧のとおり、インタープリターはすべての関数をロードしてから、main() 関数を開始します。もちろん、すべてのインポートも正しいことを確認してください ;-)

そういえば、python で「前方宣言」なんて聞いたことない…でも、間違ってるかも ;-)

于 2009-10-19T19:33:53.557 に答える
85

関数を使用する前に定義したくなく、後で定義することが不可能な場合は、他のモジュールで定義するのはどうですか?

技術的には、最初に定義しますが、クリーンです。

次のような再帰を作成できます。

def foo():
    bar()

def bar():
    foo()

Python の関数は、値が匿名であるように匿名ですが、名前にバインドできます。

上記のコードでfoo()は、foo という名前の関数を呼び出すのではなくfoo、呼び出しが行われた時点でたまたまその名前にバインドされている関数を呼び出します。foo別の場所で再定義してbar、新しい関数を呼び出すことができます。

宣言されていない変数を取得するように要求するようなものであるため、問題を解決できません。

于 2009-10-19T19:36:50.490 に答える
12

このスレッドを復活させて申し訳ありませんが、ここで議論されていない戦略が適用される可能性があります。

リフレクションを使用すると、前方宣言に似たことができます。たとえば、次のようなコード セクションがあるとします。

# We want to call a function called 'foo', but it hasn't been defined yet.
function_name = 'foo'
# Calling at this point would produce an error

# Here is the definition
def foo():
    bar()

# Note that at this point the function is defined
    # Time for some reflection...
globals()[function_name]()

したがって、このようにして、実際に定義される前に呼び出したい関数を決定しました。これは実質的に前方宣言です。Python では、Python は関数を呼び出す前に各関数をルックアップする必要があるため、ステートメントは上記の理由による場合globals()[function_name]()と同じです。このモジュールを使用してこれら 2 つのステートメントを比較すると、計算コストは​​まったく同じになります。foo()function_name = 'foo'timeit

もちろん、ここの例は非常に役に立ちませんが、関数を実行する必要があるが、前に宣言する必要がある複雑な構造を持つ場合 (または構造的に後で宣言するのはほとんど意味がありません)、文字列を格納するだけで済みます。後で関数を呼び出してみてください。

于 2014-02-22T04:08:36.543 に答える
11

cmp_configs への呼び出しが独自の関数定義内にある場合は、問題ありません。例を挙げます。

def a():
  b()  # b() hasn't been defined yet, but that's fine because at this point, we're not
       # actually calling it. We're just defining what should happen when a() is called.

a()  # This call fails, because b() hasn't been defined yet, 
     # and thus trying to run a() fails.

def b():
  print "hi"

a()  # This call succeeds because everything has been defined.

一般に、コードを関数 (main() など) 内に配置すると、問題が解決します。ファイルの最後で main() を呼び出すだけです。

于 2009-10-19T19:38:52.690 に答える
10

Python には前方宣言のようなものはありません。関数が必要になる前に、関数が宣言されていることを確認する必要があります。関数が実行されるまで、関数の本体は解釈されないことに注意してください。

次の例を検討してください。

def a():
   b() # won't be resolved until a is invoked.

def b(): 
   print "hello"

a() # here b is already defined so this line won't fail.

関数の本体は、関数を呼び出すと解釈される単なる別のスクリプトであると考えることができます。

于 2009-10-19T19:42:13.770 に答える
8

アルゴリズムは、全体的な構造から始めて詳細にドリルダウンすることで、トップダウンで理解するのが最も簡単な場合があります。

前方宣言なしでこれを行うことができます。

def main():
  make_omelet()
  eat()

def make_omelet():
  break_eggs()
  whisk()
  fry()

def break_eggs():
  for egg in carton:
    break(egg)

# ...

main()
于 2012-05-29T10:37:36.147 に答える
7

いいえ、Python で関数を前方宣言する方法はないと思います。

あなたが Python インタープリターだと想像してください。ラインに着いたら

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

cmp_configs が何であるかを知っているか、知らないかのどちらかです。続行するには、cmp_configs を知っている必要があります。再帰があっても構いません。

于 2009-10-19T19:37:31.693 に答える
4

Python では関数を前方宣言できません。関数を定義する前にロジックを実行している場合は、とにかく問題が発生している可能性があります。アクションをif __name__ == '__main__'スクリプトの最後に配置すると (自明でない場合は「main」という名前の関数を実行することによって)、コードはよりモジュール化され、必要に応じてモジュールとして使用できるようになります。に。

また、そのリスト内包表記をジェネレーター エクスプレス (つまり、print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))に置き換えます。

cmpまた、非推奨のも使用しないでください。keyless-than 関数を使用および提供します。

于 2009-10-20T04:53:42.953 に答える
1

Python は前方宣言をサポートしていませんが、これに対する一般的な回避策は、スクリプト/コードの最後で次の条件を使用することです。

if __name__ == '__main__': main()

これにより、最初にファイル全体を読み取り、次に条件を評価して main() 関数を呼び出します。この関数は、ファイル全体を最初に読み取ったため、前方宣言された関数を呼び出すことができます。この条件は、現在のファイルから Python コードを実行するたびに値__name__を返す特別な変数を利用します (コードがモジュールとしてインポートされた場合は、モジュール名を返します)。__main____name__

于 2020-12-05T17:22:36.353 に答える
0

「この問題が発生しないように、コードを再編成してください。」正しい。簡単にできます。常に動作します。

参照の前にいつでも関数を提供できます。

「しかし、これがおそらく避けられない場合があります。たとえば、何らかの形式の再帰を実装する場合などです」

それがリモートで可能であることがわかりません。関数を使用する前に関数を定義できない場所の例を提供してください。

于 2009-10-19T19:33:09.783 に答える
0

ちょっと待ってください。あなたのモジュールがcmp_configs定義される前に、あなたの例のprintステートメントに到達したとき、それが何をすることを期待していますか?

print を使用した質問の投稿が、実際に次のようなものを表現しようとしている場合:

fn = lambda mylist:"\n".join([str(bla)
                         for bla in sorted(mylist, cmp = cmp_configs)])

このステートメントを実行する前に定義する必要はありませんcmp_configs。コードの後半で定義するだけで、すべてうまくいきます。

cmp_configsラムダへの引数のデフォルト値として参照しようとしている場合、これは別の話です:

fn = lambda mylist,cmp_configs=cmp_configs : \
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)])

cmp_configsこの行に到達する前に変数を定義 する必要があります。

[編集 - 関数のコンパイル時にデフォルトの引数値が割り当てられ、後で cmp_configs の値を変更してもその値が使用されるため、この次の部分は正しくないことが判明しました。]

幸いなことに、Python はそのままでは非常に型に対応しているため、を として定義するかは気にしませんcmp_configs

cmp_configs = None

そして、コンパイラは幸せになるでしょう。cmp_configsを呼び出す前に、必ず real を宣言してくださいfn

于 2009-10-19T19:56:39.753 に答える
-1

1 つの方法は、ハンドラー関数を作成することです。早い段階でハンドラーを定義し、呼び出す必要があるすべてのメソッドの下にハンドラーを配置します。

次に、ハンドラー メソッドを呼び出して関数を呼び出すと、それらは常に使用可能になります。

ハンドラーは引数を取ることができますnameOfMethodToCall。次に、一連の if ステートメントを使用して適切なメソッドを呼び出します。

これで問題が解決します。

def foo():
    print("foo")
    #take input
    nextAction=input('What would you like to do next?:')
    return nextAction

def bar():
    print("bar")
    nextAction=input('What would you like to do next?:')
    return nextAction

def handler(action):
    if(action=="foo"):
        nextAction = foo()
    elif(action=="bar"):
        nextAction = bar()
    else:
        print("You entered invalid input, defaulting to bar")
        nextAction = "bar"
    return nextAction

nextAction=input('What would you like to do next?:')

while 1:
    nextAction = handler(nextAction)
于 2013-08-04T04:24:25.880 に答える