zoukankan      html  css  js  c++  java
  • Python 通过继承实现标准对象的子类

    idict是dict的子类,它的键值和属性是同步的,并且有强大的默认值机制.

    例如,假设x是idict的一个实例,且x['a']['b']=12,则有x.a.b=12.反之亦然;

    假设'c'不在x的键集合,那么尝试访问x['c']或者x.c,均会直接初始化默认值.

    class idict(dict):
        "super dict class, attributes and keys are equal"
        def __init__(self,d={},dft=None):
            idict.dft=dft
            for k,v in d.items():
                if isinstance(v,dict):
                    self.__setitem__(k,idict(v,idict.dft))
                else:
                    self.__setitem__(k,v)
        def __setitem__(self,k,v):
            dict.__setitem__(self,k,v)
            dict.__setattr__(self,k,v)
        def __missing__(self,k):
            self.__setitem__(k,idict.dft)
            return idict.dft
        __setattr__=__setitem__
        __getattr__=__missing__          
    • 字典访问d['k']和属性访问d.k有着微妙的关系.

    对于常规访问,字典端对应__getitem__,属性端对应__getattribute__

    对于缺失访问,字典端对应__missing__,属性端对应__getattr__

    对于添加或更新值,字典端对应__setitem__,属性端对应__setattr__

    • __init__中定义一个类属性idict.dft=dft是非常有必要的.(为什么不self.dft=dft?)
    • __init__能调用实例的__setitem__方法,也能递归调用父类idict.
    • 子类的__init__未必总是需要调用父类的__init__.此例中,通过递归idict(v,idict.dft)初始化实例属性,非常精妙.
    • 重写特殊方法的最简单的工具是直接调用父类的同类方法.例如在定义idict的__setitem__方法时,用到了dict.__setitem__

    idict有什么实际的好处?

    首先能够设置默认值,这样就能减少一些判断.这相当于dict.setdefault(k,v),但是idict[k]不是优雅许多吗?

    其次属性形式的控制风格,便于写代码(虽然看起来有些无聊).例如idict['a']['b']['c']=2,就没有idict.a.b.c=2优雅.

    总之,通过这次定制dict类,我发现Python面向对象所蕴含的强大力量.

    测试代码:

    if __name__=='__main__':
        dic={'one':1,
             'two':{
                 'four':4,
                 'five':{
                     'six':6,
                     'seven':7,}},
             'three':3}
    
        cdic=idict(dic,'default')
    
        print('-------------------the start state of cdic-------------------------------------------')
        print(cdic)
        print('-------------------query in two ways-------------------------------------------')
        print('cdic.two.five-->',cdic.two.five)
        print("cdic['two']['five']-->",cdic['two']['five'])
        print('cdic.two.five.six-->',cdic.two.five.six)
        print("cdic['two']['five']['six']-->",cdic['two']['five']['six'])
    
        print('-------------------update in two ways-------------------------------------------')
        cdic['two']['five']['six']=7
        print("cdic['two']['five']['six']=7")
        print("cdic.two.five.six-->",cdic.two.five.six )
    
        cdic.two.five.six=6
        print("cdic.two.five.six=6")
        print("cdic['two']['five']['six']-->",cdic['two']['five']['six'])
    
        print('-------------------add new one in two ways-------------------------------------------')
    
        cdic['two']['five']['eight']=8
        print("cdic['two']['five']['eight']=8")
        print("cdic.two.five.eight-->",cdic.two.five.eight)
    
        cdic.two.five.nine=9
        print("cdic.two.five.nine=9")
        print("cdic['two']['five']['nine']-->",cdic['two']['five']['nine'])
    
        print('-------------------query and set default in two ways-------------------------------------------')
        print("cdic['ten']-->",cdic['ten'])
        print("cdic.eleven-->",cdic.eleven)
        print("cdic.two.five.twelve-->",cdic.two.five.twelve)
        print("cdic['two']['five']['thirteen']-->",cdic['two']['five']['thirteen'])
    
        print('-------------------the final state of cdic-------------------------------------------')
        print('dict view--print(cdic):')
        print(cdic)
        print('
    attributes view--print(cdic.__dict__):')
        print(cdic.__dict__)
        print()
    
        def show(d): 
            for k,v in d.items():
                if isinstance(v,(str,int)):
                    yield '%s->%s'%(k,v)
                else:
                    for i in show(v):
                        yield '%s.%s'%(k,i)
    
    
        for i in show(cdic):
            print('cdic.'+i)

    测试结果:

    >>> 
    -------------------the start state of cdic-------------------------------------------
    {'two': {'five': {'seven': 7, 'six': 6}, 'four': 4}, 'one': 1, 'three': 3}
    -------------------query in two ways-------------------------------------------
    cdic.two.five--> {'seven': 7, 'six': 6}
    cdic['two']['five']--> {'seven': 7, 'six': 6}
    cdic.two.five.six--> 6
    cdic['two']['five']['six']--> 6
    -------------------update in two ways-------------------------------------------
    cdic['two']['five']['six']=7
    cdic.two.five.six--> 7
    cdic.two.five.six=6
    cdic['two']['five']['six']--> 6
    -------------------add new one in two ways-------------------------------------------
    cdic['two']['five']['eight']=8
    cdic.two.five.eight--> 8
    cdic.two.five.nine=9
    cdic['two']['five']['nine']--> 9
    -------------------query and set default in two ways-------------------------------------------
    cdic['ten']--> default
    cdic.eleven--> default
    cdic.two.five.twelve--> default
    cdic['two']['five']['thirteen']--> default
    -------------------the final state of cdic-------------------------------------------
    dict view--print(cdic):
    {'two': {'five': {'eight': 8, 'nine': 9, 'twelve': 'default', 'seven': 7, 'thirteen': 'default', 'six': 6}, 'four': 4}, 'ten': 'default', 'one': 1, 'eleven': 'default', 'three': 3}
    
    attributes view--print(cdic.__dict__):
    {'two': {'five': {'eight': 8, 'nine': 9, 'twelve': 'default', 'seven': 7, 'thirteen': 'default', 'six': 6}, 'four': 4}, 'ten': 'default', 'one': 1, 'eleven': 'default', 'three': 3}
    
    cdic.two.five.eight->8
    cdic.two.five.nine->9
    cdic.two.five.twelve->default
    cdic.two.five.seven->7
    cdic.two.five.thirteen->default
    cdic.two.five.six->6
    cdic.two.four->4
    cdic.ten->default
    cdic.one->1
    cdic.eleven->default
    cdic.three->3
  • 相关阅读:
    java 装饰者模式与继承的区别
    Java学习笔记-多线程-创建线程的方式
    java IO流复制图片
    如何解决代码重复问题
    jdbc的基本应用
    java多线程
    java中的集合和数组
    Collections的应用
    Map集合的应用及其遍历方式
    qweb
  • 原文地址:https://www.cnblogs.com/xiangnan/p/3428563.html
Copyright © 2011-2022 走看看