Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

extend Python namedtuple with many @properties?

How can namedtuples be extended or subclassed with many additional @properties ?
For a few, one can just write the text below; but there are many, so I'm looking for a generator or property factory. One way would be to generate text from _fields and exec it; another would be an add_fields with the same effect at runtime.
(My @props are to get rows and fields in a database scattered across several tables, so that rec.pname is persontable[rec.personid].pname; but namedtuples-with-smart-fields would have other uses too.)

""" extend namedtuple with many @properties ? """
from collections import namedtuple

Person = namedtuple( "Person", "pname paddr" )  # ...
persontable = [
    Person( "Smith", "NY" ),
    Person( "Jones", "IL" )
    ]

class Top( namedtuple( "Top_", "topid amount personid" )):
    """ @property 
        .person -> persontable[personid]
        .pname -> person.pname ...
    """
    __slots__ = ()
    @property
    def person(self):
        return persontable[self.personid]

    # def add_fields( self, Top.person, Person._fields ) with the same effect as these ?
    @property
    def pname(self):
        return self.person.pname
    @property
    def paddr(self):
        return self.person.paddr
    # ... many more

rec = Top( 0, 42, 1 )
print rec.person, rec.pname, rec.paddr
like image 676
denis Avatar asked Feb 03 '10 15:02

denis


People also ask

Can you modify a Namedtuple?

Since a named tuple is a tuple, and tuples are immutable, it is impossible to change the value of a field. In this case, we have to use another private method _replace() to replace values of the field. The _replace() method will return a new named tuple.

Can Namedtuple be pickled?

@Antimony: pickle handles namedtuple classes just fine; classes defined in a function local namespace not so much.

Can Namedtuple have methods?

index() , namedtuple classes also provide three additional methods and two attributes. To prevent name conflicts with custom fields, the names of these attributes and methods start with an underscore. In this section, you'll learn about these methods and attributes and how they work.


2 Answers

The answer to your question

How can namedtuples be extended or subclassed with additional @properties ?

is: exactly the way you're doing it! What error are you getting? To see a simpler case,

>>> class x(collections.namedtuple('y', 'a b c')):
...   @property
...   def d(self): return 23
... 
>>> a=x(1, 2, 3)
>>> a.d
23
>>> 
like image 193
Alex Martelli Avatar answered Oct 17 '22 16:10

Alex Martelli


How about this?

class Top( namedtuple( "Top_", "topid amount personid" )): 
    """ @property  
        .person -> persontable[personid] 
        .pname -> person.pname ... 
    """ 
    __slots__ = () 
    @property 
    def person(self): 
        return persontable[self.personid] 

    def __getattr__(self,attr):
        if attr in Person._fields:
            return getattr(self.person, attr)
        raise AttributeError("no such attribute '%s'" % attr)
like image 20
PaulMcG Avatar answered Oct 17 '22 16:10

PaulMcG