[Python] creazione attributi di classe da dizionario
Marco Buttu
mbuttu a oa-cagliari.inaf.it
Dom 20 Ott 2013 09:36:48 CEST
On 10/19/2013 12:01 PM, Manlio Perillo wrote:
> On 19/10/2013 09:32, Riccardo mancuso wrote:
>> ciao a tutti,
>> volevo chiedere se č possibile creare degli attributi di una classe,
>> partendo da un dizionario.
>
> Si, č possibile.
> Gli attributi di una classe sono "normalmente" memorizzati del
> dizionario __dict__.
>
>> Mi spiego:
>> supponiamo di avere un dizionario del tipo:
>>
>> dizionario={"auto":1,
>> "casa":2,
>> "moto":3}
>>
>> e poi di creare una classe lista_oggetti:
>>
>> class lista_oggetti(dizionario):
>> def __init__(self,dizionario):
>> pass
>>
>
> Ti basta fare:
>
> self.__dict__.update(dizionario)
Riportando la domanda dello OP:
# --- BEGIN OP
class lista_oggetti(dizionario):
def __init__(self,dizionario):
pass
vorrei fare in modo che vengano creati automaticamente gli attributi
specificati in dizionario, cioč:
lista_oggetti.auto
lista_oggetti.casa
lista_oggetti.moto
# --- END OP
sembra che voglia creare degli attributi _di classe_ piuttosto che di
istanza. Una precisazione quindi (per lui ovviamente, non per te ;) )
Se fai come ha suggerito Manlio, osserva che crei degli attributi _di
istanza_, non di classe:
>>> class Foo:
... def __init__(self, d):
... self.__dict__.update(d)
...
>>> f = Foo({'foo': 100})
>>> f.foo
100
>>> Foo.foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'Foo' has no attribute 'foo'
Se vuoi creare degli attributi _di classe_, e vuoi farlo dopo che la
classe e' stata creata, puoi fare ad esempio:
>>> class Foo:
... def __init__(self, d):
... for k, v in d.items():
... setattr(type(self), k, v) # Vedi sotto la nota sul
perche' ho usato setattr()
...
>>> f = Foo({'foo': 100})
>>> f.foo
100
>>> Foo.foo
100
Se invece vuoi aggiungere gli attributi prima della creazione della
class Foo, perche' vuoi farlo prima che __new__() trasformi in dizionari
in mappingproxy, o per altri motivi, allora devi necessariamente usare
la soluzione con metaclasse, che ti ho proposto prima.
Alcune precisazioni sul perche' ho usato setattr(). In Python 2 avresti
potuto fare:
>>> class Foo:
... def __init__(self, d):
... Foo.__dict__.update(d)
...
>>> f = Foo({'foo': 100})
>>> f.foo
100
>>> Foo.foo
100
Infatti in Python 2 Foo.__dict__ e' un normale dizionario ordinario
(tipo dict):
>>> sys.version_info
sys.version_info(major=2, minor=7, micro=3, releaselevel='final', serial=0)
>>> type(Foo.__dict__)
<type 'dict'>
In Python 3 pero' Foo.__dict__ non e' un dizionario ordinario, ma un
oggetto di tipo types.MappingProxyType:
>>> import sys
>>> sys.version_info
sys.version_info(major=3, minor=3, micro=2, releaselevel='final', serial=0)
>>> type(Foo.__dict__)
<class 'mappingproxy'>
>>> import types
>>> type(Foo.__dict__) is types.MappingProxyType
True
Questo oggetto e' un descriptor:
>>> type(Foo.__dict__['__dict__'])
<class 'getset_descriptor'>
e il suo metodo __set__() ci impedisce di fare, nello stesso identico
modo, quanto abbiamo fatto sopra con Python 2:
>>> class Foo:
... def __init__(self, d):
... Foo.__dict__.update(d)
...
>>> f = Foo({'foo': 100})
Traceback (most recent call last):
...
AttributeError: 'mappingproxy' object has no attribute 'update'
E non possiamo fare neppure un assegnamento:
>>> class Foo:
... def __init__(self, d):
... for k, v in d.items():
... Foo.__dict__[k] = v
...
>>> f = Foo({'foo': 100})
Traceback (most recent call last):
...
TypeError: 'mappingproxy' object does not support item assignment
Questo e' il motivo per cui ho usato setattr(): usando setattr() il
codice funziona sia in Python 2 che in Python 3.
--
Marco Buttu
INAF - Osservatorio Astronomico di Cagliari
Via della Scienza, Loc. Cuccuru Angius
09047 Selargius (CA)
Phone: 070 711 80 217
Email: mbuttu a oa-cagliari.inaf.it
Maggiori informazioni sulla lista
Python