1 面向对象的介绍
1.1 函数式编程和面向对象的对比
1.1.1 第一轮对比
1.1.1.1 函数式编程
1 def email(em,text): 2 """ 3 发送邮件 4 :return: 5 """ 6 print(em,text) 7 8 def msg(tel,text): 9 """ 10 发送短信 11 :return: 12 """ 13 print(tel,text) 14 15 def wechat(num,text): 16 """ 17 发送微信 18 :return: 19 """ 20 print(num,text) 21 22 23 # 编写功能:假设用户购买课程,然后给alex发送提醒; 24 if 1==1: 25 msg('188888888','张进购买了一个学位课') 26 email('alex@sb.com','张进购买了一个学位课') 27 wechat('xxxx','张进购买了一个学位课')
1.1.1.2 面向对象编程
1 class Message: 2 def email(self, em, text): 3 """ 4 发送邮件 5 :return: 6 """ 7 print(em,text) 8 9 def msg(self, tel, text): 10 """ 11 发送短信 12 :return: 13 """ 14 print(tel,text) 15 16 def wechat(self, num, text): 17 """ 18 发送微信 19 :return: 20 """ 21 print(num,text) 22 23 24 # 编写功能:假设用户购买课程,然后给alex发送提醒; 25 if 1==1: 26 obj = Message() 27 obj.email('alex@sb.com', '张进购买了一个学位课') 28 obj.msg('188888888','张进购买了一个学位课') 29 obj.wechat('xxxx','张进购买了一个学位课')
1.1.1.3 第一轮对比:
函数: 定义简单/调用简单
面向对象: 定义复杂/调用复杂 好处:归类,将某些类似的函数写在一起
1.1.1.4 第一轮的总结:
1. 函数式编程可能会比面向对象好.
2. Python中支持两种编程方式.
3. 面向对象方式格式:
|
定义: class 类名: - 定义了一个类 def 函数名(self): - 在类中编写了一个"方法" pass 调用: x1 = 类名() - 创建了一个对象/实例化一个对象 x1.函数名() - 通过对象调用其中一个方法. 注意:这里的self参数是把实例化后的对象名传过去,因此self是xx类的xx对象 |
|
4. 示例:
1 class Account: 2 def login(self): 3 user = input('请输入用户名:') 4 pwd = input('请输入密码:') 5 if user == 'alex' and pwd == 'sb': 6 print('登录成功') 7 else: 8 print('登录失败') 9 10 obj = Account() 11 obj.login() |
1.1.2 第二轮对比
"""
完成以下功能:
老狗/20岁/男/上山去砍柴
老狗/20岁/男/开车去东北
老狗/20岁/男/喜欢大宝剑
"""
1.1.2.1 函数式编程:
1 def kc(name,age,gender): 2 3 data = "%s,性别%s,今年%s岁,喜欢上山砍柴" %(name,gender,age) 4 5 print(data) 6 7 8 9 def db(name,age,gender): 10 11 data = "%s,性别%s,今年%s岁,喜欢开车去东北" %(name,gender,age) 12 13 print(data) 14 15 16 17 def bj(name,age,gender): 18 19 data = "%s,性别%s,今年%s岁,喜欢大宝剑" %(name,gender,age) 20 21 print(data) 22 23 24 25 kc('老狗',20,'男') 26 27 kc('老狗',20,'男') 28 29 db('老狗',20,'男') 30 31 bj('老狗',20,'男') |
1.1.2.2 面向对象编程:
1 class LaoGou: 2 3 def __init__(self,name,age,gender): # 特殊的方法,如果 类名() ,则该方法会被自动执行 (构造方法) 4 5 self.n1 = name 6 7 self.n2 = age 8 9 self.n3 = gender 10 11 def kc(self): 12 13 data = "%s,性别%s,今年%s岁,喜欢上山砍柴" %(self.n1,self.n3,self.n2) 14 15 print(data) 16 17 def db(self): 18 19 data = "%s,性别%s,今年%s岁,喜欢开车去东北" %(self.n1,self.n3,self.n2) 20 21 print(data) 22 23 def bj(self): 24 25 data = "%s,性别%s,今年%s岁,喜欢大宝剑" %(self.n1,self.n3,self.n2) 26 27 print(data) 28 29 obj = LaoGou('老狗',20,'男') 30 31 obj.kc() 32 33 obj.db() 34 35 obj.bj() |
1.1.2.3 第二轮对比(构造方法,在实例化的时候就已经自动运行类里的__init__()了)
|
构造方法 示例一: class Foo: def __init__(self,name): 构造方法,目的进行数据初始化. self.name = name self.age = 18 obj = Foo('侯明魏') 通过构造方法,可以将数据进行打包,以后使用时,去其中获取即可. 示例二: class Bar: pass obj = Bar() |
1.1.2.4 构造方法的应用
1.1.2.4.1 将数据封装到对象中,以供自己在方法中调用
1 class FileHandler: 2 3 def __init__(self,file_path): 4 5 self.file_path = file_path 6 7 self.f = open(self.file_path, 'rb') 8 9 def read_first(self): 10 11 pass 12 13 def read_last(self): 14 15 pass 16 17 def read_second(self): 18 19 pass 20 21 22 23 obj = FileHandler('C:/xx/xx.log') 24 25 obj.read_first() 26 27 obj.read_last() 28 29 obj.read_second() 30 31 obj.f.close()
把数据封装在self也就是obj对象中,调用方法就会用到self |
1.1.2.4.2 将数据封装到对象中,以供其他函数调用
1 def new_func(arg): 2 3 arg.k1 4 5 arg.k2 6 7 arg.k6 8 9 10 11 class Foo: 12 13 def __init__(self,k1,k2,k6): 14 15 self.k1 = k1 16 17 self.k2 = k2 18 19 self.k6 = k6 20 21 obj = Foo(111,22,333) 22 23 new_func(obj) 数据封装在对象obj里,然后可以参数形式传给其他函数,这样函数使用参数时就会带哦用参数。 |
|
练习: 信息管理系统 1. 用户登录 2. 显示当前用户信息 3. 查看当前用户所有的账单 4. 购买姑娘形状的抱枕
1 class UserInfo: 2 3 def __init__(self): 4 5 self.name = None 6 7 def info(self): 8 9 print('当前用户名称:%s' %(self.name,)) 10 11 def account(self): 12 13 print('当前用户%s的账单是:....' %(self.name,)) 14 15 def shopping(self): 16 17 print('%s购买了一个人形抱枕' %(self.name,)) 18 19 def login(self): 20 21 user = input('请输入用户名:') 22 23 pwd = input('请输入密码:') 24 25 if pwd == 'sb': 26 27 self.name = user #此时对象的name有东西了 28 29 while True: 30 31 print(""" 32 33 1. 查看用户信息 34 35 2. 查看用户账单 36 37 3. 购买抱枕 38 39 """) 40 41 num = int(input('请输入选择的序号:')) 42 43 if num == 1: 44 45 self.info() 46 47 elif num ==2: 48 49 self.account() 50 51 elif num == 3: 52 53 self.shopping() 54 55 else: 56 57 print('序号不存在,请重新输入') 58 59 else: 60 61 print('登录失败') 62 63 obj = UserInfo() 64 65 obj.login() |
1.1.1 第三轮
1 users = ['梁慧','朱奎峰','刘炳旭'...] # list() 2 # 完全可以实现 3 4 users = [ 5 6 {'name':'梁慧','age':18}, # 全栈15期%s,年龄:%s 7 8 {'name':'朱奎峰','age':18}, 9 10 {'name':'刘炳旭','age':18}, 11 12 ] # list() 13 14 15 for item in users: 16 17 temp = "全栈15期%s,年龄:%s " (item['name'],item['age']) 18 19 print(temp) 20 21 22 23 24 # 代码拆分,使得业务逻辑代码更加简洁 25 26 27 class Person(object): 28 29 def __init__(self,name,age): 30 31 self.name = name 32 33 self.age = age 34 35 36 37 def message(self): 38 39 return "全栈15期%s,年龄:%s " (self.name,self.age) 40 41 42 43 users = [ Person('梁慧',18), Person('朱奎峰',18), Person('刘炳旭',18) ] 44 45 46 47 for obj in users: 48 49 print(obj.message()) |
2 面向对象代码如何编写
2.1 规则:
|
class Foo: 定义类 def __init__(self,name): 构造方法 self.name = name def detail(self,msg): print(self.name,msg) obj = Foo() 类的实例化----》对象 obj.detail() 对象调用类里的方法 |
2.2 什么时候写?如何写?
2.2.1 方式一:归类+提取公共值
2.2.1.1 归类
1 class File: 2 3 def file_read(self,file_path): 4 5 pass 6 7 def file_update(self,file_path): 8 9 pass 10 11 def file_delete(self,file_path): 12 13 pass 14 15 def file_add(self,file_path): 16 17 pass 18 19 class Excel: 20 21 def excel_read(self,file_path): 22 23 pass 24 25 def excel_update(self,file_path): 26 27 pass 28 29 def excel_delete(self,file_path): 30 31 pass 32 33 def excel_add(self,file_path): 34 35 pass |
2.2.1.2 提取公共值
1 class File: 2 3 def __init__(self,file_path): 4 5 self.file_path = file_path 6 7 def file_read(self): 8 9 pass 10 11 def file_update(self): 12 13 pass 14 15 def file_delete(self): 16 17 pass 18 19 def file_add(self): 20 21 pass 22 23 class Excel: 24 25 def __init__(self,file_path): 26 27 self.file_path = file_path 28 29 def excel_read(self): 30 31 pass 32 33 def excel_update(self): 34 35 pass 36 37 def excel_delete(self): 38 39 pass 40 41 def excel_add(self): 42 43 pass |
2.2.2 方式二:在指定类中编写和当前类相关的所有代码 + 提取公共值
1 class Message: 2 3 def email(self): 4 5 pass 6 7 class Person: 8 9 def __init__(self,na, gen, age, fig) 10 11 self.name = na 12 13 self.gender = gen 14 15 self.age = age 16 17 self.fight =fig 18 19 def grassland(self): 20 21 self.fight = self.fight - 10 22 23 def practice(self): 24 25 self.fight = self.fight + 90 26 27 def incest(self): 28 29 self.fight = self.fight - 666 30 31 cang = Person('苍井井', '女', 18, 1000) # 创建苍井井角色 32 33 dong = Person('东尼木木', '男', 20, 1800) # 创建东尼木木角色 34 35 bo = Person('波多多', '女', 19, 2500) # 创建波多多角色 36 37 dong.grassland() |
3 面向对象的三大特性
3.1 封装
3.1.1 将相关功能封装到一个类中:
|
class Message: def email(self):pass def msg(self):pass def wechat(self):pass |
3.1.2 将数据封装到一个对象中:
|
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender obj = Person('孙福来',18,'女') |
class Person: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender obj = Person('孙福来',18,'女') ------------- obj.xxxx=123 #在类的外面用对象的方式封装了一个变量放到类里
3.2 继承->复用
类自动继承object类
3.2.1 为何会有继承?
提高代码的重用性
3.2.2 单继承(基本使用)
1 class Base: #父类,基类 2 3 def f2(self): 4 5 print('f2') 6 7 class Foo(Base): # 子类,派生类 8 9 def f1(self): 10 11 print('f1') 12 13 obj = Foo() 14 15 obj.f2() 注意:obj 是 Foo的对象,调用时,首先到Foo类里,obj把自己作为参数传给self,self就是obj.此时如果Foo类里找不到,在去Foo类的父类里面找,记住此时self依旧是Foo类 原则:现在自己类中找,么有就去父类 |
3.2.3 多继承
Java/c#/php等语言没有,子类可以继承多个父类.
原则:(先找左父类/再找右父类)
1 class Base1: 2 3 def show(self): 4 5 print('Base1.show') 6 7 class Base2: 8 9 def show(self): 10 11 print('Base2.show') 12 13 class Foo(Base1,Base2): 14 15 pass 16 17 obj = Foo() 18 19 obj.show() |
练习:
|
1. 多继承先找左边 2. self到底是谁,self是那个类的对象,那么就从该类开始找(自己没有就找父类)
1 class Base1: 2 3 def f1(self): 4 5 print('base1.1') 6 7 def f2(self): 8 9 print('base1.f2') 10 11 class Base2: 12 13 def f1(self): 14 15 print('base2.f1') 16 17 def f2(self): 18 19 print('base2.f2') 20 21 def f3(self): 22 23 print('base2.f3') 24 25 self.f1() 26 27 class Foo(Base1,Base2): 28 29 def f0(self): 30 31 print('foo.f0') 32 33 self.f3() 34 35 obj = Foo() 36 37 obj.f0() 38 39 分析:1:obj为Foo类的对象,首先必须明确这一点。 5:先去Foo类里面寻找f1()----》按前面的顺序来 |
3.2.4 多继承方法顺序
3.2.4.1 先找左后找右
3.2.4.2 经典类&&新式类
Py2:(python2.3之后出现c3算法)
经典类
新式类:如果自己或者自己的前辈只要有人继承object,那么此类就是新式类
Py3:新式类
3.2.4.3 经典类查找继承顺序的方法
一条道走到黑(深度优先)(提到深度优先,想到广度优先,所谓广度优先,就是一层一层)

如上图,黑色是继承关系;绿色是查找顺序
3.2.4.4 新式类查找继承顺序的方法
新式类,C3算法实现(python2.3更新时c3算法)
3.2.4.4.1 先设定几个定义:
- 表头:
列表的第一个元素 - 表尾:
列表中表头以外的元素集合(可以为空) - 示例
列表:[A, B, C]
表头是A,表尾是B和C
3.2.4.4.2 c3算法的规则和案例
规则
获取第一个表头 和 其他表尾进行比较
不存在则拿走。
如果存在,则放弃,然后获取第二个表的表头再次和其他表的表尾进行比较。

案例:
以下图为例,利用c3算法计算继承顺序

Foo +Merg [E] + Merg [H]
Merg [E]=[D,object]+[C,B,A,object]
|
(1)左边的表头D拿出来,与各个列表的表尾比较发现不在表尾,拿出此时顺序是E,D (2)[object]+[C,B,A,object],拿出左边列表的表头与各个列表的表尾比较发现在其他表。然后左边的列表并不是最后一个,跳过这个左边的列表,下次比较的是下一个列表的表头 (3)[C,B,A,object]拿出表头C,与各个列表的表尾比较,发现不再所有列表表尾,拿出来,此时继承顺序是E,D,C;继续跳到第一个列表,第一个列表object在其他列表中表尾中有,在跳到下一个表的 (4)[B,A,object] 拿出表头B,与各个列表的表尾比较,发现不再所有列表表尾,拿出来,此时继承顺序是E,D,C,B;继续跳到第一个列表,第一个列表object在其他列表中表尾中有,在跳到下一个表的 (5) [A,object] 拿出表头A,与各个列表的表尾比较,发现不再所有列表表尾,拿出来,此时继承顺序是E,D,C,B,A;继续跳到第一个列表,第一个列表object在其他列表中表尾中有,在跳到下一个表的;此时就只剩下[object]+ [object] (6)[object]+ [object],----》object,最后继承顺序是E,D,C,B,A,object 注意:每次在第一个列表与其他列表表尾比较时,,这个数据不动,发现有的话,跳到下一个列表的表头在比较,直到能比较拿出来为止,注意,比较完成后要再次跳到第一个列表 |
Merg [H]= [C,B,A,object]+ [G,F,object]
[H,C,B,A,G,F,object]
Foo +Merg [E] + Merg [H]
= Foo + [E,D,C,B,A,object]+ [H,C,B,A,G,F,object]
=[ Foo,E,D,H,C,B,A,G,F,object]
检验方法:
1 class A: 2 pass 3 class B(A): 4 pass 5 class C(B): 6 pass 7 class D: 8 pass 9 class E(D,C): 10 pass 11 class F: 12 pass 13 class G(F): 14 pass 15 class H(C,G): 16 pass 17 class Foo(E,H): 18 pass 19 20 print(E.__mro__) 21 print(H.__mro__) 22 print(Foo.__mro__) 23 24 答案: 25 26 (<class '__main__.E'>, <class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>) 27 28 (<class '__main__.H'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.G'>, <class '__main__.F'>, <class 'object'>) 29 30 (<class '__main__.Foo'>, <class '__main__.E'>, <class '__main__.D'>, <class '__main__.H'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class '__main__.G'>, <class '__main__.F'>, <class 'object'>)
|
3.3 多态
多种形态或多种状态
def func(arg):
arg.f1()
如上面的参数的类型并不能确定。所以python本身就具备多态的能力
鸭子类型:
参考鸭子类型,鸭子类型(英语:duck typing)是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由"当前方法和属性的集合"决定。这个概念的名字来源于由James Whitcomb Riley提出的鸭子测试,“鸭子测试”可以这样表述:
“当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
在鸭子类型中,关注的不是对象的类型本身,而是它是如何使用的。例如,在不使用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为"鸭子"的对象,并调用它的"走"和"叫"方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的"走"和"叫"方法。如果这些需要被调用的方法不存在,那么将引发一个运行时错误。任何拥有这样的正确的"走"和"叫"方法的对象都可被函数接受的这种行为引出了以上表述,这种决定类型的方式因此得名。
鸭子类型通常得益于"不"测试方法和函数中参数的类型,而是依赖文档、清晰的代码和测试来确保正确使用。
浙公网安备 33010602011771号