Em minha busca interminável de complicar demais coisas simples, estou pesquisando a maneira mais 'Pythônica' de fornecer variáveis de configuração globais dentro do típico ' config.py ' encontrado em pacotes de ovo Python.
A maneira tradicional (aah, bom e velho #define !) É a seguinte:
MYSQL_PORT = 3306
MYSQL_DATABASE = 'mydb'
MYSQL_DATABASE_TABLES = ['tb_users', 'tb_groups']
Portanto, as variáveis globais são importadas de uma das seguintes maneiras:
from config import *
dbname = MYSQL_DATABASE
for table in MYSQL_DATABASE_TABLES:
print table
ou:
import config
dbname = config.MYSQL_DATABASE
assert(isinstance(config.MYSQL_PORT, int))
Faz sentido, mas às vezes pode ser um pouco confuso, especialmente quando você está tentando lembrar os nomes de certas variáveis. Além disso, fornecer um objeto de 'configuração' , com variáveis como atributos , pode ser mais flexível. Então, seguindo a orientação do arquivo bpython config.py, eu vim com:
class Struct(object):
def __init__(self, *args):
self.__header__ = str(args[0]) if args else None
def __repr__(self):
if self.__header__ is None:
return super(Struct, self).__repr__()
return self.__header__
def next(self):
""" Fake iteration functionality.
"""
raise StopIteration
def __iter__(self):
""" Fake iteration functionality.
We skip magic attribues and Structs, and return the rest.
"""
ks = self.__dict__.keys()
for k in ks:
if not k.startswith('__') and not isinstance(k, Struct):
yield getattr(self, k)
def __len__(self):
""" Don't count magic attributes or Structs.
"""
ks = self.__dict__.keys()
return len([k for k in ks if not k.startswith('__')\
and not isinstance(k, Struct)])
e um 'config.py' que importa a classe e lê o seguinte:
from _config import Struct as Section
mysql = Section("MySQL specific configuration")
mysql.user = 'root'
mysql.pass = 'secret'
mysql.host = 'localhost'
mysql.port = 3306
mysql.database = 'mydb'
mysql.tables = Section("Tables for 'mydb'")
mysql.tables.users = 'tb_users'
mysql.tables.groups = 'tb_groups'
e é usado desta forma:
from sqlalchemy import MetaData, Table
import config as CONFIG
assert(isinstance(CONFIG.mysql.port, int))
mdata = MetaData(
"mysql://%s:%s@%s:%d/%s" % (
CONFIG.mysql.user,
CONFIG.mysql.pass,
CONFIG.mysql.host,
CONFIG.mysql.port,
CONFIG.mysql.database,
)
)
tables = []
for name in CONFIG.mysql.tables:
tables.append(Table(name, mdata, autoload=True))
O que parece uma forma mais legível, expressiva e flexível de armazenar e buscar variáveis globais dentro de um pacote.
A ideia mais idiota de todos os tempos? Qual é a melhor prática para lidar com essas situações? Qual é a sua maneira de armazenar e buscar nomes globais e variáveis dentro de seu pacote?
fonte
python-box
, veja esta respostaRespostas:
Eu fiz isso uma vez. Por fim, descobri que meu basicconfig.py simplificado é adequado para minhas necessidades. Você pode passar um namespace com outros objetos para referência, se necessário. Você também pode passar padrões adicionais de seu código. Ele também mapeia atributo e sintaxe de estilo de mapeamento para o mesmo objeto de configuração.
fonte
basicconfig.py
arquivo referido parece ter sido movido para github.com/kdart/pycopia/blob/master/core/pycopia/…ConfigHolder
com um dicionário de configurações que gostaria de definir e passar entre os módulos?confit
e ele suporta a fusão de múltiplas fontes. Faz parte de um novo módulo devtest.config .Que tal usar apenas os tipos integrados como este:
Você acessaria os valores da seguinte maneira:
Se você está disposto a sacrificar o potencial de calcular expressões dentro de sua árvore de configuração, pode usar YAML e acabar com um arquivo de configuração mais legível como este:
e usar uma biblioteca como PyYAML para analisar e acessar convenientemente o arquivo de configuração
fonte
Gosto desta solução para pequenas aplicações :
E então o uso é:
.. você deve gostar porque:
App
,@property
, mas isso requer mais código de manipulação variável por item e é baseado em objeto.--Editar-- : Para aplicativos grandes, armazenar valores em um arquivo YAML (ou seja, propriedades) e lê-lo como dados imutáveis é uma abordagem melhor (ou seja, a resposta de blubb / ohaal ). Para pequenas aplicações, a solução acima é mais simples.
fonte
Que tal usar classes?
fonte
Semelhante à resposta de blubb. Eu sugiro construí-los com funções lambda para reduzir o código. Como isso:
Mas isso cheira como se você pudesse querer fazer uma aula.
Ou, como MarkM observou, você pode usar
namedtuple
fonte
pass
é um nome de variável infeliz, pois também é uma palavra-chave.mkDict
lambda. Se chamarmos nossa classeUser
, suas chaves de dicionário "config" seriam inicializadas de forma semelhante{'st3v3': User('password','blonde','Steve Booker')}
. Quando seu "usuário" está em umauser
variável, você pode acessar suas propriedades comouser.hair
etc.User = namedtuple('User', 'passwd hair name'); config = {'st3v3': User('password', 'blonde', 'Steve Booker')}
Uma pequena variação da ideia de Husky que uso. Faça um arquivo chamado 'globais' (ou o que você quiser) e defina várias classes nele, como:
Então, se você tiver dois arquivos de código c1.py e c2.py, ambos podem ter no topo
Agora todos os códigos podem acessar e definir valores, como:
As pessoas esquecem que as classes existem, mesmo que nenhum objeto seja instanciado que seja membro dessa classe. E variáveis em uma classe que não são precedidas por 'self'. são compartilhados por todas as instâncias da classe, mesmo se não houver nenhuma. Depois que 'depurar' for alterado por qualquer código, todos os outros códigos verão a alteração.
Ao importá-lo como gl, você pode ter vários arquivos e variáveis que permitem acessar e definir valores em arquivos de código, funções, etc., mas sem perigo de colisão de namespace.
Isso não tem a verificação de erros inteligente de outras abordagens, mas é simples e fácil de seguir.
fonte
globals
, uma vez que é uma função embutida que retorna um dict com cada símbolo no escopo global atual. Além disso, o PEP8 recomenda CamelCase (com todas as letras maiúsculas nas siglas) para as classes (ou sejaDBInfo
) e maiúsculas com sublinhados para as chamadas constantes (ou sejaDEBUG
).globals
, autor deveria mudar o nomeVamos ser honestos, provavelmente devemos considerar o uso de uma biblioteca mantida pela Python Software Foundation :
https://docs.python.org/3/library/configparser.html
Exemplo de configuração: (formato ini, mas JSON disponível)
Exemplo de código:
Tornando-o acessível globalmente:
Desvantagens:
fonte
verifique o sistema de configuração IPython, implementado via traitlets para a aplicação de tipo que você está fazendo manualmente.
Recorte e cole aqui para cumprir as diretrizes do SO para não apenas remover links, pois o conteúdo dos links muda com o tempo.
documentação de traitlets
Para conseguir isso, eles basicamente definem 3 classes de objetos e suas relações entre si:
1) Configuração - basicamente um mapa de cadeia / dicionário básico com alguns aprimoramentos para fusão.
2) Configurável - classe base para criar uma subclasse de todas as coisas que você deseja configurar.
3) Aplicativo - objeto que é instanciado para executar uma função de aplicativo específica, ou seu aplicativo principal para software de propósito único.
Em suas palavras:
fonte