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. ASP.NET Core + Docker +Jenkins 实现持续集成

    1.新建一个ASP.NET Core MVC应用程序: 2.将其上传到git: 3.建立Jenkins任务 (1)选择"新建任务",输入任务名称,选择"自由风格项目&qu ...

  2. ubuntu14.4 分辨率偏低

    最近出了 14.04 LTS,就想安装上玩一玩.还是用 easybcd 从 windows硬盘安装.装完之后,显示效果不好于是做了如下处理: 1. 按下windows键,搜索 "附加驱动&q ...

  3. [LeetCode] Design Compressed String Iterator 设计压缩字符串的迭代器

    Design and implement a data structure for a compressed string iterator. It should support the follow ...

  4. jstl标签库示例二

    package app05b;import java.io.IOException;import java.util.HashMap;import java.util.Map;import javax ...

  5. ●洛谷P2664 树上游戏

    题链: https://www.luogu.org/problemnew/show/P2664题解: 扫描线,线段树维护区间覆盖 https://www.luogu.org/blog/ZJ75211/ ...

  6. ●POJ 1873 The Fortified Forest

    题链: http://poj.org/problem?id=1873 题解: 计算几何,凸包 枚举被砍的树的集合.求出剩下点的凸包.然后判断即可. 代码: #include<cmath> ...

  7. [USACO Jan09] 安全路径

    Gremlins最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的 地是牛棚_i).每一个gremlin只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经.所以它 们在 ...

  8. TOJ 数据结构实验--静态顺序栈

    描述 创建一个顺序栈(静态),栈大小为5.能够完成栈的初始化.入栈.出栈.获取栈顶元素.销毁栈等操作. 顺序栈类型定义如下: typedef struct {  int data[Max];    i ...

  9. ORACLE 触发器 基础

    --触发器--语法 CREATE OR REPLACE TRIGGER TRIGGER_NAME AFTER|BEFORE|INSTEAD OF [INSERT][OR UPDATE [OF COLU ...

  10. Windows系统提供什么样的接口,Unix、Linux系统的用户接口是什么?

    Windows:图形化用户界面 Unix.Linux:独立的环境.