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: mbu...@oa-cagliari.inaf.it

_______________________________________________
Python mailing list
Python@lists.python.it
http://lists.python.it/mailman/listinfo/python

Rispondere a