Existe uma maneira de definir convenientemente uma estrutura semelhante a C em Python? Estou cansado de escrever coisas como:
class MyStruct():
def __init__(self, field1, field2, field3):
self.field1 = field1
self.field2 = field2
self.field3 = field3
MyStruct = namedtuple("MyStruct", "field1 field2 field3")
pandas.Series(a=42).a
deve fazê-lo se o seu data-cientista ...Respostas:
Use uma tupla nomeada , que foi adicionada ao módulo de coleções na biblioteca padrão no Python 2.6. Também é possível usar a receita de tupla nomeada de Raymond Hettinger se você precisar oferecer suporte ao Python 2.4.
É bom para o seu exemplo básico, mas também abrange vários casos extremos que você pode encontrar mais tarde também. Seu fragmento acima seria escrito como:
O tipo recém-criado pode ser usado assim:
Você também pode usar argumentos nomeados:
fonte
Atualização : Classes de Dados
Com a introdução das classes de dados no Python 3.7 , chegamos muito perto.
O exemplo a seguir é semelhante ao exemplo NamedTuple abaixo, mas o objeto resultante é mutável e permite valores padrão.
Isso funciona bem com o novo módulo de digitação , caso você queira usar anotações de tipo mais específicas.
Eu tenho esperado desesperadamente por isso! Se você me perguntar, Data Classes e a nova declaração NamedTuple , combinadas com o módulo de digitação , são uma dádiva de Deus!
Declaração NamedTuple aprimorada
Desde o Python 3.6 , tornou-se bastante simples e bonito (IMHO), desde que você possa viver com imutabilidade .
Foi introduzida uma nova maneira de declarar NamedTuples , que também permite anotações de tipo :
fonte
dataclass
módulo é novo no Python 3.7, mas você podepip install dataclasses
. É o backport no Python 3.6. pypi.org/project/dataclasses/#description@dataclass
Os detalhes estão aqui: pypi.org/project/dataclasses/#descriptionVocê pode usar uma tupla para muitas coisas em que você usaria uma estrutura em C (algo como coordenadas x, y ou cores RGB, por exemplo).
Para todo o resto, você pode usar o dicionário ou uma classe de utilitário como esta :
Acho que a discussão "definitiva" está aqui , na versão publicada do Python Cookbook.
fonte
TypeError: this constructor takes no arguments
Talvez você esteja procurando Structs sem construtores:
fonte
class Sample:
não fazem nada imediatamente; eles definem atributos de classe. Esses sempre podem ser acessados como por exemploSample.name
.s1
es2
no tempo de execução. A menos que seja proibido de outra forma, você pode adicionar ou modificar oname
atributo em qualquer instância de qualquer classe a qualquer momento, independentemente de a classe ter ou não umname
atributo. Provavelmente, o maior problema funcional ao fazer isso é que diferentes instâncias da mesma classe se comportarão de maneira diferente dependendo se você definiuname
. Se você atualizarSample.name
, qualquer objeto sem umaname
propriedade definida explicitamente retornará o novoname
.self
palavras-chave e uma linha de construtor, se você me perguntar. Gostaria que Jose pudesse editar sua resposta para adicionar uma mensagem de aviso sobre o risco de compartilhar valores acidentalmente entre instâncias.Que tal um dicionário?
Algo assim:
Então você pode usar isso para manipular valores:
E os valores não precisam ser seqüências de caracteres. Eles podem ser praticamente qualquer outro objeto.
fonte
pt3.w = 1 print pt3.w
Em uma linguagem com dicts, é melhor usá-los, especialmente para objetos que estão sendo serializados, pois você pode usar automaticamente o import json para salvá-los e outras bibliotecas de serialização, desde que você não tenha estranhos coisas dentro do seu ditado. Os dicts são a solução para manter dados e lógica separados e são melhores do que estruturas para pessoas que não desejam gravar funções serializadas e desserializadas personalizadas e não desejam usar serializadores não portáteis como pickle.Você pode acessar os campos de uma classe usando um dicionário, porque os campos de uma classe, seus métodos e todas as suas propriedades são armazenados internamente usando dictos (pelo menos no CPython).
... O que nos leva ao seu segundo comentário. Acreditar que os dicionários de Python são "pesados" é um conceito extremamente não-pythonístico. E ler esses comentários mata meu Python Zen. Isso não é bom.
Veja bem, quando você declara uma classe, na verdade está criando um wrapper bastante complexo em torno de um dicionário - portanto, se houver, você está adicionando mais sobrecarga do que usando um dicionário simples. Uma sobrecarga que, a propósito, não tem sentido em nenhum caso. Se você estiver trabalhando em aplicativos críticos para o desempenho, use C ou algo assim.
fonte
self['member']
tem 3 caracteres a mais queself.member
e esses caracteres são todos relativamente fáceis de usar.Você pode subclassificar a estrutura C que está disponível na biblioteca padrão. O módulo ctypes fornece uma classe Structure . O exemplo dos documentos:
fonte
Eu também gostaria de adicionar uma solução que usa slots :
Definitivamente, verifique a documentação quanto a slots, mas uma explicação rápida dos slots é que é a maneira de o python dizer: "Se você pode bloquear esses atributos e somente esses atributos na classe, de forma que você confirme que não adicionará novos atributos uma vez que a classe é instanciado (sim, você pode adicionar novos atributos a uma instância de classe, veja o exemplo abaixo), então eliminarei a grande alocação de memória que permite adicionar novos atributos a uma instância de classe e usarei exatamente o que preciso para esses atributos com fenda ".
Exemplo de adição de atributos à instância da classe (portanto, não usando slots):
Saída: 8
Exemplo de tentativa de adicionar atributos à instância da classe em que os slots foram usados:
Saída: AttributeError: o objeto 'Point' não tem atributo 'z'
Isso pode funcionar efetivamente como uma estrutura e usa menos memória que uma classe (como uma estrutura faria, embora eu não tenha pesquisado exatamente quanto). É recomendável usar slots se você estiver criando uma grande quantidade de instâncias do objeto e não precisar adicionar atributos. Um objeto de ponto é um bom exemplo disso, pois é possível que seja possível instanciar muitos pontos para descrever um conjunto de dados.
fonte
Você também pode passar os parâmetros init para as variáveis da instância pela posição
fonte
Point3dStruct
declaração,Point3dStruct(5, 6)
não funcionará conforme o esperado. É estranho que ninguém tenha escrito isso nos 6 anos.print
>print()
eattrs[n]
>next(attrs)
(o filtro agora é seu próprio objeto iterável e requernext
).Sempre que preciso de um "objeto de dados instantâneos que também se comporte como um dicionário" ( não penso em estruturas em C!), Penso neste truque fofo:
Agora você pode apenas dizer:
Perfeitamente útil para aqueles momentos em que você precisa de um "saco de dados que NÃO é uma classe" e para quando os nomeados são incompreensíveis ...
fonte
Você acessa a estrutura C-Style em python da seguinte maneira.
se você quiser apenas usar o objeto cstruct
se você deseja criar uma matriz de objetos de cstruct
Nota: em vez do nome 'cstruct', use o nome da sua estrutura em vez de var_i, var_f, var_str, defina a variável de membro da sua estrutura.
fonte
Algumas respostas aqui são massivamente elaboradas. A opção mais simples que encontrei é (de: http://norvig.com/python-iaq.html ):
Inicializando:
adicionando mais:
edit: Desculpe, ainda não vi esse exemplo mais abaixo.
fonte
Isso pode ser um pouco tarde, mas eu fiz uma solução usando Python Meta-Classes (versão decoradora abaixo também).
Quando
__init__
é chamado durante o tempo de execução, ele pega cada um dos argumentos e seus valores e os atribui como variáveis de instância à sua classe. Dessa forma, você pode criar uma classe do tipo struct sem precisar atribuir todos os valores manualmente.Meu exemplo não possui verificação de erro, portanto é mais fácil segui-lo.
Aqui está em ação.
Eu postou no reddit e / u / Matchu postou uma versão decorador que é mais limpo. Aconselho você a usá-lo, a menos que queira expandir a versão da metaclasse.
fonte
Eu escrevi um decorador que você pode usar em qualquer método para torná-lo de modo que todos os argumentos passados ou quaisquer padrões sejam atribuídos à instância.
Uma demonstração rápida. Observe que eu uso um argumento posicional
a
, use o valor padrão parab
e um argumento nomeadoc
. Em seguida, imprimo todas as 3 referênciasself
, para mostrar que elas foram atribuídas corretamente antes da inserção do método.Observe que meu decorador deve funcionar com qualquer método, não apenas
__init__
.fonte
Não vejo essa resposta aqui, então acho que vou adicioná-la, já que estou inclinando o Python agora e a descobri. O tutorial do Python (neste caso, o Python 2) fornece o seguinte exemplo simples e eficaz:
Ou seja, um objeto de classe vazio é criado, instanciado e os campos são adicionados dinamicamente.
O lado positivo disso é realmente simples. A desvantagem é que não é particularmente auto-documentada (os membros pretendidos não estão listados em nenhum lugar da classe "definição"), e os campos não definidos podem causar problemas quando acessados. Esses dois problemas podem ser resolvidos por:
Agora, de relance, você pode pelo menos ver quais campos o programa estará esperando.
Ambos são propensos a erros de digitação,
john.slarly = 1000
terão sucesso. Ainda assim, funciona.fonte
Aqui está uma solução que usa uma classe (nunca instanciada) para armazenar dados. Gosto que dessa maneira envolva muito pouca digitação e não exija nenhum pacote adicional, etc.
Você pode adicionar mais campos posteriormente, conforme necessário:
Para obter os valores, os campos são acessados como de costume:
fonte
Pessoalmente, eu também gosto dessa variante. Estende a resposta do @ dF .
Ele suporta dois modos de inicialização (que podem ser combinados):
Além disso, ele imprime melhor:
fonte
A solução a seguir para uma estrutura é inspirada na implementação do nomeado duplo e em algumas das respostas anteriores. No entanto, ao contrário do duplo nomeado, ele é mutável, em seus valores, mas como a estrutura do estilo c imutável nos nomes / atributos, que não são uma classe ou ditado normal.
Uso:
fonte
Existe um pacote python exatamente para esse fim. veja cstruct2py
cstruct2py
é uma biblioteca python pura para gerar classes python a partir do código C e usá-las para compactar e descompactar dados. A biblioteca pode analisar os cabeçalhos C (declarações de estruturas, uniões, enumerações e matrizes) e emulá-los em python. As classes pitônicas geradas podem analisar e compactar os dados.Por exemplo:
Primeiro, precisamos gerar as estruturas pitônicas:
Agora podemos importar todos os nomes do código C:
Também podemos fazer isso diretamente:
Usando tipos e definições do código C
A saída será:
Para
cstruct2py
execução de clone :fonte
Eu acho que o dicionário de estrutura Python é adequado para esse requisito.
fonte
https://stackoverflow.com/a/32448434/159695 não funciona no Python3.
https://stackoverflow.com/a/35993/159695 funciona em Python3.
E eu o estendo para adicionar valores padrão.
fonte
Se você não possui um 3.7 para @dataclass e precisa de mutabilidade, o código a seguir pode funcionar para você. É bastante auto-documentado e amigável ao IDE (preenchimento automático), evita escrever as coisas duas vezes, é facilmente extensível e é muito simples testar se todas as variáveis de instância são completamente inicializadas:
fonte
Aqui está um truque rápido e sujo:
Como isso funciona? Apenas reutiliza a classe builtin
Warning
(derivada deException
) e use-a como se fosse sua própria classe definida.Os pontos positivos são que você não precisa importar ou definir nada primeiro, que "Aviso" é um nome abreviado e também deixa claro que você está fazendo algo sujo que não deve ser usado em outro lugar que não seja um pequeno script seu.
A propósito, tentei encontrar algo ainda mais simples,
ms = object()
mas não consegui (este último exemplo não está funcionando). Se você tiver um, estou interessado.fonte
A melhor maneira de fazer isso foi usar uma classe de dicionário personalizada, conforme explicado neste post: https://stackoverflow.com/a/14620633/8484485
Se o suporte ao preenchimento automático do iPython for necessário, basta definir a função dir () assim:
Você define sua pseudo estrutura da seguinte forma: (esta é aninhada)
Você pode acessar os valores dentro de my_struct assim:
print(my_struct.com1.inst)
=>
[5]
fonte
NamedTuple é confortável. mas ninguém compartilha o desempenho e o armazenamento.
Se você
__dict__
não estiver usando, escolha entre__slots__
(maior desempenho e armazenamento) eNamedTuple
(limpe para leitura e uso)Você pode revisar este link ( Uso de slots ) para obter mais
__slots__
informações.fonte