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('\nattributes 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

Python 通过继承实现标准对象的子类的更多相关文章

  1. sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO

    sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...

  2. python基础——继承和多态

    python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...

  3. Python进阶-继承中的MRO与super

    Python进阶-继承中的MRO与super 写在前面 如非特别说明,下文均基于Python3 摘要 本文讲述Python继承关系中如何通过super()调用"父类"方法,supe ...

  4. python基础——继承实现的原理

    python基础--继承实现的原理 1 继承顺序 class A(object): def test(self): print('from A') class B(A): def test(self) ...

  5. python基础——继承与派生、组合

    python基础--继承与派生 1 什么是继承: 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类成为基类或超累,新建的类成为派生类或子类 1.1 继承分为:单 ...

  6. python之继承、抽象类、新式类和经典类

    一.上节补充1.静态属性静态属性 : 类的属性,所有的对象共享这个变量 如果用对象名去修改类的静态属性:在对象的空间中又创建了一个属性,而不能修改类中属性的值 操作静态属性应该用类名来操作 例1:请你 ...

  7. python 面向对象 继承 派生 组合

    具体参考博客:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label12 一.面向对象 面向对象:对象与对象之间的相互交互,不可预 ...

  8. Python类继承(转发)

    目录 一.概述 二.类的继承 2.1 继承的定义 2.2 构造函数的继承 2.3 子类对父类方法的重写 三.类继承的事例 回到顶部 一.概述 面向对象编程 (OOP) 语言的一个主要功能就是“继承”. ...

  9. python中继承和多态

    继承和多态 继承 引入继承 我们有这样一个需求 模仿英雄联盟定义两个英雄类 1.英雄要有昵称.攻击力.生命值属性 2.实例化出两个英雄对象 3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判断为死 ...

随机推荐

  1. codevs3990:中国剩余定理2

    好久没做codevs啦 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cst ...

  2. Codeforces Round #411 (Div. 1) D. Expected diameter of a tree

    题目大意:给出一个森林,每次询问给出u,v,问从u所在连通块中随机选出一个点与v所在连通块中随机选出一个点相连,连出的树的直径期望(不是树输出-1).(n,q<=10^5) 解法:预处理出各连通 ...

  3. Codeforces Round #438 B. Race Against Time

    Description Have you ever tried to explain to the coordinator, why it is eight hours to the contest ...

  4. python常用命令(持续) | Commonly used Python command list (con't)

    ---------------------------------------------------------------------------------------------------- ...

  5. 用ECMAScript4 ( ActionScript3) 实现Unity的热更新 -- 操作符重载和隐式类型转换

    C#中,某些类型会定义隐式类型转换和操作符重载.Unity中,有些对象也定义了隐式类型转换和操作符重载.典型情况有:UnityEngine.Object.UnityEngine.Object的销毁是调 ...

  6. Unity3d 简单的小球沿贝塞尔曲线运动(适合场景漫游使用)

        简单的小球沿贝塞尔曲线运动,适合场景漫游使用 贝塞尔曲线:(贝塞尔曲线的基本想法部分摘自http://blog.csdn.net/u010019717/article/details/4768 ...

  7. WebDNN:Web浏览器上最快的DNN执行框架

    WebDNN:Web浏览器上最快的DNN执行框架 为什么需要WebDNN? 深层神经网络(DNN)在许多应用中受到越来越多的关注. 然而,它需要大量的计算资源,并且有许多巨大的过程来设置基于执行环境的 ...

  8. js黑魔法

    清空一个数组 一直以来,清空一个数组都是var i = [1,2,3]; i = [];,习惯成自然,被自己坑了. 举个例子 var i = [1,2,3]; var obj = {val: i}; ...

  9. jqGrid 使用心得

    参考: https://blog.csdn.net/u012411219/article/details/51315419 https://www.cnblogs.com/kissdodog/p/38 ...

  10. Hibernate 自动生产表

    hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. 今天就来演示一下Hibernate最初级的 ...