循序渐进PYTHON3(七) --1-- 面向对象
Python 面向对象
什么是面向对象编程?
面向对象编程是一种程序设计范式
对现实世界建立对象模型
把程序看作不同对象的相互调用
Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。下面我们将详细介绍Python的面向对象编程。
如果你以前没有接触过面向对象的编程语言,那你可能需要先了解一些面向对象语言的一些基本特征,在头脑里头形成一个基本的面向对象的概念,这样有助于你更容易的学习Python的面向对象编程。
接下来我们先来简单的了解下面向对象的一些基本特征。
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
12345678910111213
定义类并创建实例在Python中,类通过class关键字定义。以 Person 为例,定义一个Person类如下:classPerson():pass按照 Python 的编程习惯,类名以大写字母开头,紧接着是(object),表示该类是从哪个类继承下来的。类的继承将在后面的章节讲解,现在我们只需要简单地从object类继承。有了Person类的定义,就可以创建出具体的xiaoming、xiaohong等实例。创建实例使用 类名+(),类似函数调用的形式创建:xiaoming=Person()xiaohong=Person()注:python 2 创建类与python 3 不同
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
py 2.2 后继承 object 的目的是使这个类成为 new style class, 没有继承 object 的为传统 classic class,在py 2.7.11进行了测试 >>> class A(object):... pass... >>> print(type(A))<type 'type'>>>> class B():... pass... >>> print(type(B))<type 'classobj'># 可见2个type是不同的>>> print dir(A)['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']>>> print dir(B)['__doc__', '__module__']# 属性也是不一样的而py 3.5.2:class A(object): passprint(type(A))print(dir(A))class B(): passprint(type(B))print(dir(B))<class 'type'>['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']<class 'type'>['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__']说明 py 3.5 object 已经作为默认基类被继承了(跟 java 一样). |
- 字段:字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同。普通字段属于对象,静态字段属于类.
1234567891011
classProvince:# 静态字段country='中国'def__init__(self, name):# 普通字段self.name=name# 直接访问普通字段obj=Province('河北省')print(obj.name)# 直接访问静态字段print(Province.country)静态字段在内存中只保存一份,普通字段在每个对象中都要保存一份
- 方法:方法包括:普通方法、静态方法和类方法,三种方法在内存中都归属于类,区别在于调用方式不同。
普通方法:由对象调用;至少一个self参数;执行普通方法时,自动将调用该方法的对象赋值给self;
类方法:由类调用; 至少一个cls参数;执行类方法时,自动将调用该方法的类复制给cls;
静态方法:由类调用;无默认参数;
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/usr/bin/env python# Version = 3.5.2# __auth__ = '无名小妖'class Foo: def __init__(self, name): self.name = name def ord_func(self): """ 定义普通方法,至少有一个self参数 """ print('普通方法') @classmethod def class_func(cls): """ 定义类方法,至少有一个cls参数 """ print('类方法') @staticmethod def static_func(): """ 定义静态方法 ,无默认参数""" print('静态方法')# 调用普通方法f = Foo('那么')f.ord_func()# 调用类方法Foo.class_func()# 调用静态方法Foo.static_func() |
尽量不要用对象执行静态方法和类方法。
属性:Python中的属性其实是普通方法的变种。
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class Foo: def func(self): pass # 定义属性 @property def prop(self): print('xxx')# ############### 调用 ###############foo_obj = Foo()foo_obj.func()foo_obj.prop #调用属性 |
由属性的定义和调用要注意一下几点:
- 定义时,在普通方法的基础上添加 @property 装饰器;
- 定义时,属性仅有一个self参数
- 调用时,无需括号
方法:foo_obj.func()
属性:foo_obj.prop
注意:属性存在意义是:访问属性时可以制造出和访问字段完全相同的假象。
属性的定义有两种方式:
- 装饰器 即:在方法上应用装饰器
- 静态字段 即:在类中定义值为property对象的静态字段
装饰器方式:在类的普通方法上应用@property装饰器
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
#!/usr/bin/env python# Version = 3.5.2# __auth__ = '无名小妖'class Pager(): def __init__(self,all_count): self.all_count = all_count @property def all_pager(self): a1,a2 = divmod(self.all_count,10) if a2 == 0: x = a1 else: x = a1 + 1 return x @all_pager.setter def all_pager(self,value): self.all_count = value * 10 @all_pager.deleter def all_pager(self): print('deleter')p = Pager(101)print(p.all_pager)p.all_pager = 123print(p.all_pager)del p.all_pager |
输出结果:
|
1
2
3
|
11123deleter |
静态字段方式,创建值为property对象的静态字段
- 第一个参数是方法名,调用
对象.属性时自动触发执行方法 - 第二个参数是方法名,调用
对象.属性 = XXX时自动触发执行方法 - 第三个参数是方法名,调用
del 对象.属性时自动触发执行方法
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
class Foo: def get_bar(self): return 'xiaoyao1' # *必须两个参数 def set_bar(self, value): print('set value is ' + value) def del_bar(self): print('xiaoyao2') BAR = property(fget=get_bar, fset=set_bar, fdel=del_bar)obj = Foo()obj.BAR # 自动调用第一个参数中定义的方法:get_barx = obj.BARprint(x)obj.BAR = "alex" # 自动调用第二个参数中定义的方法:set_bar方法,并将“alex”当作参数传入del obj.BAR # 自动调用第三个参数中定义的方法:del_bar方法xiaoyao1set value is alexxiaoyao2 |
Python 三大特性:
封装
封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。
封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
__init__ 是封装必不可少的,看列子:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class Init(): def __init__(self,name,age,gender): self.Name = name self.Age = age self.Gender = genderobj1 = Init('xiao',15,'男')obj2 = Init('yao',16,'女')print(obj1.Name)print(obj2.Name) |
这样实现了数据封装
|
1
2
|
xiaoyao |
继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。
通过继承创建的新类称为“子类”或“派生类”。
被继承的类称为“基类”、“父类”或“超类”。
继承的过程,就是从一般到特殊的过程。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
在某些 OOP 语言中,一个子类可以继承多个基类。但是一般情况下,一个子类只能有一个基类,要实现多重继承,可以通过多级继承来实现。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class C1(): def c1(self): print('C1')class C2(C1): def c2(self): print('C2')class C3(): def c3(self): print('C3') def c1(self): print('C3')class C4(C2,C3): def c4(self): print('C4')obj = C4()obj.c1()obj1 = C3()obj1.c1() |
输出结果:
|
1
2
|
C1C3 |
可见,C4继承C2,C3,C2又继承C1,所以obj会有c1方法。
类的继承可以总结为:
1.左侧优先
|
1
|
class C4(C2,C3) 这里C2比C3优先 |
2.深度优先
上面例子C1和C3都有c1方法,但是最后C4继承的是C1的c1
3.有共同的父类,最后找父类
看图红色箭头表示继承关系,黑色箭头表示查找关系
图一: 图二:

浙公网安备 33010602011771号