2010-03-25 10 views
7

Soy muy nuevo en Python y trato de descubrir cómo crear un objeto que tenga valores accesibles por nombre de atributo o por índice. Por ejemplo, la forma en que os.stat() devuelve un stat_result o pwd.getpwnam() devuelve un struct_passwd.Estructura accesible por nombre de atributo u opciones de índice

Al tratar de resolverlo, solo he encontrado implementaciones C de los tipos anteriores. Nada específicamente en Python. ¿Cuál es la forma nativa de Python para crear este tipo de objeto?

Pido disculpas si esto ya se ha cubierto ampliamente. En la búsqueda de una respuesta, me falta un concepto fundamental que me impide encontrar una respuesta.

Respuesta

3

No se puede utilizar la misma aplicación que el objeto resultado de os.stat() y otros. Sin embargo, Python 2.6 tiene una nueva función de fábrica que crea un tipo de datos similar llamado tupla con nombre. Una tupla nombrada es una tupla cuyas ranuras también pueden ser direccionadas por nombre. La tupla nombrada no debería requerir más memoria, según la documentación, que una tupla normal, ya que no tienen un diccionario por instancia. La firma de la función de fábrica es:

collections.namedtuple(typename, field_names[, verbose]) 

El primer argumento especifica el nombre del nuevo tipo, el segundo argumento es una cadena (espacio o separado por comas) que contiene los nombres de campo y, por último, si es prolijo cierto, la la función de fábrica también imprimirá la clase generada.

Ejemplo

Suponga que tiene una tupla que contiene un nombre de usuario y contraseña.Para tener acceso al nombre de usuario que consigue el artículo en la posición cero y se accede a la contraseña en la posición uno:

credential = ('joeuser', 'secret123') 
print 'Username:', credential[0] 
print 'Password:', credential[1] 

No hay nada malo con este código, pero la tupla no es auto-documentado. Debe buscar y leer la documentación sobre el posicionamiento de los campos en la tupla. Aquí es donde la tupla nombrada puede venir al rescate. Podemos recodificar el ejemplo anterior de la siguiente manera:

import collections 
# Create a new sub-tuple named Credential 
Credential = collections.namedtuple('Credential', 'username, password') 

credential = Credential(username='joeuser', password='secret123') 

print 'Username:', credential.username 
print 'Password:', credential.password 

Si está interesado de lo que el código es el siguiente para el tipo de credenciales de nueva creación puede agregar detallado = True a la lista de argumentos al crear el tipo, en este caso particular obtenemos el siguiente resultado:

import collections 
Credential = collections.namedtuple('Credential', 'username, password', verbose=True) 

class Credential(tuple):          
    'Credential(username, password)'      

    __slots__ =() 

    _fields = ('username', 'password') 

    def __new__(_cls, username, password): 
     return _tuple.__new__(_cls, (username, password)) 

    @classmethod 
    def _make(cls, iterable, new=tuple.__new__, len=len): 
     'Make a new Credential object from a sequence or iterable' 
     result = new(cls, iterable)         
     if len(result) != 2:           
      raise TypeError('Expected 2 arguments, got %d' % len(result)) 
     return result 

    def __repr__(self): 
     return 'Credential(username=%r, password=%r)' % self 

    def _asdict(t): 
     'Return a new dict which maps field names to their values' 
     return {'username': t[0], 'password': t[1]} 

    def _replace(_self, **kwds): 
     'Return a new Credential object replacing specified fields with new values' 
     result = _self._make(map(kwds.pop, ('username', 'password'), _self)) 
     if kwds: 
      raise ValueError('Got unexpected field names: %r' % kwds.keys()) 
     return result 

    def __getnewargs__(self): 
     return tuple(self) 

    username = _property(_itemgetter(0)) 
    password = _property(_itemgetter(1)) 

la tupla llamado no sólo proporciona acceso a los campos de nombre, sino también contiene funciones auxiliares tales como la función _Asegúrese() que ayuda a la creación de una instancia de credenciales de una secuencia o iterable. Por ejemplo:

cred_tuple = ('joeuser', 'secret123') 
credential = Credential._make(cred_tuple) 

La documentación de la biblioteca de Python para namedtuple tiene más información y ejemplos de código, por lo que sugiere que take a peek.

5

Python 2.6 introdujo collections.namedtuple para que esto sea fácil. Con las versiones anteriores de Python puede usar el named tuple recipe.

Citando directamente de los documentos:

>>> Point = namedtuple('Point', 'x y') 
>>> p = Point(11, y=22)  # instantiate with positional or keyword arguments 
>>> p[0] + p[1]    # indexable like the plain tuple (11, 22) 
33 
>>> x, y = p    # unpack like a regular tuple 
>>> x, y 
(11, 22) 
>>> p.x + p.y    # fields also accessible by name 
33 
>>> p      # readable __repr__ with a name=value style 
Point(x=11, y=22) 
0

un objeto que tiene valores que son accesibles, ya sea por el nombre del atributo, o por el índice

no estoy seguro de lo que está encontrando difícil sobre esto.

Una colección accesible por instrumentos de índice __getitem__.

Una colección accesible por nombres implementa __getattr__ (o __getattribute__).

Puede implementar ambos sin ningún problema. O bien, puede usar namedtuple.

Para hacer la vida más simple, puede ampliar la clase tuple para que no tenga que implementar su propia __getitem__. O puede definir una clase ordinaria que también tenga __getitem__ para no tener que meterse con __getattr__.

Por ejemplo

>>> class Foo(object): 
...  def __init__(self, x, y, z): 
...   self.x= x 
...   self.y= y 
...   self.z= z 
...  def __getitem__(self, index): 
...   return { 0: self.x, 1: self.y, 2: self.z }[index] 
... 
>>> f= Foo(1,2,3) 
>>> f.x 
1 
>>> f[0] 
1 
>>> f[1] 
2 
>>> f[2] 
3 
>>> f.y 
2 
Cuestiones relacionadas