抽象指对现实世界问题和实体的本质表现,行为和特征建模,建立一个相关的子集,可以用于 绘程序结构,从而实现这种模型。抽象不仅包括这种模型的数据属性,还定义了这些数据的接口。
对某种抽象的实现就是对此数据及与之相关接口的现实化(realization)。现实化这个过程对于客户 程序应当是透明而且无关的。
封装/接口
封装描述了对数据/信息进行隐藏的观念,它对数据属性提供接口和访问函数。通过任何客户端直接对数据的访问,无视接口,与封装性都是背道而驰的,除非程序员允许这些操作。作为实现的 一部分,客户端根本就不需要知道在封装之后,数据属性是如何组织的。在Python中,所有的类属性都是公开的,但名字可能被“混淆”了,以阻止未经授权的访问,但仅此而已,再没有其他预防措施了。这就需要在设计时,对数据提供相应的接口,以免客户程序通过不规范的操作来存取封装的数据属性。
注意:封装绝不是等于“把不想让别人看到、以后可能修改的东西用private隐藏起来”
真正的封装是,经过深入的思考,做出良好的抽象,给出“完整且最小”的接口,并使得内部细节可以对外透明
(注意:对外透明的意思是,外部调用者可以顺利的得到自己想要的任何功能,完全意识不到内部细节的存在)
合成
合成扩充了对类的 述,使得多个不同的类合成为一个大的类,来解决现实问题。合成 述了 一个异常复杂的系统,比如一个类由其它类组成,更小的组件也可能是其它的类,数据属性及行为, 所有这些合在一起,彼此是“有一个”的关系。
派生/继承/继承结构
派生描述了子类衍生出新的特性,新类保留已存类类型中所有需要的数据和行为,但允许修改或者其它的自定义操作,都不会修改原类的定义。
继承描述了子类属性从祖先类继承这样一种方式
继承结构表示多“代”派生,可以述成一个“族谱”,连续的子类,与祖先类都有关系。
泛化/特化
基于继承
泛化表示所有子类与其父类及祖先类有一样的特点。
特化描述所有子类的自定义,也就是,什么属性让它与其祖先类不同。
多态与多态性
多态指的是同一种事物的多种状态:水这种事物有多种不同的状态:冰,水蒸气
多态性的概念指出了对象如何通过他们共同的属性和动作来操作及访问,而不需考虑他们具体的类。
冰,水蒸气,都继承于水,它们都有一个同名的方法就是变成云,但是冰.变云(),与水蒸气.变云()是截然不同的过程,虽然调用的方法都一样
自省/反射
自省也称作反射,这个性质展示了某对象是如何在运行期取得自身信息的。如果传一个对象给你,你可以查出它有什么能力,这是一项强大的特性。如果Python不支持某种形式的自省功能,dir和type内建函数,将很难正常工作。还有那些特殊属性,像__dict__,__name__及__doc__
四、类
类有两种作用:属性引用和实例化
属性引用(类名.属性)
classGaren:
camp='Demacia'
defattack(self):print('attack')
#引用类的特征(类的变量)和技能(类的函数)
print(Garen.camp)print(Garen.attack)
Garen.attack(1231231)
实例化(__init__与self)
x=int(10)print(x)
obj=Garen() #实例化
print(obj)
1 classGaren:2 camp='Demacia'
3
4 def __init__(self,nickname):5 self.nick=nickname #g1.nick='草丛伦'
6 defattack(self,enemy):7 #print('---------->',self.nick) #g1.nick
8 print('%s attack %s' %(self.nick,enemy))9
10
11 g1=Garen('草丛伦') #Garen.__init___(g1,'草丛伦')
12 g2=Garen('猥琐轮')13 print(g1.nick)14 g1.attack('alex')15
16 print(g1.nick)17 print(g1.camp)18 print(g1.attack)19 print(Garen.attack)20
21 Garen.attack() #调用的是函数
22 g1.attack() #self=g1
23 Garen.attack(g1)24
25 print(g2.nick)26 print(g2.camp)27
28 如何使用实例
如何使用实例
1 #总结:
2 #类:一:实例化,二:引用名字(类名.变量名,类名.函数名)
3 #实例:引用名字(实例名.类的变量,实例名.绑定方法,实例名.实例自己的变量名)
4
5 classGaren:6 camp='Demacia'
7
8 def __init__(self,nickname):9 self.nick=nickname #g1.nick='草丛伦'
10 defattack(self,enemy):11 #print('---------->',self.nick) #g1.nick
12 print('%s attack %s' %(self.nick,enemy))13
14 #print(Garen.camp) #查
15 #Garen.camp='aaaaaa' #改
16 #print(Garen.camp)
17 #18 ## del Garen.camp #删除
19 ## print(Garen.camp)
20 #21 #Garen.x=1
22 #print(Garen.x)
23
24
25 g1=Garen('alex')26 #print(g1.nick)
27 #g1.nick='asb'
28 #print(g1.nick)
29 #del g1.nick
30 #print(g1.nick)
31
32 #g1.sex='female'
33 #print(g1.sex)
34
35 总结
总结
类特殊成员:
1. __doc__
表示类的描述信息
classFoo:"""描述类信息,这是用于看片的神奇"""
deffunc(self):pass
print Foo.__doc__
#输出:类的描述信息
View Code
2. __module__ 和 __class__
__module__ 表示当前操作的对象在那个模块
__class__ 表示当前操作的对象的类是什么
#!/usr/bin/env python#-*- coding:utf-8 -*-
classC:def __init__(self):
self.name= 'wupeiqi'lib/aa.py
View Code
from lib.aa importC
obj=C()print obj.__module__ #输出 lib.aa,即:输出模块
print obj.__class__ #输出 lib.aa.C,即:输出类
View Code
3. __init__
构造方法,通过类创建对象时,自动触发执行。
classFoo:def __init__(self, name):
self.name=name
self.age= 18obj= Foo('wupeiqi') #自动执行类中的 __init__ 方法
View Code
4. __del__
析构方法,当对象在内存中被释放时,自动触发执行。
注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。
classFoo:def __del__(self):pass
5. __call__
对象后面加括号,触发执行。
注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()
classFoo:def __init__(self):pass
def __call__(self, *args, **kwargs):print '__call__'obj= Foo() #执行 __init__
obj() #执行 __call__
View Code
6. __dict__
类或对象中的所有成员
上文中我们知道:类的普通字段属于对象;类中的静态字段和方法等属于类,即:
classProvince:
country= 'China'
def __init__(self, name, count):
self.name=name
self.count=countdef func(self, *args, **kwargs):print 'func'
#获取类的成员,即:静态字段、方法、
print Province.__dict__
#输出:{'country': 'China', '__module__': '__main__', 'func': , '__init__': , '__doc__': None}
obj1= Province('HeBei',10000)print obj1.__dict__
#获取 对象obj1 的成员#输出:{'count': 10000, 'name': 'HeBei'}
obj2= Province('HeNan', 3888)print obj2.__dict__
#获取 对象obj1 的成员#输出:{'count': 3888, 'name': 'HeNan'}
View Code
7. __str__
如果一个类中定义了__str__方法,那么在打印 对象 时,默认输出该方法的返回值。
classFoo:def __str__(self):return 'wupeiqi'obj=Foo()printobj#输出:wupeiqi
View Code
8、__getitem__、__setitem__、__delitem__
用于索引操作,如字典。以上分别表示获取、设置、删除数据
#!/usr/bin/env python#-*- coding:utf-8 -*-
classFoo(object):def __getitem__(self, key):print '__getitem__',keydef __setitem__(self, key, value):print '__setitem__',key,valuedef __delitem__(self, key):print '__delitem__',key
obj=Foo()
result= obj['k1'] #自动触发执行 __getitem__
obj['k2'] = 'wupeiqi' #自动触发执行 __setitem__
del obj['k1'] #自动触发执行 __delitem__
View Code
9、__getslice__、__setslice__、__delslice__
该三个方法用于分片操作,如:列表
#!/usr/bin/env python#-*- coding:utf-8 -*-
classFoo(object):def __getslice__(self, i, j):print '__getslice__',i,jdef __setslice__(self, i, j, sequence):print '__setslice__',i,jdef __delslice__(self, i, j):print '__delslice__',i,j
obj=Foo()
obj[-1:1] #自动触发执行 __getslice__
obj[0:1] = [11,22,33,44] #自动触发执行 __setslice__
del obj[0:2] #自动触发执行 __delslice__
View Code
10. __iter__
用于迭代器,之所以列表、字典、元组可以进行for循环,是因为类型内部定义了 __iter__
classFoo(object):passobj=Foo()for i inobj:printi#报错:TypeError: 'Foo' object is not iterable
第一步
第一步
第一步
#!/usr/bin/env python#-*- coding:utf-8 -*-
classFoo(object):def __iter__(self):passobj=Foo()for i inobj:printi#报错:TypeError: iter() returned non-iterator of type 'NoneType'
第二步
第二步
第二步
#!/usr/bin/env python#-*- coding:utf-8 -*-
classFoo(object):def __init__(self, sq):
self.sq=sqdef __iter__(self):returniter(self.sq)
obj= Foo([11,22,33,44])for i inobj:printi
第三步
第三步
第三步
以上步骤可以看出,for循环迭代的其实是 iter([11,22,33,44]) ,所以执行流程可以变更为:
#!/usr/bin/env python#-*- coding:utf-8 -*-
obj= iter([11,22,33,44])for i inobj:print i
View Code
#!/usr/bin/env python#-*- coding:utf-8 -*-
obj= iter([11,22,33,44])whileTrue:
val=obj.next()printval
For循环语法内部
For循环语法内部
for循环语法内部
11. __new__ 和 __metaclass__
阅读以下代码:
classFoo(object):def __init__(self):passobj= Foo() #obj是通过Foo类实例化的对象
View Code
上述代码中,obj 是通过 Foo 类实例化的对象,其实,不仅 obj 是一个对象,Foo类本身也是一个对象,因为在Python中一切事物都是对象。
如果按照一切事物都是对象的理论:obj对象是通过执行Foo类的构造方法创建,那么Foo类对象应该也是通过执行某个类的 构造方法 创建。
print type(obj) #输出: 表示,obj 对象由Foo类创建
print type(Foo) #输出: 表示,Foo类对象由 type 类创建
View Code
所以,obj对象是Foo类的一个实例,Foo类对象是 type 类的一个实例,即:Foo类对象 是通过type类的构造方法创建。
那么,创建类就可以有两种方式:
a). 普通方式
classFoo(object):deffunc(self):print 'hello wupeiqi'
View Code
b).特殊方式(type类的构造函数)
deffunc(self):print 'hello wupeiqi'Foo= type('Foo',(object,), {'func': func})#type第一个参数:类名#type第二个参数:当前类的基类#type第三个参数:类的成员
View Code
==》 类 是由 type 类实例化产生
那么问题来了,类默认是由 type 类实例化产生,type类中如何实现的创建类?类又是如何创建对象?
答:类中有一个属性 __metaclass__,其用来表示该类由 谁 来实例化创建,所以,我们可以为 __metaclass__ 设置一个type类的派生类,从而查看 类 创建的过程。
classMyType(type):def __init__(self, what, bases=None, dict=None):
super(MyType, self).__init__(what, bases, dict)def __call__(self, *args, **kwargs):
obj= self.__new__(self, *args, **kwargs)
self.__init__(obj)classFoo(object):__metaclass__ =MyTypedef __init__(self, name):
self.name=namedef __new__(cls, *args, **kwargs):return object.__new__(cls, *args, **kwargs)#第一阶段:解释器从上到下执行代码创建Foo类#第二阶段:通过Foo类创建obj对象
obj = Foo()
View Code
五、对象
面向过程的程序设计的核心是过程,过程即解决问题的步骤,面向过程的设计就好比精心设计好一条流水线,考虑周全什么时候处理什么东西。
优点是:极大的降低了程序的复杂度
缺点是:一套流水线或者流程就是用来解决一个问题,生产汽水的流水线无法生产汽车,即便是能,也得是大改,改一个组件,牵一发而动全身。
应用场景:一旦完成基本很少改变的场景,著名的例子有Linux內核,git,以及Apache HTTP Server等。
面向对象的程序设计的核心是对象,要理解对象为何物,必须把自己当成上帝,上帝眼里世间存在的万物皆为对象,不存在的也可以创造出来。面向对象的程序设计好比如来设计西游记,如来要解决的问题是把经书传给东土大唐,如来想了想解决这个问题需要四个人:唐僧,沙和尚,猪八戒,孙悟空,每个人都有各自的特征和技能(这就是对象的概念,特征和技能分别对应对象的数据属性和方法属性),然而这并不好玩,于是如来又安排了一群妖魔鬼怪,为了防止师徒四人在取经路上被搞死,又安排了一群神仙保驾护航,这些都是对象。然后取经开始,师徒四人与妖魔鬼怪神仙交互着直到最后取得真经。如来根本不会管师徒四人按照什么流程去取。♥♥♥♥♥。◕‿◕。♥♥♥♥♥ (举例很形象,看懂你就明白了)