Why doesn't the namedtuple module use a metaclass to create nt class objects?

后端 未结 4 1768
野性不改
野性不改 2021-02-18 14:02

I spent some time investigating the collections.namedtuple module a few weeks ago. The module uses a factory function which populates the dynamic data (the name of the new

4条回答
  •  遥遥无期
    2021-02-18 14:43

    Here is another approach.

    """ Subclass of tuple with named fields """
    from operator import itemgetter
    from inspect import signature
    
    class MetaTuple(type):
        """ metaclass for NamedTuple """
    
        def __new__(mcs, name, bases, namespace):
            cls = type.__new__(mcs, name, bases, namespace)
            names = signature(cls._signature).parameters.keys()
            for i, key in enumerate(names):
                setattr(cls, key, property(itemgetter(i)))
            return cls
    
    class NamedTuple(tuple, metaclass=MetaTuple):
        """ Subclass of tuple with named fields """
    
        @staticmethod
        def _signature():
            " Override in subclass "
    
        def __new__(cls, *args):
            new = super().__new__(cls, *args)
            if len(new) == len(signature(cls._signature).parameters):
                return new
            return new._signature(*new)
    
    if __name__ == '__main__':
        class Point(NamedTuple):
            " Simple test "
            @staticmethod
            def _signature(x, y, z): # pylint: disable=arguments-differ
                " Three coordinates "
        print(Point((1, 2, 4)))
    

    If this approach has any virtue at all, it's the simplicity. It would be simpler yet without NamedTuple.__new__, which serves only the purpose of enforcing the element count. Without that, it happily allows additional anonymous elements past the named ones, and the primary effect of omitting elements is the IndexError on omitted elements when accessing them by name (with a little work that could be translated to an AttributeError). The error message for an incorrect element count is a bit strange, but it gets the point across. I wouldn't expect this to work with Python 2.

    There is room for further complication, such as a __repr__ method. I have no idea how the performance compares to other implementations (caching the signature length might help), but I much prefer the calling convention as compared to the native namedtuple implementation.

提交回复
热议问题