• Python元类实践--自己定义一个和collections中一样的namedtuple


    大家可能很熟悉在collections模块中有一个很好用的扩展数据类型-namedtuple。
    如果你还不知道这个类型,那么请翻看标准手册。

    我利用元类轻松定义一个namedtuple。

    先把代码贴上,满足心急的朋友。

    def myNamedTuple(tuple_name, attrs_str):
        attrs_set = set(attrs_str.split(' '))
        def __init__(self, attrs):         #我们将来实例初始化的时候需要调用的方法。
            for key, value in zip(attrs_set, set(attrs)):
                self.__dict__[key]=value
        def __str__(self):      #这个只是方便打印用的。
            values = [str(x) for x in self.__dict__.values()]
            return tuple_name+'(' + ', '.join(values) + ')'
        def to_dict(self):      #提供一个to_dict()方法,用来把我们的命名元组转为字典。
            return self.__dict__
        #调用type来建立类。
        #第二个参数指定其继承自元组。
        #第三个参数指定我们需要存入的属性名(也就是__dict__的键名,然后就是上面定义的方法。
        return type(tuple_name, (tuple,),{'attr_keys':attrs_set,'__init__':__init__,'__str__':__str__,'to_dict':to_dict})
    
    if __name__=='__main__':
        Point = myNamedTuple('Point','x y')
        p = Point([1,2])      #目前我们的参数只能传入一个,否则报错,这是和namedtuple之间的差别。
        print(p)
        print(type(Point),p, sep='
    ')
        print(p.x,'---',p.y)
        print(p[0],p[1])
        print(p.to_dict)
        p +=(4,)        #此时已经变成了普通的tuple了。内置的namedtuple也是一样。
        print(type(Point),p, sep='
    ')
    
    

    实现方法

    其实,Python的内部也是创建了一个继承自tuple的类。

    >>> from collections import namedtuple
    >>> Rectangle=namedtuple('Rectangle', 'height width')
    >>> r = Rectangle(3,4)
    >>> type(r)
    <class '__main__.Rectangle'>
    

    建立一个列表用来存储所有需要存入的健。在将来实例化调用__init__方法的时候,我们再来建立实例的__dict__属性字典。
    至于取值,那么就是类调用实例的__dict__了。

    如果看不明白的,请先看我关于元类介绍的那一讲。

    改进

    由于我们的类继承自元组,而元组默认只能传入一个可迭代对象。
    那么我们修改一下原来的代码,让我们的myNamedTuple也可以像namedtuple一样可以接受多个参数。

    
    def myNamedTuple(tuple_name, attrs_str):
        class Meta(type):      #定义一个元类,采用`__call__`方法来拦截类的实例化,在实例化之前我们先把位置参数全部转入一个叫args的元组中,然后在调用type的`__call__`方法,从而把刚才的元组传进去,这样就只有一个参数了,从而无论你传入多少个位置参数,在这个步骤之后,只会出现一个参数了,成功!
            def __call__(self, *args):   
                return type.__call__(self, args)   
        attrs_set = set(attrs_str.split(' '))
        def __init__(self, args):
            for key, value in zip(attrs_set, set(args)):
                self.__dict__[key]=value
        def __str__(self):
            values = [str(x) for x in self.__dict__.values()]
            return tuple_name+'(' + ', '.join(values) + ')'
        def to_dict(self):
            return self.__dict__
        return Meta(tuple_name, (tuple,),{'attr_keys':attrs_set,'__init__':__init__,'__str__':__str__,'to_dict':to_dict})
    
    if __name__=='__main__':
        Point = myNamedTuple('Point','x y')
        print(Point)
        p = Point(1,2)     #多个参数成功调用....
        print(p)
        print(type(Point),p, sep='
    ')
        print(p.x,'---',p.y)
        print(p[0],p[1])
        print(p.to_dict)
        p +=(4,)        #此时已经变成了普通的tuple了。
        print(type(Point),p, sep='
    ')
    

    如果有什么不懂的,请留言。

    如果这个例子通了,那么collections中的其他数据类型是不是也是一样的道理呢?

  • 相关阅读:
    all the tops
    es6 and typescript
    [leetcode]question5: Longest Palindromic Substring
    webpack and publish lib
    HTTPClient to use http/https protocol to send request
    《算法导论》-分治法-笔记
    《Linux C编程一站式学习》-笔记
    WIN7中同时打开多个独立Excel窗口
    RAD Studio XE6之Tpanel
    vb中StatusBar1.Panels(3).Text = Format(Date, "yyyy年mm月dd日")是什么意思
  • 原文地址:https://www.cnblogs.com/jessonluo/p/4764753.html
Copyright © 2020-2023  润新知