Pergunta

A variável __debug__ é útil em parte porque afeta todos os módulos. Se eu quiser criar uma outra variável que funciona da mesma maneira, como eu faria isso?

A variável (vamos ser original e chamá-lo de 'foo') não tem que ser verdadeiramente global, no sentido de que se eu mudar foo em um módulo, ele é atualizado em outros. Eu seria bom se eu poderia definir foo antes de importar outros módulos e, em seguida, eles iriam ver o mesmo valor para ele.

Foi útil?

Solução

Eu não endossa esta solução de qualquer maneira, forma ou formulário. Mas se você adicionar uma variável para o módulo __builtin__, será acessível como se um global de qualquer outro módulo que inclui __builtin__ -. Que é de todos eles, por padrão

a.py contém

print foo

b.py contém

import __builtin__
__builtin__.foo = 1
import a

O resultado é que "1" é impresso.

Editar: O módulo __builtin__ está disponível como o símbolo __builtins__ local - essa é a razão para a discrepância entre duas dessas respostas. Observe também que __builtin__ foi renomeado para builtins em python3.

Outras dicas

Se você precisar de uma variável cross-módulo global talvez variável de nível de módulo global apenas simples será suficiente.

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

Exemplo real-world: Django é global_settings.py (embora em aplicações Django configurações são usadas por importar o objeto django.conf.settings ).

Definir um módulo (chamemos-lhe "globalbaz") e têm as variáveis ??definidas dentro dela. Todos os módulos que utilizam este "pseudoglobal" deve importar o módulo "globalbaz", e referem-se a ele usando "globalbaz.var_name"

Isso funciona independentemente do local da mudança, você pode alterar a variável antes ou após a importação. O módulo importado usará o último valor. (Eu testei isso em um exemplo de brinquedo)

Para esclarecimento, olhares globalbaz.py como esta:

var_name = "my_useful_string"

Eu acredito que há uma abundância de circunstâncias em que faz sentido e que simplifica a programação de ter alguns globals que são conhecidos por vários módulos (fortemente acoplados). Neste espírito, eu gostaria de elaborar um pouco sobre a idéia de ter um módulo de globals que é importados por esses módulos que precisam fazer referência a eles.

Quando há apenas um tal módulo, eu o nome de "g". Nele, eu atribuir valores padrão para cada variável que pretendo tratar como global. Em cada módulo que usa qualquer um deles, eu não uso "de g de importação var", pois isso só resulta em uma variável local que é inicializado de g apenas no momento da importação. Eu faço a maioria das referências no g.var forma, e "g". serve como um lembrete constante de que estou lidando com uma variável que é potencialmente acessível a outros módulos.

Se o valor de uma variável como global é para ser usado com frequência em alguma função em um módulo, então essa função pode fazer uma cópia local: var = g.var. No entanto, é importante perceber que as atribuições de var são locais, e g.var global não pode ser atualizado sem fazer referência g.var explicitamente em uma atribuição.

Note que você também pode ter vários módulos tais GLOBALS compartilhadas por diferentes subconjuntos de seus módulos para manter as coisas um pouco mais rigidamente controlados. A razão de eu usar nomes curtos para os meus módulos GLOBALS é evitar desordenar o código muito com ocorrências de-los. Com apenas um pouco de experiência, eles se tornam mnemônico o suficiente com apenas 1 ou 2 caracteres.

É ainda possível fazer uma atribuição para, digamos, g.x quando x não foi já definido em g, e um módulo diferente pode g.x. então o acesso No entanto, embora o intérprete permitir, esta abordagem não é tão transparente, e eu evitá-lo. Há ainda a possibilidade de criar acidentalmente uma nova variável no g como resultado de um erro de digitação no nome da variável para uma atribuição. Às vezes, um exame de dir (g) é útil para descobrir quaisquer nomes surpresa que possam ter surgido por esse acidente.

Você pode passar os globals de um módulo para onother:

No Módulo A:

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

No Módulo B:

def do_something_with_my_globals(glob): # glob is simply a dict.
    glob["my_var"]=3

As variáveis ??globais são geralmente uma má idéia, mas você pode fazer isso através da atribuição de __builtins__:

__builtins__.foo = 'something'
print foo

Além disso, próprios módulos são variáveis ??que podem ser acessados ??a partir de qualquer módulo. Então, se você definir um módulo chamado my_globals.py:

# my_globals.py
foo = 'something'

Em seguida, você pode usar isso em qualquer lugar, bem como:

import my_globals
print my_globals.foo

Usando módulos em vez de modificar __builtins__ é geralmente uma maneira mais limpa para fazer globals desse tipo.

Você já pode fazer isso com variáveis ??de nível de módulo. Os módulos são os mesmos, não importa o módulo que estão sendo importados de. Então você pode fazer a variável de uma variável de nível de módulo em qualquer módulo faz sentido colocá-lo em, e acessá-lo ou atribuir a ele a partir de outros módulos. Seria melhor chamar uma função para definir o valor da variável, ou para torná-lo uma propriedade de algum objeto singleton. Dessa forma, se você acabar precisando para executar algum código quando a variável que mudou, você pode fazê-lo sem quebrar interface externa do seu módulo.

Não é geralmente uma ótima maneira de fazer as coisas - usando globals raramente é - mas eu acho que essa é a forma mais limpa de fazê-lo.

Eu queria postar uma resposta que há um caso em que a variável não será encontrado.

importações cíclicas podem quebrar o comportamento do módulo.

Por exemplo:

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

Nesta é exemplo deveria ser óbvio, mas em uma grande base de código, isso pode ser muito confuso.

Isso soa como modificar o espaço de nome __builtin__. Para fazê-lo:

import __builtin__
__builtin__.foo = 'some-value'

Não use o __builtins__ diretamente (aviso do extra "s") -, aparentemente, isso pode ser um dicionário ou um módulo. Graças à ??O????? para apontar isto, mais pode ser encontrado aqui .

Agora foo está disponível para uso em todos os lugares.

Eu não recomendo fazer isso em geral, mas o uso deste é até o programador.

Atribuir a ele deve ser feito como acima, apenas a criação foo = 'some-other-value' só irá definir-lo no namespace atual.

Eu uso isso para um par built-in funções primitivas que eu senti foram realmente faltando. Um exemplo é a função find que tem a mesma semântica de uso como filtro, mapa, reduzir.

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

import __builtin__
__builtin__.find = builtin_find

Uma vez que este é executado (por exemplo, através da importação de perto do seu ponto de entrada) todos os seus módulos podem usar find () como se, obviamente, que foi construído em.

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

Nota:. Você pode fazer isso, é claro, com filtro e outra linha para teste de comprimento zero, ou com a reduzir em um tipo de linha de estranho, mas eu sempre senti que era estranho

I pode alcançar através do módulo modificável (ou mutável fortes) variáveis ??usando um dicionário:

# 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

Ao lançar test_wait_app_up_fail, a duração do tempo limite real é de 3 segundos.

Gostaria de saber se seria possível evitar algumas das desvantagens do uso de variáveis ??globais (ver, por exemplo http: //wiki.c2.com/?GlobalVariablesAreBad ) usando um espaço de nomes de classe em vez de um namespace / módulo global para passar valores de variáveis. O seguinte código indica que os dois métodos são essencialmente idênticas. Há uma ligeira vantagem na utilização de espaços de nomes de classe, tal como explicado abaixo.

Os seguintes fragmentos de código mostram também que atributos ou variáveis ??podem ser criados e excluídos em ambos os namespaces módulo / globais e namespaces classe dinamicamente.

wall.py

# Note no definition of global variables

class router:
    """ Empty class """

Eu chamo isso de 'muro' módulo, uma vez que é usado para variáveis ??saltar fora. Ele vai atuar como um espaço para definir temporariamente variáveis ??globais e atributos de toda a classe da classe 'router' vazio.

source.py

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

Este módulo importações parede e define um único sourcefn função que define uma mensagem e a emite por dois mecanismos diferentes, uma via globais e uma através da função router. Note-se que as variáveis ??wall.msg e wall.router.message são definidos aqui pela primeira vez em seus respectivos namespaces.

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'

Este módulo define um destfn função que utiliza os dois mecanismos diferentes para receber as mensagens emitidas por fonte. Ele permite a possibilidade de que a variável 'msg' pode não existir. destfn também exclui as variáveis ??uma vez que eles foram exibidos.

main.py

import source, dest

source.sourcefn()

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

Este módulo chama as funções previamente definidas em sequência. Após a primeira chamada para dest.destfn as variáveis ??wall.msg e wall.router.msg não existem mais.

A saída do programa é:

mundial: Olá, mundo!
router: Olá, mundo!
mundial: nenhuma mensagem
router: nenhuma mensagem

Os fragmentos de código acima mostram que o módulo / global e os mecanismos de variáveis ??de classe / classe são essencialmente idênticas.

Se um monte de variáveis ??são para ser compartilhado, poluição namespace pode ser gerenciado ou usando vários módulos do tipo parede, por exemplo, wall1, WALL2 etc, ou através da definição de várias classes de tipo roteador num único ficheiro. O último é ligeiramente mais limpo, de modo que talvez representa uma vantagem marginal para a utilização do mecanismo de classe-variável.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top