可通过属性名称或索引选项访问的结构

问题描述:

我对Python非常陌生,并试图找出如何创建具有可通过属性名称或索引访问的值的对象。例如,os.stat()返回一个stat_result的方式,或者pwd.getpwnam()返回一个struct_passwd。可通过属性名称或索引选项访问的结构

在试图弄清楚,我只遇到了上述类型的C实现。没有什么特别的Python。什么是Python原生的方式来创建这种类型的对象?

我很抱歉,如果这已被广泛覆盖。在寻找答案时,我必须错过一些基本概念,即排除我找到答案。

不能使用相同的实现为os.stat()和其他人的结果对象。然而Python 2.6有一个新的工厂函数,它创建一个名为元组的类似数据类型。一个命名的元组是一个元组,其插槽也可以通过名称来寻址。根据文档,指定的元组不应该要求更多的内存,因为它们没有每个实例字典。工厂功能签名是:

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

第一个参数指定的新类型的名称,第二个参数是一个字符串(空格或逗号分隔)包含的字段名称和,最后,如果详细为真,则工厂功能也将打印生成的类。

假设你有一个包含用户名和密码的元组。在零位访问你获得该项目的用户名和密码在一个位置访问:

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

没有什么不对的代码,但元组是不是自我记录。您必须查找并阅读关于元组中字段定位的文档。这是指定的元组可以救援的地方。我们可以重新编码在前面的例子如下:

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 

如果你有兴趣的代码如下所示为新创建的证书类型,你可以在创建类型时添加详细=真参数列表,在此特殊情况下,我们得到以下的输出:

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

命名组不会只提供访问通过名称字段,但也包含辅助功能,如这有助于从一个序列或创建凭证实例_make()函数迭代。例如:

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

为namedtuple Python库文档有更多的信息和代码示例,所以我建议你take a peek.

Python 2.6引入了collections.namedtuple使这个很简单。使用较旧的Python版本,您可以使用named tuple recipe

从文档直接引用:

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

具有可访问或者通过属性名称或指数

我不知道你在做什么值的对象在这方面发现很难。

索引可访问的集合实现__getitem__

可通过名称访问的集合实现__getattr__(或__getattribute__)。

你可以在没有任何麻烦的情况下实现。或者,您可以使用namedtuple

为了使生活更简单,您可以扩展tuple类,以便您不必实施自己的__getitem__。或者你可以定义一个普通类,它也有__getitem__,所以你不必与__getattr__混淆。

例如

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