3

注意: これは、関数本体内のグローバル変数を変更する方法に関する質問ではありません。globalキーワードはわかりました。

私のスクリプトには、多数のグローバル構成変数があります。modified_procedure()これらのグローバル変数の 1 つをローカル名前空間 (以下で呼び出します) にシャドウイングし、構成変数を参照する別の関数を呼び出す関数を書きたいと思います。すなわち、

PARAMETER = 1

def procedure():
    return PARAMETER * 3

def modified_procedure():
    PARAMETER += 1
    return procedure()

PARAMETERの本体で発生するため、これは失敗しますmodified_procedure()。インタープリターはそれをローカル変数と見なし、グローバル名前空間で検索しません。グローバル変数を変更しようとしているわけではありませんPARAMETERmodified_procedure()の名前空間でシャドウしようとしています。

いくつかの不便な解決策を考えることができます。

  • スクリプトを OOP 化して、構成変数がオブジェクト属性になるようにし、新しい属性を持つサブクラスを作成できるようにします。procedure()
  • in を使用globalmodified_procedure()て変更PARAMETERし、結果を返す前に復元します。procedure()

シャドーイングでできますPARAMETERか?もしそうなら、どのように?

4

3 に答える 3

4

少しハックですが、以下のアプローチを使用して機能させることができます。

まず、initial メソッドを次のように定義します。

PARAMETER = 1

def procedure(PARAMETER = PARAMETER):
    return PARAMETER * 3

globals()次に、2 番目のメソッドで、メソッドを使用して、変更した で呼び出すことができPARAMETERます。

def modified_procedure_v1():
    PARAMETER = globals()["PARAMETER"] + 1
    return procedure()

次の方法で、更新された PARAMETER 値を使用して、変更されたメソッド内から最初のメソッドを呼び出すこともできます。

def modified_procedure_v2():
    PARAMETER = globals()["PARAMETER"] + 1
    return procedure(PARAMETER)

したがって、最終結果は次のようになります。

>>> modified_procedure_v1() #uses global PARAMETER
3
>>> modified_procedure_v2() #uses PARAMETER value local to this method
6
于 2014-07-31T20:56:02.000 に答える
1

mockライブラリを(ab) 使用して、のグローバル スコープPARAMETERに記録されている asの値を一時的に変更できます。procedure

import mock

def modified_procedure():
    with mock.patch.dict(procedure.func_globals, PARAMETER=PARAMETER+1):
        return procedure()

Python 3 では、サードパーティ ライブラリではなくパッケージmockの一部であり、次のようになります。unittest

from unittest import mock

def modified_procedure():
    with mock.patch.dict(procedure.__globals__, PARAMETER=PARAMETER+1):
        return procedure()

を使用せずmockに、次のようなものを試すことができます

def modified_procedure():
    # Support Python 2 and 3. 
    try:
       d = procedure.__globals__
    except AttributeError:
       d = procedure.func_globals
    # Ensure that procedure()'s globals are restored
    # even if it raises an exception.
    try:
       d['PARAMETER'] += 1
       return procedure()
    finally:
       d['PARAMETER' -= 1
于 2014-07-31T21:05:13.863 に答える
1

あなたが求めているのは、動的スコープに相当します。Python は、今日でも使用されているほとんどの言語 (Perl と Emacs Lisp は例外) と同様に、動的スコープをまったくサポートしておらず、レキシカル スコープを選択しています。

関数オブジェクトを変更して、procedureその を置き換えることができます__globals__。しかし、これはさらにハックで、起動するコードが増えます。procedureパラメータを受け入れるように変更できる場合は、それを行います。グローバルを参照する必要がある場合、グローバルを一時的に変更することは、最も苦痛が少なく、驚くべきアプローチです。

于 2014-07-31T20:56:32.617 に答える