4

次の機能があるとしましょう。

def xplusy(x, y):
    return x+y

def xplus1(x):
    xplusy = xplusy(x, 1)
    return xplusy

これを呼び出すa = xplus1(4)と、次のエラーがスローされます。

UnboundLocalError: local variable 'xplusy' referenced before assignment

xplus1次のように再定義すると、エラーは名前の競合が原因です。

def xplus1(x):
    s = xplusy(x, 1)
    return s

それは正常に動作します。

なぜそうなのか: コンパイラは変数と関数呼び出しを正しく区別できないのですか?

それを回避する方法はありますか?

4

5 に答える 5

16

Python では、関数はデータであり、型付けは動的です。これは、次の行が有効な Python であることを意味します。

def func(x):
    return x + 3

func = 3

funcintになりました。元の関数funcは参照されなくなりました。もともと関数だったという事実funcは、将来どのような種類のデータを割り当てることができるかには関係ありません。(これが「動的型付け」の意味です。)

したがって、静的型付けがなく、「関数」が有効なデータ型であるため、Python インタープリターが関数と同じ名前で参照されるデータを区別することは意味がありません。したがって、特定のスコープ内で、同じ非修飾変数名を使用して 2 つの異なることを意味する方法はありません。

あなたの特定のケースでは、xplus1関数のコードが何かを意味する場合、それは「の値を計算してその値を変数にxplusy(x,1)代入し、それによってfunctionへの参照を失う」ことを意味します。ただし、関数のスコープ内では、インタープリターはそのスコープ外の変数への代入を許可しないため、代入ステートメントを記述することで、新しいローカル変数を導入していると想定します。ただし、ローカル変数はまだ定義されていないため、それを呼び出そうとすると失敗します。グローバルに定義された関数はフォールバックとして呼び出されません。これも、修飾されていない 2 つの名前を同一にして、同じスコープ内の異なるデータを指すことができないためです。xplusy xplusyxplusyxplusy(x,1)


「1つのスコープ内で変数名が重複しない」ルールを示す別の例(実際には、この回答を作成しようとしてプロンプトをいじっているときに発見しただけです):

>>> def f1():
...     a = xplusy(3,4)
...     xplusy = 5
...     print xplusy
...
>>> f1()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in f1
UnboundLocalError: local variable 'xplusy' referenced before assignment
>>> def f1():
...     a = xplusy(3,4)
...     print a
...
>>> f1()
7

これは、一意の名前を必要とするステートメントではなく、実際にはscopeであることを示しています。


編集: これは、これおよびその他のスコープ関連の動作を説明する非常にクールな投稿です: http://me.veekun.com/blog/2011/04/24/gotcha-python-scoping-closures/

于 2013-04-22T07:06:25.687 に答える
3

Python関数では、他のオブジェクトと同じであることを意味するファーストクラスオブジェクトです。

「ファースト クラス」オブジェクトとは何ですか?に関する詳細情報

于 2013-04-22T06:53:50.867 に答える
2

これが発生する理由は、xplusy明示的に is と言わない限り変更できないグローバル変数としてスコープに存在するためxplusyですglobal

def xplusy(x,y):
    return x+y

def xplus1(x):
    global xplusy
    xplusy = xplusy(x,1)
    return xplusy

ただし、これは、または最初に返さxplusyれたものを参照します。つまり、最初の後にs をスローします。intfloatxplusyTypeError

これを行うためのよりpythonicな方法は、おそらく次のようになります

def xplus1(x):
    return xplusy(x,1)

またはfunctoolsモジュールを使用する:

from functools import partial
xplus1 = partial(xplusy,y=1) #since you wanted to override y with 1

どの引数がオーバーライドされるか気にしない場合は、単純に行うことができます

xplus1 = partial(xplusy,1)
于 2013-04-22T06:51:39.060 に答える
1

funcNameコールバックなどで、静的な名前 (ではなく) で関数を参照する場合がありますfuncName()。したがって、Python では、変数名は関数用に予約されています。変数に格納する LAMBDA 関数を使用する方法とよく似ています。

于 2013-04-22T06:52:09.763 に答える
1

Python では、xplusy何でも参照できます。あなたはこれを行うことができます:

def xplusy(x, y):
    return x+y

def otherfunction(x, y):
    return x*y

def xplus1(x):
    xplusy = otherfunction
    return  xplusy(x, 1)

変数はスコープ内でxplusy参照さotherfunctionれます。xplus1

xplus1(2)
>>> 2

結果は 2 + 1 ではなく 2 * 1 です。割り当てには注意してください。必要な数の変数を使用してください。

于 2013-04-22T07:00:47.740 に答える