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('\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 通过继承实现标准对象的子类的更多相关文章
- sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO
sqlalchemy mark-deleted 和 python 多继承下的方法解析顺序 MRO 今天在弄一个 sqlalchemy 的数据库基类的时候,遇到了跟多继承相关的一个小问题,因此顺便看了一 ...
- python基础——继承和多态
python基础——继承和多态 在OOP程序设计中,当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类 ...
- Python进阶-继承中的MRO与super
Python进阶-继承中的MRO与super 写在前面 如非特别说明,下文均基于Python3 摘要 本文讲述Python继承关系中如何通过super()调用"父类"方法,supe ...
- python基础——继承实现的原理
python基础--继承实现的原理 1 继承顺序 class A(object): def test(self): print('from A') class B(A): def test(self) ...
- python基础——继承与派生、组合
python基础--继承与派生 1 什么是继承: 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类成为基类或超累,新建的类成为派生类或子类 1.1 继承分为:单 ...
- python之继承、抽象类、新式类和经典类
一.上节补充1.静态属性静态属性 : 类的属性,所有的对象共享这个变量 如果用对象名去修改类的静态属性:在对象的空间中又创建了一个属性,而不能修改类中属性的值 操作静态属性应该用类名来操作 例1:请你 ...
- python 面向对象 继承 派生 组合
具体参考博客:http://www.cnblogs.com/linhaifeng/articles/6182264.html#_label12 一.面向对象 面向对象:对象与对象之间的相互交互,不可预 ...
- Python类继承(转发)
目录 一.概述 二.类的继承 2.1 继承的定义 2.2 构造函数的继承 2.3 子类对父类方法的重写 三.类继承的事例 回到顶部 一.概述 面向对象编程 (OOP) 语言的一个主要功能就是“继承”. ...
- python中继承和多态
继承和多态 继承 引入继承 我们有这样一个需求 模仿英雄联盟定义两个英雄类 1.英雄要有昵称.攻击力.生命值属性 2.实例化出两个英雄对象 3.英雄之间可以互殴,被殴打的一方掉血,血量小于0则判断为死 ...
随机推荐
- java中的多态案例
多态性实际上有两种: 1.方法的多态性: 1.1方法重载:相同的方法名,会根据传入的参数的类型和个数不同执行不同的方法 1.2方法覆写:同一个方法名称,会根据子类的不同实现不同的功能 2.对象的多态性 ...
- PHP面向对象-看父类调用子类方法
大部分面向对象编程语言中,父类是不允许调用子类的方法的,但是PHP中可以 1.父类调用子类方法示例 class A { public function testa() { $this->test ...
- [Codeforces 946G]Almost Increasing Array
Description 题库链接 给你一个长度为 \(n\) 的序列 \(A\) .现在准许你删除任意一个数,删除之后需要修改最小的次数使序列单调递增.问最小次数. \(1\leq n\leq 200 ...
- P2515 [HAOI2010]软件安装
树形背包 #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> ...
- [BZOJ]4199: [Noi2015]品酒大会(后缀数组+笛卡尔树)
Time Limit: 10 Sec Memory Limit: 512 MB Description Input Output Sample Input 10 ponoiiipoi 2 1 4 7 ...
- 「LibreOJ NOIP Round #1」旅游路线
Description T 城是一个旅游城市,具有 nnn 个景点和 mmm 条道路,所有景点编号为 1,2,...,n1,2,...,n1,2,...,n.每条道路连接这 nnn 个景区中的某两个景 ...
- HDU2222 自动机(学习中)
题目大意: 给你很多个单词,然后给你一篇文章,问给出的单词在文章中出现的次数. 解题思路: AC自动机入门题.需要注意的就是可能有重复单词 代码如下: #include<iostream> ...
- 2015 多校联赛 ——HDU5402(模拟)
For each test case, in the first line, you should print the maximum sum. In the next line you should ...
- bzoj3126[Usaco2013 Open]Photo 单调队列优化dp
3126: [Usaco2013 Open]Photo Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 374 Solved: 188[Submit] ...
- jmeter正则表达式书写
在测试过程中,经常会有以下几种场景,如A接口的返回值,用于B接口中,而且A登陆的账户,每次登陆,这个sid值还是变化的.那么在实际工作中,如何才能A接口中提取参数到B接口中?接下来我们就可以用正则表达 ...