파이썬에서 모듈 전체 변수를 만드는 방법? [복제]
이 질문에는 이미 답변이 있습니다.
- 함수에서 전역 변수 사용 18 답변
모듈 내부에 전역 변수를 설정하는 방법이 있습니까? 아래에 표시된 것처럼 가장 분명한 방법으로 시도했을 때 파이썬 인터프리터는 변수 __DBNAME__
가 존재하지 않는다고 말했습니다 .
...
__DBNAME__ = None
def initDB(name):
if not __DBNAME__:
__DBNAME__ = name
else:
raise RuntimeError("Database name has already been set.")
...
그리고 다른 파일로 모듈을 가져온 후
...
import mymodule
mymodule.initDB('mydb.sqlite')
...
그리고 역 추적은 다음과 같습니다.
... UnboundLocalError : 할당 전에 로컬 변수 ' DBNAME '이 (가) 참조되었습니다 ...
어떤 아이디어? 이 동료의 권장 사항에 따라 모듈을 사용하여 싱글 톤을 설정하려고 합니다.
여기에 무슨 일이 일어나고 있습니다.
첫째, 파이썬이 실제로 가지고있는 유일한 전역 변수는 모듈 범위 변수입니다. 진정한 전역 변수는 만들 수 없습니다. 당신이 할 수있는 것은 특정 범위에서 변수를 만드는 것입니다. (Python 인터프리터 내에서 변수를 만든 다음 다른 모듈을 가져 오면 변수는 가장 바깥 쪽 범위에 있으므로 Python 세션 내에서 전역입니다.)
모듈 전역 변수를 만들려면 이름에 할당하면됩니다.
이 단일 행을 포함하는 foo.py라는 파일을 상상해보십시오.
X = 1
이제 가져 오기를 상상해보십시오.
import foo
print(foo.X) # prints 1
그러나 예제와 같이 모듈 범위 변수 중 하나를 함수 내부의 전역으로 사용한다고 가정 해 봅시다. 파이썬의 기본값은 함수 변수가 로컬이라고 가정하는 것입니다. 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.")
그런데이 예에서는 if not __DBNAME__
빈 문자열 이외의 문자열 값이 true로 평가되므로 실제 데이터베이스 이름이 true로 평가되므로 단순 테스트가 적합합니다. 그러나 숫자 값이 0 일 수있는 변수의 경우에는 말할 수 없습니다 if not variablename
. 이 경우 연산자 None
사용을 명시 적으로 테스트해야합니다 is
. 명시 적 None
테스트 를 추가하기 위해 예제를 수정했습니다 . 에 대한 명시 적 테스트 None
는 결코 틀리지 않으므로 기본적으로 사용합니다.
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.
It is considered best practice in Python not to do import *
, but to minimize the coupling and maximize explicitness by either using mymodule.something
or by explicitly doing an import like from mymodule import something
.
EDIT: If, for some reason, you need to do something like this in a very old version of Python that doesn't have the global
keyword, there is an easy workaround. Instead of setting a module global variable directly, use a mutable type at the module global level, and store your values inside it.
In your functions, the global variable name will be read-only; you won't be able to rebind the actual global variable name. (If you assign to that variable name inside your function it will only affect the local variable name inside the function.) But you can use that local variable name to access the actual global object, and store data inside it.
You can use a list
but your code will be ugly:
__DBNAME__ = [None] # use length-1 list as a mutable
# later, in code:
if __DBNAME__[0] is None:
__DBNAME__[0] = name
A dict
is better. But the most convenient is a class instance, and you can just use a trivial class:
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
(You don't really need to capitalize the database name variable.)
I like the syntactic sugar of just using __m.dbname
rather than __m["DBNAME"]
; it seems the most convenient solution in my opinion. But the dict
solution works fine also.
With a dict
you can use any hashable value as a key, but when you are happy with names that are valid identifiers, you can use a trivial class like Box
in the above.
Explicit access to module level variables by accessing them explicity on the module
In short: The technique described here is the same as in steveha's answer, except, that no artificial helper object is created to explicitly scope variables. Instead the module object itself is given a variable pointer, and therefore provides explicit scoping upon access from everywhere. (like assignments in local function scope).
Think of it like self for the current module instead of the current instance !
# db.py
import sys
# this is a pointer to the module object instance itself.
this = sys.modules[__name__]
# we can explicitly make assignments on it
this.db_name = None
def initialize_db(name):
if (this.db_name is None):
# also in local function scope. no scope specifier like global is needed
this.db_name = name
# also the name remains free for local use
db_name = "Locally scoped db_name variable. Doesn't do anything here."
else:
msg = "Database is already initialized to {0}."
raise RuntimeError(msg.format(this.db_name))
As modules are cached and therefore import only once, you can import db.py
as often on as many clients as you want, manipulating the same, universal state:
# client_a.py
import db
db.initialize_db('mongo')
# client_b.py
import db
if (db.db_name == 'mongo'):
db.db_name = None # this is the preferred way of usage, as it updates the value for all clients, because they access the same reference from the same module object
# client_c.py
from db import db_name
# be careful when importing like this, as a new reference "db_name" will
# be created in the module namespace of client_c, which points to the value
# that "db.db_name" has at import time of "client_c".
if (db_name == 'mongo'): # checking is fine if "db.db_name" doesn't change
db_name = None # be careful, because this only assigns the reference client_c.db_name to a new value, but leaves db.db_name pointing to its current value.
As an additional bonus I find it quite pythonic overall as it nicely fits Pythons policy of Explicit is better than implicit.
Steveha's answer was helpful to me, but omits an important point (one that I think wisty was getting at). The global keyword is not necessary if you only access but do not assign the variable in the function.
If you assign the variable without the global keyword then Python creates a new local var -- the module variable's value will now be hidden inside the function. Use the global keyword to assign the module var inside a function.
Pylint 1.3.1 under Python 2.7 enforces NOT using global if you don't assign the var.
module_var = '/dev/hello'
def readonly_access():
connect(module_var)
def readwrite_access():
global module_var
module_var = '/dev/hello2'
connect(module_var)
For this, you need to declare the variable as global. However, a global variable is also accessible from outside the module by using module_name.var_name
. Add this as the first line of your module:
global __DBNAME__
You are falling for a subtle quirk. You cannot re-assign module-level variables inside a python function. I think this is there to stop people re-assigning stuff inside a function by accident.
You can access the module namespace, you just shouldn't try to re-assign. If your function assigns something, it automatically becomes a function variable - and python won't look in the module namespace.
You can do:
__DB_NAME__ = None
def func():
if __DB_NAME__:
connect(__DB_NAME__)
else:
connect(Default_value)
but you cannot re-assign __DB_NAME__
inside a function.
One workaround:
__DB_NAME__ = [None]
def func():
if __DB_NAME__[0]:
connect(__DB_NAME__[0])
else:
__DB_NAME__[0] = Default_value
Note, I'm not re-assigning __DB_NAME__
, I'm just modifying its contents.
참고URL : https://stackoverflow.com/questions/1977362/how-to-create-module-wide-variables-in-python
'Programing' 카테고리의 다른 글
"for (… in…)"루프의 요소 순서 (0) | 2020.05.11 |
---|---|
webpack으로 moment.js가 로캘을로드하지 못하게하는 방법은 무엇입니까? (0) | 2020.05.11 |
github에 커밋하기 전에 readme.md 파일이 어떻게 보이는지 어떻게 테스트합니까? (0) | 2020.05.11 |
배열을 비교하는 Jasmine.js (0) | 2020.05.11 |
'for (;;);와 같은 Ajax 호출 응답은 무엇입니까? (0) | 2020.05.11 |