How to create module-wide variables in Python? [duplicate] Ask Question

How to create module-wide variables in Python? [duplicate] Ask Question

Is there a way to set up a global variable inside of a module? When I tried to do it the most obvious way as appears below, the Python interpreter said the variable __DBNAME__ did not exist.

...
__DBNAME__ = None

def initDB(name):
    if not __DBNAME__:
        __DBNAME__ = name
    else:
        raise RuntimeError("Database name has already been set.")
...

And after importing the module in a different file

...
import mymodule
mymodule.initDB('mydb.sqlite')
...

And the traceback was:

... UnboundLocalError: local variable 'DBNAME' referenced before assignment ...

Any ideas? I'm trying to set up a singleton by using a module, as per this fellow's recommendation.

ベストアンサー1

Here is what is going on.

First, the only global variables Python really has are module-scoped variables. You cannot make a variable that is truly global; all you can do is make a variable in a particular scope. (If you make a variable inside the Python interpreter, and then import other modules, your variable is in the outermost scope and thus global within your Python session.)

All you have to do to make a module-global variable is just assign to a name.

Imagine a file called foo.py, containing this single line:

X = 1

Now imagine you import it.

import foo
print(foo.X)  # prints 1

However, let's suppose you want to use one of your module-scope variables as a global inside a function, as in your example. Python's default is to assume that function variables are local. You simply add a global declaration in your function, before you try to use the global.

def initDB(name):
    global __DBNAME__  # add this line!
    if __DBNAME__ is None: # see notes below; explicit test for None
        __DBNAME__ = name
    else:
        raise RuntimeError("Database name has already been set.")

By the way, for this example, the simple if not __DBNAME__ test is adequate, because any string value other than an empty string will evaluate true, so any actual database name will evaluate true. But for variables that might contain a number value that might be 0, you can't just say if not variablename; in that case, you should explicitly test for None using the is operator. I modified the example to add an explicit None test. The explicit test for None is never wrong, so I default to using it.

Finally, as others have noted on this page, two leading underscores signals to Python that you want the variable to be "private" to the module. If you ever do an import * from mymodule, Python will not import names with two leading underscores into your name space. But if you just do a simple import mymodule and then say dir(mymodule) you will see the "private" variables in the list, and if you explicitly refer to mymodule.__DBNAME__ Python won't care, it will just let you refer to it. The double leading underscores are a major clue to users of your module that you don't want them rebinding that name to some value of their own.

Python では、 を行わず、 を使用するか のようなインポートを明示的に行うことimport *で結合を最小限に抑え、明示性を最大限に高めることがベストプラクティスと考えられています。mymodule.somethingfrom mymodule import something

編集: 何らかの理由で、キーワードがない非常に古いバージョンの Python でこのような操作を実行する必要がある場合はglobal、簡単な回避策があります。モジュール グローバル変数を直接設定する代わりに、モジュール グローバル レベルで可変型を使用し、その中に値を格納します。

関数内では、グローバル変数名は読み取り専用になります。実際のグローバル変数名を再バインドすることはできません。(関数内でその変数名に代入すると、関数内のローカル変数名にのみ影響します。) ただし、そのローカル変数名を使用して実際のグローバル オブジェクトにアクセスし、その中にデータを格納することはできます。

を使用することもできますlistが、コードは見苦しくなります。

__DBNAME__ = [None] # use length-1 list as a mutable

# later, in code:  
if __DBNAME__[0] is None:
    __DBNAME__[0] = name

A の方dictが良いです。しかし、最も便利なのはクラス インスタンスであり、単純なクラスを使用できます。

class Box:
    pass

__m = Box()  # m will contain all module-level values
__m.dbname = None  # database name global in module

# later, in code:
if __m.dbname is None:
    __m.dbname = name

(データベース名変数を大文字にする必要はありません。)

__m.dbname私はではなくを使用する構文糖衣が好きです__m["DBNAME"]。これが私の意見では最も便利な解決策のようです。しかし、このdict解決策も問題なく機能します。

を使用すると、任意のハッシュ可能な値をキーとして使用できますが、有効な識別子である名前で十分な場合は、上記のdictような単純なクラスを使用できます。Box

おすすめ記事