create custom namedtuple type with extra features

后端 未结 2 1267
死守一世寂寞
死守一世寂寞 2021-01-18 16:19

I\'d like to create my own type of build-in namedtuple that has some extra features. Let\'s say we create a class:

from collections import namedtuple
MyClass         


        
2条回答
  •  长发绾君心
    2021-01-18 16:48

    namedtuple() uses a string template to generate a class object.

    You could use that same technique for your modified version; but do use the code already generated for you as a base class:

    import sys
    from collections import OrderedDict
    
    _typechecking_class_template = """\
    from collections import namedtuple as _namedtuple
    
    class {typename}(_namedtuple({typename!r}, {field_names!r})):
        '{typename}({arg_list})'
    
        __slots__ = ()
    
        def __new__(_cls, {arg_list}):
            'Create new instance of {typename}({arg_list})'
            for name, type_ in _cls._field_types.items():
                value = locals()[name]
                if not isinstance(value, type_):
                    raise TypeError("Incorrect type {{!r}} for {{}}, expected {{!r}}".format(
                        type(value).__name__, name, type_.__name__))
            return tuple.__new__(_cls, ({arg_list}))
    """
    
    def typechecking_namedtuple(typename, field_names, field_types):
        if isinstance(field_names, str):
            field_names = field_names.replace(',', ' ').split()
        field_names = list(map(str, field_names))
        typename = str(typename)
        class_definition = _typechecking_class_template.format(
            typename = typename,
            field_names = tuple(field_names),
            arg_list = repr(tuple(field_names)).replace("'", "")[1:-1],
        )
        namespace = dict(__name__='typechecking_namedtuple_%s' % typename)
        exec(class_definition, namespace)
        result = namespace[typename]
        result._field_types = OrderedDict(zip(field_names, field_types))
        try:
            module = sys._getframe(1).f_globals.get('__name__', '__main__')
            result.__module__ = module
        except (AttributeError, ValueError):
            pass
        return result
    

    This lets you produce new type-checking namedtuple classes:

    >>> MyClass = typechecking_namedtuple('MyClass', 'field1 field2', (int, float))
    >>> MyClass(42, 81.2)
    MyClass(field1=42, field2=81.2)
    >>> MyClass('fourtytwo', 81.2)
    Traceback (most recent call last):
      File "", line 1, in 
      File "", line 16, in __new__
    TypeError: Incorrect type 'str' for field1, expected 'int'
    >>> MyClass(42, None)
    Traceback (most recent call last):
      File "", line 1, in 
      File "", line 16, in __new__
    TypeError: Incorrect type 'NoneType' for field2, expected 'float'
    

提交回复
热议问题