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. kafka知识体系

    最近一直在整理kafka相关资料,以构建自己的知识体系. 主要分为五大方面: Kafka设计与原理分析 Kafka配置分析 Kafka运维手册 Kafka编程开发 kafka源码分析

  2. [原创]手把手教你写网络爬虫(4):Scrapy入门

    手把手教你写网络爬虫(4) 作者:拓海 摘要:从零开始写爬虫,初学者的速成指南! 封面: 上期我们理性的分析了为什么要学习Scrapy,理由只有一个,那就是免费,一分钱都不用花! 咦?怎么有人扔西红柿 ...

  3. [LeetCode] Lonely Pixel II 孤独的像素之二

    Given a picture consisting of black and white pixels, and a positive integer N, find the number of b ...

  4. electron通讯

    Electron桌面应用实现两个窗口(渲染进程)之间的通讯,传输数据: 方法1:在两个网页(渲染进程)间共享数据最简单的方法是使用浏览器中已经实现的 HTML5 API. 其中比较好的方案是用 Sto ...

  5. POJ2449 Remmarguts' Date

    "Good man never makes girls wait or breaks an appointment!" said the mandarin duck father. ...

  6. [JSOI2007]字符加密

    题目描述 喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法. 例如‘JSOI07’,可以读作 ...

  7. C++Primer学习——动态内存

    静态内存:用来保存static 栈内存:保存非static 智能指针: shared_ptr:允许多个指针指向一个对象 unique_ptr:独占所指对象 weak_ptr:一种弱引用,指向share ...

  8. CodeForces346 C. Number Transformation II

    C. Number Transformation II time limit per test 1 second memory limit per test 256 megabytes input s ...

  9. hdu 5476 (计算几何)

    题意:求三角形内∠MPB+∠APC=∠MPC+∠APB的轨迹长度- - 1.基于M的中垂线       2.三角形内的圆弧(比赛只有看自己能否猜中),ps.以下是别人家的证明 #include < ...

  10. 【网络流问题·我就想建好模】

    ·为了有助于你读后文,在写题前先列出一些大米饼的代码习惯: 一个提醒:所有的ADD函数无特殊说明均如图:(没有w就直接跳过) 以及: go(i,a,b)=====for(int i=a;i<=b ...