Jak zrobić zmienną cross-module?

Zmienna __debug__ jest po części przydatna, ponieważ wpływa na każdy moduł. Jeśli chcę utworzyć inną zmienną, która działa w ten sam sposób, jak to zrobić?

Zmienna (bądźmy oryginalni i nazwijmy ją 'foo') nie musi być naprawdę globalna, w tym sensie, że jeśli zmienię foo w jednym module, będzie aktualizowana w innych. Byłbym w porządku, gdybym mógł ustawić foo przed importowaniem innych modułów, a następnie zobaczyliby tę samą wartość dla niego.

Author: codeforester, 2008-09-27

12 answers

Nie popieram tego rozwiązania w żaden sposób, w formie ani formie. Ale jeśli dodasz zmienną do modułu __builtin__, będzie ona dostępna tak, jakby globalna z dowolnego innego modułu, który zawiera __builtin__ -- czyli wszystkie z nich, domyślnie.

A.py zawiera

print foo

B.py zawiera

import __builtin__
__builtin__.foo = 1
import a

Wynikiem jest wydrukowanie "1".

Edit: Moduł __builtin__ jest dostępny jako symbol lokalny __builtins__ - to jest powód rozbieżności między dwiema z tych odpowiedzi. Również zauważ, że __builtin__ został przemianowany na builtins w python3.

 97
Author: Curt Hagenlocher,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-10 13:05:44

Jeśli potrzebujesz globalnej zmiennej międzymodułowej, może wystarczy prosta globalna zmienna poziomu modułu.

A.py:

var = 1

B.py:

import a
print a.var
import c
print a.var

C.py:

import a
a.var = 2

Test:

$ python b.py
# -> 1 2

Przykład z prawdziwego świata: Django ' s global_settings.py (chociaż w Django ustawienia aplikacji są używane przez importowanie obiektu django.conf.settings).

 139
Author: jfs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-15 22:13:22

Zdefiniuj moduł (nazwij go "globalbaz") i zdefiniuj w nim zmienne. Wszystkie moduły używające tego "pseudoglobal" powinny importować moduł " globalbaz "i odwoływać się do niego za pomocą" globalbaz.var_name "

To działa niezależnie od miejsca zmiany, możesz zmienić zmienną przed lub po imporcie. Zaimportowany moduł użyje najnowszej wartości. (Testowałem to na przykładzie zabawki)

Dla wyjaśnienia, globalbaz.py wygląda tak:

var_name = "my_useful_string"
 21
Author: hayalci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 00:15:19

Uważam, że istnieje wiele okoliczności, w których ma to sens i upraszcza programowanie, aby mieć pewne globale, które są znane w kilku (ściśle powiązanych) modułach. W tym duchu chciałbym nieco rozwinąć pomysł posiadania modułu globals, który jest importowany przez te moduły, które muszą się do nich odwoływać.

Gdy istnieje tylko jeden taki moduł, nazywam go "g". W nim przypisuję domyślne wartości dla każdej zmiennej, którą zamierzam traktować jako globalną. W każdym moduł, który używa żadnego z nich, nie używam "from g import var", ponieważ powoduje to tylko zmienną lokalną, która jest inicjalizowana od g tylko w momencie importu. Większość odniesień robię w postaci g. var, A "g." służy jako stałe przypomnienie, że mam do czynienia ze zmienną, która jest potencjalnie dostępna dla innych modułów.

Jeśli wartość takiej zmiennej globalnej ma być często używana w jakiejś funkcji w module, to funkcja ta może wykonać lokalną kopię: var = g. var. Jednak ważne jest, aby zdać sobie sprawę, że przypisania do var są lokalne i globalne g. var nie mogą być aktualizowane bez wyraźnego odniesienia się do G.var w przypisaniu.

Zauważ, że możesz mieć wiele takich modułów globalnych współdzielonych przez różne podzbiory Twoich modułów, aby utrzymać nieco ściślejszą kontrolę. Powodem, dla którego używam krótkich nazw dla moich modułów globals, jest unikanie zbytniego zaśmiecania kodu ich wystąpieniami. Z niewielkim doświadczeniem stają się mnemoniczne wystarczy tylko 1 lub 2 znaki.

Jest nadal możliwe przypisanie do, powiedzmy, g. x, gdy x nie było jeszcze zdefiniowane w g, a inny moduł może wtedy uzyskać dostęp do g. x. jednak, mimo że interpreter na to pozwala, takie podejście nie jest tak przejrzyste, a ja go unikam. Nadal istnieje możliwość przypadkowego utworzenia nowej zmiennej w g w wyniku literówki w nazwie zmiennej dla przypisania. Czasami badanie dir (g) jest przydatne, aby odkryć jakiekolwiek zaskakujące nazwiska, które mogły powstać w wyniku takiego wypadku.

 21
Author: David Vanderschel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-26 20:14:08

Możesz przekazać globale jednego modułu do onother:

W Module A:

import module_b
my_var=2
module_b.do_something_with_my_globals(globals())
print my_var

W Module B:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3
 9
Author: user394430,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-17 02:22:22

Zmienne globalne są zazwyczaj złym pomysłem, ale możesz to zrobić przypisując do __builtins__:

__builtins__.foo = 'something'
print foo

Również same moduły są zmiennymi, do których można uzyskać dostęp z dowolnego modułu. Więc jeśli zdefiniujesz moduł o nazwie my_globals.py:

# my_globals.py
foo = 'something'

Wtedy możesz użyć tego z dowolnego miejsca:

import my_globals
print my_globals.foo

Używanie modułów zamiast modyfikowania {[3] } jest generalnie czystszym sposobem robienia tego typu globali.

 7
Author: spiv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-27 01:03:43

Możesz już to zrobić ze zmiennymi poziomu modułu. Moduły są takie same bez względu na to, z jakiego modułu są importowane. Możesz więc zmienić zmienną na poziomie modułu w dowolnym module, który ma sens, aby ją umieścić, i uzyskać do niej dostęp lub przypisać do niej z innych modułów. Lepiej byĹ 'oby wywoĹ' aÄ ‡ funkcjÄ ™ ustawiajÄ ... cÄ ... wartoĹ "Ä ‡ zmiennej lub uczyniÄ ‡ z niej wĹ 'asnoĹ" Ä ‡ pewnego obiektu singleton. W ten sposób, jeśli będziesz musiał uruchomić jakiś kod po zmianie zmiennej, możesz to zrobić bez uszkodzenia zewnętrznego interfejsu modułu.

Zazwyczaj nie jest to świetny sposób na robienie rzeczy-używanie globali rzadko jest - ale myślę, że jest to najczystszy sposób, aby to zrobić.

 5
Author: intuited,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-12 01:26:37

Chciałem napisać odpowiedź, że istnieje przypadek, w którym zmienna nie zostanie znaleziona.

Cykliczne importowanie może zakłócić zachowanie modułu.

Na przykład:

First.py

import second
var = 1

Second.py

import first
print(first.var)  # will throw an error because the order of execution happens before var gets declared.

Main.py

import first

Na tym przykładzie powinno to być oczywiste, ale w dużej bazie kodu może to być naprawdę mylące.

 3
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-31 03:14:05

To brzmi jak modyfikacja przestrzeni nazw __builtin__. Do zrobienia:

import __builtin__
__builtin__.foo = 'some-value'

Nie używaj bezpośrednio __builtins__ (zwróć uwagę na dodatkowe "s") - najwyraźniej może to być słownik lub moduł. Dzięki ΤΖΩΤΖΙΟΥ za zwrócenie na to uwagi, więcej można znaleźć tutaj .

Teraz foo jest dostępny do użytku wszędzie.

Nie zalecam robienia tego ogólnie, ale użycie tego zależy od programisty.

Przypisanie do niego musi być wykonane jak wyżej, samo ustawienie {[4] } spowoduje tylko to w bieżącej przestrzeni nazw.

 2
Author: awatts,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-28 00:40:37

Używam tego do kilku wbudowanych prymitywnych funkcji, których naprawdę brakowało. Jednym z przykładów jest funkcja find, która ma taką samą semantykę użycia jak filter, map, reduce.

def builtin_find(f, x, d=None):
    for i in x:
        if f(i):
            return i
    return d

import __builtin__
__builtin__.find = builtin_find

Po uruchomieniu (na przykład poprzez importowanie w pobliżu punktu wejścia) wszystkie Twoje moduły mogą używać funkcji find() tak, jakby była wbudowana.

find(lambda i: i < 0, [1, 3, 0, -5, -10])  # Yields -5, the first negative.

Uwaga: możesz to zrobić, oczywiście, z filtrem i inną linią do przetestowania dla zerowej długości, lub z redukcją w jednym rodzaju dziwnej linii, ale zawsze czułem, że to dziwne.

 1
Author: Brian Arsuaga,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-15 00:10:57

Mogłem uzyskać zmienne modulowalne (lub mutowalne ) używając słownika:

# in myapp.__init__
Timeouts = {} # cross-modules global mutable variables for testing purpose
Timeouts['WAIT_APP_UP_IN_SECONDS'] = 60

# in myapp.mod1
from myapp import Timeouts

def wait_app_up(project_name, port):
    # wait for app until Timeouts['WAIT_APP_UP_IN_SECONDS']
    # ...

# in myapp.test.test_mod1
from myapp import Timeouts

def test_wait_app_up_fail(self):
    timeout_bak = Timeouts['WAIT_APP_UP_IN_SECONDS']
    Timeouts['WAIT_APP_UP_IN_SECONDS'] = 3
    with self.assertRaises(hlp.TimeoutException) as cm:
        wait_app_up(PROJECT_NAME, PROJECT_PORT)
    self.assertEqual("Timeout while waiting for App to start", str(cm.exception))
    Timeouts['WAIT_JENKINS_UP_TIMEOUT_IN_SECONDS'] = timeout_bak

Podczas uruchamiania test_wait_app_up_fail rzeczywisty czas oczekiwania wynosi 3 sekundy.

 0
Author: foudfou,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-12-02 15:24:38

Zastanawiałem się, czy byłoby możliwe uniknięcie niektórych wad używania zmiennych globalnych (patrz np. http://wiki.c2.com/?GlobalVariablesAreBad ) poprzez użycie przestrzeni nazw klasy zamiast globalnej/module do przekazywania wartości zmiennych. Poniższy kod wskazuje, że obie metody są zasadniczo identyczne. Istnieje niewielka przewaga w używaniu przestrzeni nazw klas, jak wyjaśniono poniżej.

Poniższe fragmenty kodu pokazują również, że atrybuty lub zmienne może być dynamicznie tworzony i usuwany zarówno w globalnych / modułowych przestrzeniach nazw, jak i w klasach.

Wall.py

# Note no definition of global variables

class router:
    """ Empty class """

Nazywam ten moduł "ścianą", ponieważ służy do odbijania zmiennych od. Będzie działać jako przestrzeń do tymczasowego definiowania zmiennych globalnych i atrybutów całej klasy pustej klasy "router".

Source.py

import wall
def sourcefn():
    msg = 'Hello world!'
    wall.msg = msg
    wall.router.msg = msg

Ten moduł importuje ścianę i definiuje jedną funkcję sourcefn, która definiuje wiadomość i emituje ją przez dwa różne mechanizmy, jeden przez globals i jeden przez funkcję routera. Zauważ, że zmienne wall.msg i wall.router.message są tu zdefiniowane po raz pierwszy w swoich odpowiednich przestrzeniach nazw.

Dest.py

import wall
def destfn():

    if hasattr(wall, 'msg'):
        print 'global: ' + wall.msg
        del wall.msg
    else:
        print 'global: ' + 'no message'

    if hasattr(wall.router, 'msg'):
        print 'router: ' + wall.router.msg
        del wall.router.msg
    else:
        print 'router: ' + 'no message'

Ten moduł definiuje funkcję destfn, która wykorzystuje dwa różne mechanizmy do odbierania wiadomości emitowanych przez źródło. Pozwala to na możliwość, że zmienna " msg " może nie istnieć. destfn usuwa również zmienne po ich wyświetleniu.

Main.py

import source, dest

source.sourcefn()

dest.destfn() # variables deleted after this call
dest.destfn()

To moduł wywołuje kolejno zdefiniowane wcześniej funkcje. Po pierwszym wywołaniu dest.destfn zmienne wall.msg i wall.router.msg już nie istnieją.

Wyjście z programu to:

Global: Hello world!
Router: Hello world!
global: no message
router: Brak wiadomości

Powyższe fragmenty kodu pokazują, że mechanizmy module/global I class/Class variable są zasadniczo identyczne.

Jeśli wiele zmiennych ma być współdzielonych, przestrzeń nazw zanieczyszczeniem można zarządzać za pomocą kilku modułów typu ściennego, np. wall1, wall2 itp. lub definiując kilka klas typu routera w jednym pliku. Ten ostatni jest nieco bardziej uporządkowany, więc być może stanowi marginalną korzyść dla wykorzystania mechanizmu zmiennej klasy.

 0
Author: robertofbaycot,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-14 11:05:51