2010-03-25 15 views
7

Jestem bardzo nowy w Pythonie i próbuję znaleźć sposób utworzenia obiektu, który ma wartości dostępne przez nazwę atrybutu lub przez indeks. Na przykład sposób, w jaki os.stat() zwraca wartość stat_result lub pwd.getpwnam(), zwraca struct_passwd.Struktura dostępna poprzez nazwy atrybutów lub opcje indeksu

Próbując to zrozumieć, natrafiłem tylko na implementacje C powyższych typów. Nic konkretnego w Pythonie. Jaki jest natywny sposób Pythona do tworzenia tego rodzaju obiektu?

Przepraszam, jeśli już to zostało szeroko omówione. Szukając odpowiedzi, brakuje mi jakiejś podstawowej koncepcji, która wyklucza mnie ze znalezienia odpowiedzi.

Odpowiedz

3

Nie można używać tego samego wdrożenia jako przedmiot wynikowej os.stat() i innych. Jednak Python 2.6 ma nową funkcję fabryczną, która tworzy podobny typ danych o nazwie nazwanej krotce. Nazwana krotka jest krotką, której gniazda mogą być również adresowane po imieniu. Nazwana krotka nie powinna wymagać więcej pamięci, zgodnie z dokumentacją, niż zwykłej krotki, ponieważ nie mają one słownika dla danej instancji. Podpis funkcja fabryczne to:

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

Pierwszy argument określa nazwę nowego typu, drugi argument jest ciągiem znaków (spacja lub oddzielone przecinkami) zawierający nazwy pól i wreszcie, jeśli gadatliwy jest prawdziwe, funkcja fabryczna wydrukuje również wygenerowaną klasę.

Przykład

Załóżmy, że masz krotki zawierający nazwę użytkownika i hasło.Aby uzyskać dostęp do nazwy użytkownika masz pozycja w pozycji zerowej, a hasło jest dostępne w jednej pozycji:

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

Nie ma nic złego z tego kodu, ale krotka nie jest samodokumentujące. Musisz znaleźć i przeczytać dokumentację dotyczącą pozycjonowania pól w krotce. To tutaj nazwana krotka może przyjść z pomocą. Możemy przekodować poprzedni przykład w następujący sposób:

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 

Jeśli jesteś zainteresowany, co kod wygląda dla nowo utworzonego poświadczeń typu można dodać gadatliwy = True do listy argumentów podczas tworzenia typu, w tym szczególny przypadek otrzymujemy następujący wynik:

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)) 

Podany krotka nie tylko zapewniają dostęp do pól przez nazwę, ale zawiera również funkcje pomocnicze, takie jak funkcja _make(), która pomaga tworząc poświadczeń wystąpienie z sekwencji lub iterable. Na przykład:

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

Dokumentacja biblioteki Pythona do namedtuple ma więcej informacji i przykładów kodu, więc sugerujemy take a peek.

5

Python 2.6 wprowadził collections.namedtuple, aby było to łatwiejsze. W starszych wersjach Pythona możesz użyć named tuple recipe.

Cytując bezpośrednio od docs:

>>> 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

obiekt, który ma wartości, które są dostępne za pomocą nazwy atrybutu lub przez indeks

Nie jestem pewien, co masz trudno o to.

Kolekcja dostępna przez indeks implementuje __getitem__.

Kolekcja dostępna pod nazwami implementuje __getattr__ (lub __getattribute__).

Możesz realizować oba bez żadnych problemów. Lub możesz użyć namedtuple.

Aby uprościć życie, można przedłużyć klasę tuple, aby nie trzeba było wdrażać własnego __getitem__. Lub możesz zdefiniować zwykłą klasę, która również ma __getitem__, więc nie musisz zadzierać z __getattr__.

Na przykład

>>> 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 
Powiązane problemy