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

发布于 2024-08-26 15:20:44 字数 256 浏览 9 评论 0原文

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

在试图弄清楚这一点时,我只遇到过上述类型的 C 实现。 Python 中没有什么特别的内容。创建此类对象的 Python 本机方法是什么?

如果这已经被广泛报道,我深表歉意。在寻找答案的过程中,我一定错过了一些使我无法找到答案的基本概念。

I am very new to Python, and trying to figure out how to create an object that has values that are accessible either by attribute name, or by index. For example, the way os.stat() returns a stat_result or pwd.getpwnam() returns a struct_passwd.

In trying to figure it out, I've only come across C implementations of the above types. Nothing specifically in Python. What is the Python native way to create this kind of object?

I apologize if this has been widely covered already. In searching for an answer, I must be missing some fundamental concept that is excluding me from finding an answer.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

生寂 2024-09-02 15:20:44

Python 2.6 引入了 collections.namedtuple 来简化此操作。对于较旧的 Python 版本,您可以使用命名元组配方

直接引用文档:

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

Python 2.6 introduced collections.namedtuple to make this easy. With older Python versions you can use the named tuple recipe.

Quoting directly from the 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)
故乡的云 2024-09-02 15:20:44

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

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

第一个参数指定新类型的名称,第二个参数是包含字段名称的字符串(空格或逗号分隔),最后,如果 verbose 为 true,工厂函数还将打印该类生成的。

示例

假设您有一个包含用户名和密码的元组。要访问用户名,您可以在位置 0 处获取该项目,并在位置 1 处访问密码:

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  

如果您对新创建的凭据类型的代码感兴趣,可以在创建类型时将 verbose=True 添加到参数列表中,在这种特殊情况下,我们会得到以下输出:

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() 函数,该函数有助于从序列或可迭代对象创建 Credential 实例。例如:

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

namedtuple 的 python 库文档有更多信息和代码示例,因此我建议您 看一下。

You can't use the same implementation as the result object of os.stat() and others. However Python 2.6 has a new factory function that creates a similar datatype called named tuple. A named tuple is a tuple whose slots can also be addressed by name. The named tuple should not require any more memory, according to the documentation, than a regular tuple, since they don't have a per instance dictionary. The factory function signature is:

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

The first argument specifies the name of the new type, the second argument is a string (space or comma separated) containing the field names and, finally, if verbose is true, the factory function will also print the class generated.

Example

Suppose you have a tuple containing a username and password. To access the username you get the item at position zero and the password is accessed at position one:

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

There's nothing wrong with this code but the tuple isn't self-documenting. You have to find and read the documentation about the positioning of the fields in the tuple. This is where named tuple can come to the rescue. We can recode the previous example as follows:

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  

If you are interested of what the code looks like for the newly created Credential-type you can add verbose=True to the argument list when creating the type, in this particular case we get the following output:

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

The named tuple doesn't only provide access to fields by name but also contains helper functions such as the _make() function which helps creating an Credential instance from a sequence or iterable. For example:

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

The python library documentation for namedtuple has more information and code examples, so I suggest that you take a peek.

定格我的天空 2024-09-02 15:20:44

具有可通过属性名称或索引访问的值的对象

我不确定您对此有何困难。

通过索引访问的集合实现了__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

an object that has values that are accessible either by attribute name, or by index

I'm not sure what you're finding hard about this.

A collection accessible by index implements __getitem__.

A collection accessible by names implements __getattr__ (or __getattribute__).

You can implement both without any trouble at all. Or, you can use namedtuple.

To make life simpler, you could extend the tuple class so you don't have to implement your own __getitem__. Or you can define an ordinary class that also has __getitem__ so you didn't have to mess with __getattr__.

For example

>>> 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文