[Python-ideas] Docstrings for namedtuple
Tim Delaney
timothy.c.delaney at gmail.com
Sun Dec 16 22:08:18 CET 2012
It can be made a bit more intelligent. I haven't done anything with
docstrings here, but it wouldn't be hard to add. This automatically handles
defaults (you can call the namedtuple with either zero parameters or the
exact number). You can specify __rename__ = True, which will then only
exclude __dunder_names__ (otherwise all names starting with an underscore
are excluded). You can also pass verbose=[True|False] to the subclass
constructor.
import collections
class NamedTupleMetaClass(type):
# The prepare function
@classmethod
def __prepare__(metacls, name, bases): # No keywords in this case
return collections.OrderedDict()
# The metaclass invocation
def __new__(cls, name, bases, classdict):
fields = collections.OrderedDict()
rename = False
verbose = False
for f in classdict:
if f == '__rename__':
rename = classdict[f]
elif f == '__verbose__':
verbose = classdict[f]
for f in classdict:
if f.startswith('_'):
if not rename:
continue
if f.startswith('__') and f.endswith('__'):
continue
fields[f] = classdict[f]
result = type.__new__(cls, name, bases, classdict)
result.fields = fields
result.rename = rename
result.verbose = verbose
return result
class NamedTuple(metaclass=NamedTupleMetaClass):
def __new__(cls, *p, **kw):
print(p)
if not p:
p = cls.fields.values()
try:
verbose = kw['verbose']
except KeyError:
verbose = cls.verbose
return collections.namedtuple(cls.__name__, list(cls.fields),
rename=cls.rename, verbose=verbose)(*p)
Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64
bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import namedtuple_baseclass
>>> class Point(namedtuple_baseclass.NamedTuple):
... x = 0
... y = 0
...
>>> print(Point())
Point(x=0, y=0)
>>> print(Point(1, 2))
Point(x=1, y=2)
>>> print(Point(1))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\namedtuple_baseclass.py", line 38, in __new__
return collections.namedtuple(cls.__name__, list(cls.fields),
rename=cls.rename, verbose=cls.verbose)(*p)
TypeError: __new__() missing 1 required positional argument: 'y'
>>> print(Point(1, 2, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File ".\namedtuple_baseclass.py", line 38, in __new__
return collections.namedtuple(cls.__name__, list(cls.fields),
rename=cls.rename, verbose=cls.verbose)(*p)
TypeError: __new__() takes 3 positional arguments but 4 were given
>>>
Tim Delaney
On 17 December 2012 07:05, Terry Reedy <tjreedy at udel.edu> wrote:
> On 12/16/2012 8:22 AM, Eli Bendersky wrote:
>
> This may be a good time to say that personally I always disliked
>> namedtuple's creation syntax. It is unpleasant in two respects:
>>
>> 1. You have to repeat the name
>> 2. You have to specify the fields in a space-separated string
>>
>> I wish there was an alternative of something like:
>>
>> @namedtuple
>> class Point:
>> x = 0
>> y = 0
>>
>
> Pretty easy, once one figures out metaclass basics.
>
> import collections as co
>
> class ntmeta():
> def __prepare__(name, bases, **kwds):
> return co.OrderedDict()
> def __new__(cls, name, bases, namespace):
> print(namespace) # shows why filter is needed
> return co.namedtuple(name,
> filter(lambda s: s[0] != '_', namespace))
>
> class Point(metaclass=ntmeta):
>
> x = 0
> y = 0
>
> p = Point(1,2)
> print(p)
> #
> OrderedDict([('__module__', '__main__'), ('__qualname__', 'Point'), ('x',
> 0), ('y', 0)])
> Point(x=1, y=2)
>
> To use the filtered namespace values as defaults (Antoine's suggestion),
> first replace namedtuple() with its body.
> Then modify the header of generated name.__new__. For Point, change
>
> def __new__(_cls, x, y):
> #to
> def __new__(_cls, x=0, y=0):
>
> Also change the newclass docstring. For Point, change
> 'Point(x, y)'
> to
> 'Point(x=0, y=0)'
>
> --
> Terry Jan Reedy
>
>
> ______________________________**_________________
> Python-ideas mailing list
> Python-ideas at python.org
> http://mail.python.org/**mailman/listinfo/python-ideas<http://mail.python.org/mailman/listinfo/python-ideas>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20121217/a3346a54/attachment.html>
More information about the Python-ideas
mailing list