9

Stack Overflowには、Pythonのグローバル変数に関して多くの質問があり、他の言語から来た人々にはある程度の混乱が生じるようです。スコープルールは、他のバックグラウンドを持つ多くの人々が期待するように正確に機能するわけではありません。

同時に、コードはクラスレベルではなく、モジュールレベルで編成されることを目的としています。したがって、すべてが必ずしもクラスに含まれているとは限らない場合、メンバー変数に含まれているはずの状態をモジュールレベルの変数に含めることができます。

だから私の質問は2つの部分です:

1)グローバルの使用を避ける必要がありますか(具体的には、関数内からグローバルを設定し、グローバルキーワードを使用します)?

2)#1が「はい」の場合、それらが使用されると予想される一般的なパターンはありますか?

私は多くの異なる言語がたくさんある場所で働いており、混乱を緩和し、pythonistasが後で私を嫌わないようにしたいと思っています。

建設的なご意見ありがとうございます。

4

4 に答える 4

7

「 Pythonでのシングルトンとその問題」というタイトルのこのブログ投稿を読むことを強くお勧めします。それは私にグローバル変数の使用を再考させました。いくつかの選択の引用:

ただし、注意してください。シングルトンデザインパターンを実装していないからといって、シングルトンのコア問題を回避できるわけではありません。シングルトンの中心的な問題は、グローバルな共有状態です。シングルトンは、栄光に満ちたグローバル変数にすぎません。Javaのような言語では、シングルトンのようなものを使用する理由はたくさんあります。Pythonでは、シングルトンとは異なるものがあり、非常に無邪気な名前が付いているため、厄介な詳細が隠されています:モジュール。

そうです、Pythonモジュールはシングルトンです。また、シングルトンパターンと同じ問題がありますが、少し悪いだけです。

そして、このような共有状態が発生する可能性のある問題の一例を次に示します。

無関係なことについて話さないために、標準ライブラリのモジュールの1つであるmimetypesモジュールを見てみましょう。

見てください:

inited = False

def init(files=None):
    global inited
    db = MimeTypes()
    ...

これは、Pythonに付属しているmimetypesモジュールの実際のコードですが、より厄介な詳細が削除されています。ポイントは、共有状態があるということです。また、共有状態はブールフラグであり、モジュールが初期化されている場合はTrue、初期化されていない場合はFalseです。mimetypesはそれ自体を初期化するため、この特定のケースはおそらくそれほど問題にはなりません(私を信じてください)が、init関数にfilesパラメーターがあることがわかります。その関数にファイルのリストを渡すと、それらのファイルからのmime情報を使用して、メモリ内のmimeデータベースが再初期化されます。ここで、2つの異なるソースでmimetypeを初期化する2つのライブラリがある場合にどうなるか想像してみてください…</ p>

これは十分に一般的なパターンであり、私は自分でそれを行いました...しかし、たとえば、それを行うためのより良い方法は次のようになります:initすべてのメソッドを実装するクラスのインスタンスを返し、コードの他の部分initは前者に干渉しない異なるパラメータを持つ異なるインスタンス。「欠点」は、新しいインスタンスを初期化したくないコードにこのインスタンスを渡す必要があることですが、その「欠点」の利点は、依存関係が何であるかを明確にすることです。

とにかく、要するに、私はそれをできるだけ避けようとします、しかしあなたが暗黙のシングルトンを持っているコードで大丈夫ならそれからそれを選んでください。

于 2012-09-28T15:24:51.060 に答える
3

global要するに、はい、あなたはキーワードの使用を避けるべきです。それは理由のためにその言語であるかもしれませんが、私は一般的にそれをコードの臭いと考えています-あなたが維持したいいくつかの状態がある場合は、それをクラスにカプセル化します。これは、を使用するよりもはるかに脆弱ではありませんglobal

于 2012-09-28T15:17:33.760 に答える
3

私はあなたの他の質問にその発言をしたので、ここに私の2セントがあります:

Pythonはオブジェクト指向ですが、使用する必要はありません。ただし、必要に応じて、クラスのこのメカニズムを利用して、いくつかのプロパティを保持できます。

class Config():
"""
hold some vars for example.
"""
def __init__(self):
    self.CONFIG_LOG_FILE_DIR='/tmp2/ozn/venus_mon_log/'
    self.DATE_FORMAT="%Y%m%d"
    #self.FILE_NAME_BASE_TEMPLATE=eval('datetime.datetime.now().strftime(self.DATE_FORMAT)')+'-venus_utilization.log'
    self.FILE_NAME_BASE_TEMPLATE='venus_utilization.log'
    self.FILE_NAME=self.CONFIG_LOG_FILE_DIR+self.FILE_NAME_BASE_TEMPLATE
    self.MAX_FILE_SIZE=1024*1024*50 # in Byte, 50 in MB.

プロパティへのアクセスを提供するインスタンスを作成できます。

   cfg = Config()

そして、以下を使用してそれらにアクセスします。

   cfg.MAX_FILE_SIZE

またはそれらを変更する:

   cfg.MAX_FILE_SIZE=50000 
   cfg.MAX_FILE_SIZE=calculateNewSize() 

など...次のようなこともできます。

 # this will print all items that an instance has    
 if options.debug:
    print "DEBUG INFO:"
    for k,v in vars(cfg).iteritems():
        print k,v
于 2012-09-28T15:28:39.067 に答える
2

グローバルは実際にはタブーではありません。使用する前に、関数でグローバルとして宣言することを忘れないでください。私の意見では、ユーザーはあなたがグローバルを明示的に使用していることを知っているので、これは実際にそれらをより明確にします。

私は、Python以外の人が、Pythonグローバルを理解しておらず、コードを変更して、適切なグローバル宣言を追加していないことを恐れています。

于 2012-09-28T15:10:15.497 に答える