python面向对象重新梳理
关于本篇博文:
面向对象中所有的内容的重新梳理,其实面向对象的知识早在一个多月前就学习过并整理过,但是发现还是有所欠缺,故在此以极其简介的语言风格重新梳理一遍
面向对象详细介绍:http://www.cnblogs.com/wyb666/p/8728621.html
参考文章:http://www.cnblogs.com/linhaifeng/articles/6182264.html
一、面向过程与面向对象
1.面向过程
1 # 面向过程:核心是过程二字,过程指的是解决问题的步骤,设计一条流水线,机械式的思维方式 2 # 优点:复杂的问题流程化,进而简单化 3 # 缺点:可扩展性差 4 # 以下是面向过程的实例(用户注册),用户注册的流程为:用户输入信息->判断用户信息是否合法->合法就保存用户数据 5 import json 6 import re 7 8 9 def interactive(): 10 """ 11 用户输入信息 12 :return: 以字典形式返回注册账号的信息 13 """ 14 name = input('name>>>').strip() 15 pwd = input('password>>>').strip() 16 email = input('email>>> ').strip() 17 return { 18 'name': name, 19 'pwd': pwd, 20 'email': email 21 } 22 23 24 def check(user_info): 25 """ 26 判断用户输入信息是否正确 27 :param user_info: 用户信息 28 :return: 返回字典(用户信息及合法性) 29 """ 30 is_valid = True # is_valid表示合法性 31 # 判断用户名的合法性 32 if len(user_info['name']) == 0: 33 print('用户名不能为空') 34 is_valid = False 35 # 判断密码的合法性 36 if len(user_info['pwd']) < 6: 37 print('密码不能少于6位') 38 is_valid = False 39 # 判断邮箱格式的合法性 40 if not re.search(r'@.*?\.com$', user_info['email']): 41 print('邮箱格式不合法') 42 is_valid = False 43 return { 44 'is_valid': is_valid, 45 'user_info': user_info 46 } 47 48 49 def register(check_info): 50 """ 51 如果合法就注册用户(把用户信息导入json文件中) 52 :param check_info: 包含用户信息及合法性的字典 53 :return: 54 """ 55 if check_info['is_valid']: 56 with open('db.json', 'w', encoding='utf-8') as f: 57 json.dump(check_info['user_info'], f) 58 59 60 # 程序主函数 61 def main(): 62 user_info = interactive() 63 check_info = check(user_info) 64 register(check_info) 65 66 67 # 程序主入口 68 if __name__ == '__main__': 69 main()
2.面向对象
1 # 面向对象:核心就是对象二字,对象就是特征与技能的结合体 2 # 优点:可扩展性强 3 # 缺点:编程复杂度高 4 # 应用场景:用户需求经常变化,互联网应用,游戏,企业内部应用 5 6 # 类就是一系列对象相似的特征与技能的结合体 强调:站在不同的角度,得到的分类是不一样的 7 # 另外在现实世界中一定先有对象,后有类; 在程序中一定得先定义类,后调用类来产生对象 8 9 10 # 先定义类 11 class Student: 12 # 特征: 13 school = 'luffycity' 14 15 # 技能: 16 def learn(self): 17 print('is learning') 18 19 def eat(self): 20 print('is sleeping') 21 22 23 # 后产生对象 24 stu1 = Student() 25 stu2 = Student() 26 stu3 = Student() 27 28 print(stu1) 29 print(stu2) 30 print(stu3)
二、面向对象入门
1.类与对象的基本使用
(1)类的定义
1 # 定义类 2 class Student: 3 # 数据属性 4 school = 'luffycity' 5 6 # 函数属性 7 def learn(self): 8 print('is learning') 9 10 def eat(self): 11 print('is sleeping') 12 13 14 # 查看类的名称空间 15 print(Student.__dict__) 16 print(Student.__dict__['school']) 17 print(Student.__dict__['learn']) 18 print(Student.__dict__['eat']) 19 20 # 查 21 print(Student.school) # Student.__dict__['school'] 22 print(Student.learn) # Student.__dict__['learn'] 23 print(Student.eat) # Student.__dict__['eat'] 24 25 # 增 26 Student.county = 'China' 27 print(Student.__dict__) 28 print(Student.county) 29 30 # 删 31 del Student.county 32 33 # 改 34 Student.school = 'oldboy'
1 #python为类内置的特殊属性 2 类名.__name__# 类的名字(字符串) 3 类名.__doc__# 类的文档字符串 4 类名.__base__# 类的第一个父类(在讲继承时会讲) 5 类名.__bases__# 类所有父类构成的元组(在讲继承时会讲) 6 类名.__dict__# 类的字典属性 7 类名.__module__# 类定义所在的模块 8 类名.__class__# 实例对应的类(仅新式类中)
(2)__init__方法(构造函数)及对象的定义
1 # __init__方法用来为对象定制对象自己独有的特征 2 class Student: 3 school = 'luffycity' 4 5 # 构造函数 6 def __init__(self, name, sex, age): 7 self.Name = name 8 self.Sex = sex 9 self.Age = age 10 11 def learn(self): 12 print('is learning') 13 14 def eat(self): 15 print('is sleeping') 16 17 18 # 定义对象 19 stu1 = Student('王二丫', '女', 18) # Student.__init__(stu1,'王二丫','女',18) 20 21 # __init__方法后实例化的步骤: 22 # 1、先产生一个空对象stu1 23 # 2、Student.__init__(stu1,'王二丫','女',18) 24 25 # 对象的操作: 26 # 查 27 print(stu1.__dict__) 28 29 # 改 30 stu1.Name = '李二丫' 31 print(stu1.__dict__) 32 33 34 # 删除 35 del stu1.Name 36 print(stu1.__dict__) 37 38 # 增 39 stu1.class_name = 'python开发' 40 print(stu1.__dict__)
2.属性查找与绑定方法
关于绑定方法详细解释:https://www.cnblogs.com/vipchenwei/p/7126772.html
类有两种属性:数据属性和函数属性
- 类的数据属性是所有对象共享的
- 类的函数属性是绑定给对象用的
1 class Student: 2 school = 'luffycity' 3 4 def __init__(self, name, sex, age): 5 self.Name = name 6 self.Sex = sex 7 self.Age = age 8 9 def learn(self): 10 print('%s is learning' % self.Name) 11 12 def eat(self, food): 13 print('%s is eating' % self.Name) 14 print("food:", food) 15 16 17 stu1 = Student('王二丫', '女', 18) 18 stu2 = Student('李三炮', '男', 38) 19 stu3 = Student('张铁蛋', '男', 48) 20 21 22 # 对象:特征与技能的结合体 23 # 类:类是一系列对象相似的特征与相似的技能的结合体 24 # 类中的数据属性是所有对象共有的 25 print(Student.school, id(Student.school)) 26 print(stu1.school, id(stu1.school)) 27 print(stu2.school, id(stu2.school)) 28 print(stu3.school, id(stu3.school)) 29 # 类中的函数属性:是绑定给对象使用的,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传给self 30 print(Student.learn) 31 stu1.learn() # 调用对象的learn方法 32 stu2.learn() 33 stu3.learn() 34 35 print(stu1.eat) 36 stu1.eat("包子") # eat(stu1, "包子") 37 print(stu2.eat) 38 print(stu3.eat)
3.python中一切都是对象
1 # python一切皆对象,在python3里统一类类与类型的概念 2 class Student: 3 school = 'luffycity' 4 5 def __init__(self, name, sex, age): 6 self.Name = name 7 self.Sex = sex 8 self.Age = age 9 10 # stu1.Name='王二丫' 11 # stu1.Sex='女' 12 # stu1.Age=18 13 14 def learn(self, x): 15 print('%s is learning %s' % (self.Name, x)) 16 17 def eat(self): 18 print('%s is sleeping' % self.Name) 19 20 # 以下均是对象: 21 print(type([1, 2])) 22 print(list) 23 print(Student) 24 25 l1 = [1, 2, 3] # l=list([1,2,3]) 本质上是实例化对象 26 l2 = [] # l=list([1,2,3]) 本质上实例化对象 27 l1.append(4) # list.append(l1,4) 本质上是调用对象的绑定方法 28 list.append(l1, 4) # 和上一句同理 29 print(l1)
4.面向对象可拓展性与练习
(1)面向对象可拓展性实例:
1 # 1、在没有学习类这个概念时,数据与功能是分离的 2 def exc1(host, port, db, charset): 3 conn = connect(host, port, db, charset) 4 conn.execute(sql) 5 return xxx 6 7 8 def exc2(host, port, db, charset, proc_name) 9 conn = connect(host, port, db, charset) 10 conn.call_proc(sql) 11 return xxx 12 13 14 # 每次调用都需要重复传入一堆参数 15 exc1('127.0.0.1', 3306, 'db1', 'utf8', 'select * from tb1;') 16 exc2('127.0.0.1', 3306, 'db1', 'utf8', '存储过程的名字') 17 18 # 2、我们能想到的解决方法是,把这些变量都定义成全局变量 19 HOST = '127.0.0.1' 20 PORT = 3306 21 DB = 'db' 22 CHARSET = 'utf8' 23 24 def exc1(host, port, db, charset): 25 conn = connect(host, port, db, charset) 26 conn.execute(sql) 27 return xxx 28 29 30 def exc2(host, port, db, charset, proc_name) 31 conn = connect(host, port, db, charset) 32 conn.call_proc(sql) 33 return xxx 34 35 36 exc1(HOST, PORT, DB, CHARSET, 'select * from tb1;') 37 exc2(HOST, PORT, DB, CHARSET, '存储过程的名字') 38 39 40 # 3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用, 41 # 然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合 42 # 到一起的解决方法,这就是我们说的类了 43 44 class MySQLHandler: 45 def __init__(self, host, port, db, charset='utf8'): 46 self.host = host 47 self.port = port 48 self.db = db 49 self.charset = charset 50 51 def exc1(self, sql): 52 conn = connect(self.host, self.port, self.db, self.charset) 53 res = conn.execute(sql) 54 return res 55 56 def exc2(self, sql): 57 conn = connect(self.host, self.port, self.db, self.charset) 58 res = conn.call_proc(sql) 59 return res 60 61 62 obj = MySQLHandler('127.0.0.1', 3306, 'db1') 63 obj.exc1('select * from tb1;') 64 obj.exc2('存储过程的名字') 65 66 67 # 改进 68 class MySQLHandler: 69 def __init__(self, host, port, db, charset='utf8'): 70 self.host = host 71 self.port = port 72 self.db = db 73 self.charset = charset 74 self.conn = connect(self.host, self.port, self.db, self.charset) 75 76 def exc1(self, sql): 77 return self.conn.execute(sql) 78 79 def exc2(self, sql): 80 return self.conn.call_proc(sql) 81 82 83 obj = MySQLHandler('127.0.0.1', 3306, 'db1') 84 obj.exc1('select * from tb1;') 85 obj.exc2('存储过程的名字')
(2)练习1
1 # 练习1:编写一个学生类,产生一堆学生对象 2 # 要求: 有一个计数器(属性),统计总共实例了多少个对象 3 4 5 class Student: 6 school = 'luffycity' 7 count = 0 8 9 def __init__(self, name, age, sex): 10 self.name = name 11 self.age = age 12 self.sex = sex 13 Student.count += 1 # 等价于self.count+=1 14 15 def learn(self): 16 print('%s is learing' % self.name) 17 18 19 stu1 = Student('alex', 'male', 38) 20 stu2 = Student('jinxing', 'female', 78) 21 stu3 = Student('egon', 'male', 18) 22 23 print(Student.count) 24 print(stu1.count) 25 print(stu2.count) 26 print(stu3.count) 27 print(stu1.__dict__) 28 print(stu2.__dict__) 29 print(stu3.__dict__)
(3)练习2
1 # 练习2:模仿LoL定义两个英雄类 2 # 要求: 3 # 英雄需要有昵称、攻击力、生命值等属性; 4 # 实例化出两个英雄对象; 5 # 英雄之间可以互殴,被殴打的一方掉血,血量小于0则判定为死亡。 6 7 8 class Garen: 9 camp = 'Demacia' 10 11 def __init__(self, nickname, life_value, aggresivity): 12 self.nickname = nickname 13 self.life_value = life_value 14 self.aggresivity = aggresivity 15 16 def attack(self, enemy): 17 enemy.life_value -= self.aggresivity 18 19 20 class Riven: 21 camp = 'Noxus' 22 23 def __init__(self, nickname, life_value, aggresivity): 24 self.nickname = nickname 25 self.life_value = life_value 26 self.aggresivity = aggresivity 27 28 def attack(self, enemy): 29 enemy.life_value -= self.aggresivity 30 31 32 # 用类实例化对象 33 g1 = Garen('草丛伦', 100, 30) 34 r1 = Riven('可爱的锐雯雯', 80, 50) 35 36 print(r1.life_value) 37 g1.attack(r1) 38 print(r1.life_value)
(4)补充
1 (1)站的角度不同,定义出的类是截然不同的,详见面向对象实战之需求分析 2 (2)现实中的类并不完全等于程序中的类,比如现实中的公司类,在程序中有时需要拆分成部门类,业务类...... 3 (3)有时为了编程需求,程序中也可能会定义现实中不存在的类,比如策略类,现实中并不存在,但是在程序中却是一个很常见的类
三、面向对象进阶
1.继承
1 # 单继承与多继承: 2 class ParentClass1: #定义父类 3 pass 4 5 class ParentClass2: #定义父类 6 pass 7 8 class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass 9 pass 10 11 class SubClass2(ParentClass1,ParentClass2): # 多继承,用逗号分隔开多个继承的类 12 pass 13 14 15 # 经典类与新式类: 16 只在python2中才分新式类和经典类,python3中统一都是新式类 17 在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类 18 在python2中,显式地声明继承object的类,以及该类的子类,都是新式类 19 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类 20 21 提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现 22 23 24 # 上面练习2可以用继承重写: 25 class Hero: 26 x=3 27 def __init__(self,nickname,life_value,aggresivity): 28 self.nickname=nickname 29 self.life_value=life_value 30 self.aggresivity=aggresivity 31 def attack(self,enemy): 32 enemy.life_value-=self.aggresivity 33 34 class Garen(Hero): 35 pass 36 37 class Riven(Hero): 38 pass 39 40 41 g1=Garen('刚们',29,30) 42 print(g1.nickname,g1.life_value,g1.aggresivity) 43 g1.x=1 44 print(g1.x) 45 46 47 # 属性查找小练习: 48 # 一切属性查找均从对象开始查找,找不到就向上找父类 49 class Foo: 50 def f1(self): 51 print('from Foo.f1') 52 53 def f2(self): 54 print('from Foo.f2') 55 self.f1() #b.f1() 56 57 class Bar(Foo): 58 def f1(self): 59 print('from Bar.f1') 60 61 b=Bar() 62 # print(b.__dict__) 63 b.f2()
2.派生
子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值
1 class Hero: 2 def __init__(self, nickname, life_value, aggresivity): 3 self.nickname = nickname 4 self.life_value = life_value 5 self.aggresivity = aggresivity 6 7 def attack(self, enemy): 8 enemy.life_value -= self.aggresivity 9 10 11 class Garen(Hero): 12 camp = 'Demacia' 13 14 def attack(self, enemy): 15 print('from Garen Class') 16 17 18 class Riven(Hero): 19 camp = 'Noxus' 20 21 def __init__(self, nickname, aggressivity, life_value, skin): 22 Hero.__init__(self, nickname, aggressivity, life_value) # 调用父类功能 23 self.skin = skin # 新属性 24 25 def attack(self, enemy): # 在自己这里定义新的attack,不再使用父类的attack,且不会影响父类 26 Hero.attack(self, enemy) # 调用功能 27 print('from riven') 28 29 def fly(self): # 在自己这里定义新的 30 print('%s is flying' % self.nickname) 31 32 33 g = Garen('草丛伦', 100, 30) 34 r = Riven('锐雯雯', 80, 50, '比基尼') 35 # print(g.camp) 36 # g.attack(r) 37 # print(r.life_value) 38 g.attack(r)
3.新式类和旧式类
当类为新式类时,多继承下属性查找的方式为深度优先;当类为旧式类时,多继承下属性查找的方式为广度优先
1 # 新式类与经典类: 2 3 # 在python2中-》经典类:没有继承object的类,以及它的子类都称之为经典类 4 # 5 # class Foo: 6 # pass 7 # 8 # class Bar(Foo): 9 # pass 10 # 11 # 12 # 在python2中-》新式类:继承object的类,以及它的子类都称之为新式类 13 # class Foo(object): 14 # pass 15 # 16 # class Bar(Foo): 17 # pass 18 19 20 # 在python3中-》新式类:一个类没有继承object类,默认就继承object 21 # class Foo(): 22 # pass 23 # print(Foo.__bases__)
多继承的测试代码:
1 # 验证多继承情况下的属性查找: 2 class A: 3 # def test(self): 4 # print('from A') 5 pass 6 7 8 class B(A): 9 # def test(self): 10 # print('from B') 11 pass 12 13 14 class C(A): 15 # def test(self): 16 # print('from C') 17 pass 18 19 20 class D(B): 21 # def test(self): 22 # print('from D') 23 pass 24 25 26 class E(C): 27 # def test(self): 28 # print('from E') 29 pass 30 31 32 class F(D, E): 33 # def test(self): 34 # print('from F') 35 pass 36 37 38 # F,D,B,E,C,A 39 40 print(F.mro()) 41 f = F() 42 f.test()
4.在子类中重用父类的属性
(1)指名道姓(不依赖继承)
1 class Hero: 2 def __init__(self,nickname,life_value,aggresivity): 3 self.nickname=nickname 4 self.life_value=life_value 5 self.aggresivity=aggresivity 6 def attack(self,enemy): 7 enemy.life_value-=self.aggresivity 8 9 10 class Garen(Hero): 11 camp='Demacia' 12 13 def __init__(self,nickname,life_value,aggresivity,weapon): 14 # self.nickname=nickname 15 # self.life_value=life_value 16 # self.aggresivity=aggresivity 17 Hero.__init__(self,nickname,life_value,aggresivity) 18 19 self.weapon=weapon 20 21 def attack(self,enemy): 22 Hero.attack(self,enemy) # 指名道姓 23 print('from Garen Class') 24 25 26 g=Garen('草丛伦',100,30,'金箍棒') 27 print(g.__dict__)
(2)super() (依赖继承)
1 class Hero: 2 def __init__(self,nickname,life_value,aggresivity): 3 self.nickname=nickname 4 self.life_value=life_value 5 self.aggresivity=aggresivity 6 def attack(self,enemy): 7 enemy.life_value-=self.aggresivity 8 9 10 class Garen(Hero): 11 camp='Demacia' 12 13 def __init__(self,nickname,life_value,aggresivity,weapon): 14 # self.nickname=nickname 15 # self.life_value=life_value 16 # self.aggresivity=aggresivity 17 18 # super(Garen,self).__init__(nickname,life_value,aggresivity) 19 super().__init__(nickname,life_value,aggresivity) 20 self.weapon=weapon 21 22 def attack(self,enemy): 23 Hero.attack(self,enemy) # 指名道姓 24 print('from Garen Class') 25 26 27 g=Garen('草丛伦',100,30,'金箍棒') 28 print(g.__dict__)
(3)思考
1 class A: 2 def f1(self): 3 print('from A') 4 super().f1() 5 6 7 class B: 8 def f1(self): 9 print('from B') 10 11 12 class C(A, B): 13 pass 14 15 16 print(C.mro()) 17 # [<class '__main__.C'>, 18 # <class '__main__.A'>, 19 # <class '__main__.B'>, 20 # <class 'object'>] 21 22 23 c = C() 24 c.f1()
上述代码输出结果为:
1 [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>] 2 from A 3 from B
5.组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
1 class People: 2 school = 'luffycity' 3 4 def __init__(self, name, age, sex): 5 self.name = name 6 self.age = age 7 self.sex = sex 8 9 10 class Teacher(People): 11 def __init__(self, name, age, sex, level, salary, ): 12 super().__init__(name, age, sex) 13 14 self.level = level 15 self.salary = salary 16 17 def teach(self): 18 print('%s is teaching' % self.name) 19 20 21 class Student(People): 22 def __init__(self, name, age, sex, class_time, ): 23 super().__init__(name, age, sex) 24 self.class_time = class_time 25 26 def learn(self): 27 print('%s is learning' % self.name) 28 29 30 class Course: 31 def __init__(self, course_name, course_price, course_period): 32 self.course_name = course_name 33 self.course_price = course_price 34 self.course_period = course_period 35 36 def tell_info(self): 37 print('课程名<%s> 课程价钱<%s> 课程周期<%s>' % (self.course_name, self.course_price, self.course_period)) 38 39 40 class Date: 41 def __init__(self, year, mon, day): 42 self.year = year 43 self.mon = mon 44 self.day = day 45 46 def tell_info(self): 47 print('%s-%s-%s' % (self.year, self.mon, self.day)) 48 49 50 # 实例化对象 51 teacher1 = Teacher('alex', 18, 'male', 10, 3000, ) 52 teacher2 = Teacher('egon', 28, 'male', 30, 3000, ) 53 python = Course('python', 3000, '3mons') 54 linux = Course('linux', 2000, '4mons') 55 56 57 # 组合实例: 58 # 设置教师课程 59 teacher1.course = python 60 teacher2.course = python 61 print(teacher1.course) 62 print(teacher2.course) 63 print(teacher1.course.course_name) 64 print(teacher2.course.course_name) 65 teacher1.course.tell_info() 66 67 # 实例化学生对象并设置学生课程 68 student1 = Student('张三', 28, 'female', '08:30:00') 69 student1.course1 = python 70 student1.course2 = linux 71 student1.course1.tell_info() 72 student1.course2.tell_info() 73 student1.courses = [] 74 student1.courses.append(python) 75 student1.courses.append(linux) 76 77 # 实例化学生对象并设置学生生日及学生课程 78 student1 = Student('张三', 28, 'female', '08:30:00') 79 d = Date(1988, 4, 20) 80 python = Course('python', 3000, '3mons') 81 student1.birh = d 82 student1.birh.tell_info() 83 student1.course = python 84 student1.course.tell_info()
6.接口及多态
(1)接口
1 # IAnimal .java Java 语言中的接口很好的展现了接口的含义 2 /* 3 * Java的Interface接口的特征: 4 * 1)是一组功能的集合,而不是一个功能 5 * 2)接口的功能用于交互,所有的功能都是public,即别的对象可操作 6 * 3)接口只定义函数,但不涉及函数实现 7 * 4)这些功能是相关的,都是动物相关的功能,但光合作用就不适宜放到IAnimal里面了 */ 8 9 package com.oo.demo; 10 public interface IAnimal { 11 public void eat(); 12 public void run(); 13 public void sleep(); 14 public void speak(); 15 } 16 17 18 # Pig.java:猪”的类设计,实现了IAnnimal接口 19 package com.oo.demo; 20 public class Pig implements IAnimal{ //如下每个函数都需要详细实现 21 public void eat(){ 22 System.out.println("Pig like to eat grass"); 23 } 24 25 public void run(){ 26 System.out.println("Pig run: front legs, back legs"); 27 } 28 29 public void sleep(){ 30 System.out.println("Pig sleep 16 hours every day"); 31 } 32 33 public void speak(){ 34 System.out.println("Pig can not speak"); } 35 } 36 37 # Person2.java 38 /* 39 *实现了IAnimal的“人”,有几点说明一下: 40 * 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样 41 * 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */ 42 43 package com.oo.demo; 44 public class Person2 implements IAnimal { 45 public void eat(){ 46 System.out.println("Person like to eat meat"); 47 } 48 49 public void run(){ 50 System.out.println("Person run: left leg, right leg"); 51 } 52 53 public void sleep(){ 54 System.out.println("Person sleep 8 hours every dat"); 55 } 56 57 public void speak(){ 58 System.out.println("Hellow world, I am a person"); 59 } 60 } 61 62 # Tester03.java 63 package com.oo.demo; 64 65 public class Tester03 { 66 public static void main(String[] args) { 67 System.out.println("===This is a person==="); 68 IAnimal person = new Person2(); 69 person.eat(); 70 person.run(); 71 person.sleep(); 72 person.speak(); 73 74 System.out.println("\n===This is a pig==="); 75 IAnimal pig = new Pig(); 76 pig.eat(); 77 pig.run(); 78 pig.sleep(); 79 pig.speak(); 80 } 81 }
注:hi boy,给我开个查询接口。。。此时的接口指的是:自己提供给使用者来调用自己功能的方式\方法\入口
接口提取了一群类共同的函数,可以把接口当做一个函数的集合,然后让子类去实现接口中的函数
这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样
归一化的好处在于:
- 让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
- 使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合
- 就象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕
模仿interface:在python中根本就没有一个叫做interface的关键字,如果非要去模仿接口的概念
可以借助第三方模块:http://pypi.python.org/pypi/zope.interface
twisted的twisted\internet\interface.py里使用zope.interface
文档https://zopeinterface.readthedocs.io/en/latest/
设计模式:https://github.com/faif/python-patterns
也可以使用继承来实现:
- 继承基类的方法,并且做出自己的改变或者扩展(代码重用):实践中,继承的这种用途意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
- 声明某个子类兼容于某基类,定义一个接口类(模仿java的Interface),接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
注子类完全可以不用去实现接口 ,这就用到了抽象类
(2)抽象类
与java一样,python也有抽象类的概念但是同样需要借助模块实现,抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化
为什么要有抽象类:
- 如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性
- 比如我们有香蕉的类,有苹果的类,有桃子的类,从这些类抽取相同的内容就是水果这个抽象的类,你吃水果时,要么是吃一个具体的香蕉,要么是吃一个具体的桃子。。。。。。你永远无法吃到一个叫做水果的东西
- 从设计角度去看,如果类是从现实对象抽象而来的,那么抽象类就是基于类抽象而来的
- 从实现角度来看,抽象类与普通类的不同之处在于:抽象类中只能有抽象方法(没有实现功能),该类不能被实例化,只能被继承,且子类必须实现抽象方法
抽象类与接口:
- 抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性
- 抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
1 import abc 2 3 4 # 抽象类的标准写法: 5 class Animal(metaclass=abc.ABCMeta): # 只能被继承,不能被实例化 6 all_type = 'animal' 7 8 @abc.abstractmethod # 被装饰的方法必须被子类重写 9 def run(self): 10 pass 11 12 @abc.abstractmethod 13 def eat(self): 14 pass 15 16 17 # animal=Animal() -》 该代码无法运行会报错 18 19 20 class People(Animal): 21 def run(self): 22 print('people is running') 23 24 def eat(self): 25 print('people is eating') 26 27 28 class Pig(Animal): 29 def run(self): 30 print('people is walking') 31 32 def eat(self): 33 print('people is eating') 34 35 36 class Dog(Animal): 37 def run(self): 38 print('people is walking') 39 40 def eat(self): 41 print('people is eating') 42 43 44 peo1 = People() 45 pig1 = Pig() 46 dog1 = Dog() 47 48 peo1.eat() 49 pig1.eat() 50 dog1.eat() 51 52 print(peo1.all_type)
(3)多态与多态性
多态详细解释: http://www.cnblogs.com/linhaifeng/articles/7340687.html
1 # 多态:同一类事物的多种形态 2 import abc 3 4 5 class Animal(metaclass=abc.ABCMeta): # 同一类事物:动物 6 @abc.abstractmethod 7 def talk(self): 8 pass 9 10 11 class People(Animal): # 动物的形态之一:人 12 def talk(self): 13 print('say hello') 14 15 16 class Dog(Animal): # 动物的形态之二:狗 17 def talk(self): 18 print('say wangwang') 19 20 21 class Pig(Animal): # 动物的形态之三:猪 22 def talk(self): 23 print('say aoao') 24 25 26 class Cat(Animal): 27 def talk(self): 28 print('say miamiao') 29 30 31 # 多态性:指的是可以在不考虑对象的类型的情况下而直接使用对象 32 peo1 = People() 33 dog1 = Dog() 34 pig1 = Pig() 35 cat1 = Cat() 36 37 38 peo1.talk() 39 dog1.talk() 40 pig1.talk() 41 42 43 def func(animal): 44 animal.talk() 45 46 47 func(peo1) 48 func(pig1) 49 func(dog1) 50 func(cat1)
(4)鸭子类型
逗比时刻:
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子
python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象,也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法
1 #二者都像鸭子,二者看起来都像文件,因而就可以当文件一样去用 2 class TxtFile: 3 def read(self): 4 pass 5 6 def write(self): 7 pass 8 9 class DiskFile: 10 def read(self): 11 pass 12 def write(self): 13 pass
例2:其实大家一直在享受着多态性带来的好处,比如Python的序列类型有多种形态:字符串,列表,元组,多态性体现如下
1 #str,list,tuple都是序列类型 2 s=str('hello') 3 l=list([1,2,3]) 4 t=tuple((4,5,6)) 5 6 #我们可以在不考虑三者类型的前提下使用s,l,t 7 s.__len__() 8 l.__len__() 9 t.__len__() 10 11 len(s) 12 len(l) 13 len(t)
四、面向对象高阶
1.重谈封装
(1)封装之如何隐藏属性
1 # 隐藏属性实例: 2 class A: 3 __x = 1 # _A__x=1 4 5 def __init__(self, name): 6 self.__name = name # self._A__name=name 7 8 def __foo(self): # def _A__foo(self): 9 print('run foo') 10 11 def bar(self): 12 self.__foo() # self._A__foo() 13 print('from bar') 14 15 16 print(A.__dict__) 17 # 接下来的两句都会报错: 18 # print(A.__x) 19 # print(A.__foo) 20 21 a = A('egon') 22 print(a._A__x) 23 print(a._A__foo()) 24 25 # 接下来这句也会报错: 26 # print(a.__name) # a.__dict__['__name'] 27 print(a.__dict__) 28 29 a.bar() 30 31 # python实际上是通过使用变形来让这些属性无法被直接访问 32 # 这种变形的特点: 33 # 1、在类外部无法直接obj.__AttrName 34 # 2、在类内部是可以直接使用:obj.__AttrName 35 # 3、子类无法覆盖父类__开头的属性 36 # 4、这种变形在类定义的阶段就会生成 37 38 39 # 子类无法覆盖父类__开头的属性: 40 class Foo: 41 def __func(self): #_Foo__func 42 print('from foo') 43 44 class Bar(Foo): 45 def __func(self): #_Bar__func 46 print('from bar') 47 48 b=Bar() 49 b.func() 50 51 52 # 这种变形需要注意的问题是: 53 # (1)这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N, 54 # 即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问 55 # (2)变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形 56 # (3)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有 57 58 class B: 59 __x = 1 60 61 def __init__(self, name): 62 self.__name = name # self._B__name=name 63 64 65 # 验证问题一: 66 print(B._B__x) 67 68 # 验证问题二: 69 B.__y = 2 70 print(B.__dict__) 71 b = B('egon') 72 print(b.__dict__) 73 74 b.__age = 18 75 print(b.__dict__) 76 print(b.__age) 77 78 79 # 验证问题三: 80 class A: 81 def foo(self): 82 print('A.foo') 83 84 def bar(self): 85 print('A.bar') 86 self.foo() # self.foo() -> b.foo() 87 88 89 class B(A): 90 def foo(self): 91 print('B.foo') 92 93 94 b = B() 95 b.bar() 96 97 98 class A: 99 def __foo(self): # _A__foo 100 print('A.foo') 101 102 def bar(self): 103 print('A.bar') 104 self.__foo() # self._A__foo() 105 106 107 class B(A): 108 def __foo(self): # _B__foo 109 print('B.foo') 110 111 112 b = B() 113 b.bar()
(2)封装的意义
封装数据:将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制
1 # 一:封装数据属性:明确的区分内外,控制外部对隐藏的属性的操作行为 2 class People: 3 def __init__(self, name, age): 4 self.__name = name 5 self.__age = age 6 7 def tell_info(self): 8 print('Name:<%s> Age:<%s>' % (self.__name, self.__age)) 9 10 def set_info(self, name, age): 11 if not isinstance(name, str): 12 print('名字必须是字符串类型') 13 return 14 if not isinstance(age, int): 15 print('年龄必须是数字类型') 16 return 17 self.__name = name 18 self.__age = age 19 20 21 # 外部对姓名和年龄的操作只能通过tell_info和set_info这两个函数实现 22 p = People('wyb', 21) 23 p.tell_info() 24 p.set_info('woz', 22) 25 p.tell_info() 26 27 28 # 二、 封装方法:隔离复杂度 29 # 取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱 30 # 对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做 31 # 隔离了复杂度,同时也提升了安全性 32 class ATM: 33 def __card(self): 34 print('插卡') 35 36 def __auth(self): 37 print('用户认证') 38 39 def __input(self): 40 print('输入取款金额') 41 42 def __print_bill(self): 43 print('打印账单') 44 45 def __take_money(self): 46 print('取款') 47 48 def withdraw(self): 49 self.__card() 50 self.__auth() 51 self.__input() 52 self.__print_bill() 53 self.__take_money() 54 55 56 a = ATM() 57 a.withdraw()
2.property
1 # BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 2 # 3 # 成人的BMI数值: 4 # 过轻:低于18.5 5 # 正常:18.5-23.9 6 # 过重:24-27 7 # 肥胖:28-32 8 # 非常肥胖, 高于32 9 # 10 # 体质指数(BMI)=体重(kg)÷身高^2(m) 11 # EX:70kg÷(1.75×1.75)=22.86 12 class BMI: 13 def __init__(self, name, weight, height): 14 self.name = name 15 self.weight = weight 16 self.height = height 17 18 @property # 像访问数据一样调用类中函数 19 def bmi(self): 20 return self.weight / (self.height ** 2) 21 22 23 p = BMI('egon', 75, 1.81) 24 print(p.bmi) 25 p.height = 1.82 26 print(p.bmi) 27 # p.bmi=3333 # 报错AttributeError: can't set attribute 28 29 30 class People: 31 def __init__(self, name): 32 self.__name = name 33 34 @property # 像访问数据一样调用类中函数 35 def name(self): 36 # print('getter') 37 return self.__name 38 39 @name.setter # 设置值操作 40 def name(self, val): 41 # print('setter',val) 42 if not isinstance(val, str): 43 print('名字必须是字符串类型') 44 return 45 self.__name = val 46 47 @name.deleter # 删除值操作 48 def name(self): 49 # print('deleter') 50 print('不允许删除') 51 52 53 p = People('egon') 54 print(p.name) 55 p.name = 'wyb' 56 print(p.name) 57 p.name = 123 58 del p.name
3.绑定方法与非绑定方法
1 # 在类内部定义的函数,分为两大类: 2 # 绑定方法:绑定给谁,就应该由谁来调用,谁来调用就回把调用者当作第一个参数自动传入 3 # 绑定到对象的方法:在类内定义的没有被任何装饰器修饰的 4 # 绑定到类的方法:在类内定义的被装饰器classmethod修饰的方法 5 # 6 # 非绑定方法:没有自动传值这么一说了,就类中定义的一个普通工具,对象和类都可以使用 7 # 非绑定方法:不与类或者对象绑定 8 class Foo: 9 def __init__(self, name): 10 self.name = name 11 12 def tell(self): 13 print('名字是%s' % self.name) 14 15 @classmethod 16 def func(cls): # cls=Foo 17 print(cls) 18 19 @staticmethod 20 def func1(x, y): 21 print(x + y)
应用:
1 import settings 2 import hashlib 3 import time 4 class People: 5 def __init__(self, name, age, sex): 6 self.id = self.create_id() 7 self.name = name 8 self.age = age 9 self.sex = sex 10 11 def tell_info(self): # 绑定到对象的方法 12 print('Name:%s Age:%s Sex:%s' % (self.name, self.age, self.sex)) 13 14 @classmethod 15 def from_conf(cls): 16 obj = cls( 17 settings.name, 18 settings.age, 19 settings.sex 20 ) 21 return obj 22 23 @staticmethod 24 def create_id(): 25 m = hashlib.md5(str(time.time()).encode('utf-8')) 26 return m.hexdigest() 27 28 29 # 绑定给对象,就应该由对象来调用,自动将对象本身当作第一个参数传入 30 # p.tell_info() # tell_info(p) 31 32 # 绑定给类,就应该由类来调用,自动将类本身当作第一个参数传入 33 # p=People.from_conf() # from_conf(People) 34 # p.tell_info() 35 36 # 非绑定方法,不与类或者对象绑定,谁都可以调用,没有自动传值一说 37 p1 = People('egon1', 18, 'male') 38 p2 = People('egon2', 28, 'male') 39 p3 = People('egon3', 38, 'male') 40 print(p1.id) 41 print(p2.id) 42 print(p3.id)
4.反射
1 # # 反射:通过字符串映射到对象的属性 2 # class People: 3 # country = 'China' 4 # 5 # def __init__(self, name, age): 6 # self.name = name 7 # self.age = age 8 # 9 # def talk(self): 10 # print('%s is talking' % self.name) 11 # 12 # 13 # obj = People('egon', 18) 14 # print(obj.name) # obj.__dict__['name'] 15 # print(obj.talk) 16 # choice = input('>>: ') # choice='name' 17 # print(obj.choice) # print(obj.'name') -> 报错 18 19 # python中内置了一些方法可以实现反射: 20 # print(hasattr(obj, 'name')) # obj.name # obj.__dict__['name'] 21 # print(hasattr(obj, 'talk')) # obj.talk 22 # print(getattr(obj,'name',None)) 23 # print(getattr(obj,'talk',None)) 24 # setattr(obj,'sex','male') # obj.sex='male' 25 # print(obj.sex) 26 # delattr(obj,'age') # del obj.age 27 # print(obj.__dict__) 28 # print(getattr(People,'country')) # People.country 29 30 31 # # 反射的应用: 32 # 接受用户输入,根据用户输入选择属性 33 class Service: 34 def run(self): 35 while True: 36 inp = input('>>: ').strip() # cmd='get a.txt' 37 cmds = inp.split() # cmds=['get','a.txt'] 38 if hasattr(self, cmds[0]): 39 func = getattr(self, cmds[0]) # 获得绑定方法 40 func(cmds) # 调用绑定方法 41 42 def get(self, cmds): 43 print('get.......', cmds) 44 45 def put(self, cmds): 46 print('put.......', cmds) 47 48 49 obj = Service() 50 obj.run()
5.内置方法
1 # isinstance(obj,cls)检查是否obj是否是类 cls 的对象 2 class Foo(object): 3 pass 4 obj = Foo() 5 isinstance(obj, Foo) 6 7 # issubclass(sub, super)检查sub类是否是 super 类的派生类 8 class Foo(object): 9 pass 10 11 class Bar(Foo): 12 pass 13 14 issubclass(Bar, Foo)
6.元类
(1)exec
1 exec:三个参数 2 参数一:字符串形式的命令 3 参数二:全局作用域(字典形式),如果不指定,默认为globals() 4 参数三:局部作用域(字典形式),如果不指定,默认为locals() 5 6 7 # 可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中 8 # 实例如下: 9 g={ 10 'x':1, 11 'y':2 12 } 13 l={} 14 15 exec(''' 16 global x,z 17 x=100 18 z=200 19 20 m=300 21 ''',g,l) 22 23 print(g) # {'x': 100, 'y': 2,'z':200,......} 24 print(l) # {'m': 300}
(2)元类介绍
python中一切皆是对象,类本身也是一个对象,当使用关键字class的时候,python解释器在加载class的时候就会创建一个对象(这里的对象指的是类而非类的实例),因而我们可以将类当作一个对象去使用,同样满足第一类对象的概念,可以:
- 把类赋值给一个变量
- 把类作为函数参数进行传递
- 把类作为函数的返回值
- 在运行时动态地创建类
- 可以当作容器类的元素,l=[func,time,obj,1]
1 # 类也是对象,Foo=type(....) 2 class Foo: 3 pass 4 5 obj=Foo() 6 print(type(obj)) 7 print(type(Foo))
元类是类的类,是类的模板,元类是用来控制如何创建类的,正如类是创建对象的模板一样,而元类的主要目的是为了控制类的创建行为
产生类的类称之为元类,默认所有用class定义的类,他们的元类是type,元类用metaclass表示
(3)创建一个类的两种方式
使用class关键字
1 class Chinese: # Chinese=type(...) 2 country = 'China' 3 4 def __init__(self, namem, age): 5 self.name = namem 6 self.age = age 7 8 def talk(self): 9 print('%s is talking' % self.name) 10 11 # print(Chinese) 12 obj = Chinese('woz', 18) 13 print(obj, obj.name, obj.age)
使用type的方法手动模拟class创建类的过程,将创建类的步骤拆分开,手动去创建
1 # 定义类的三要素:类名,类的基类们,类的名称空间 2 class_name = 'Chinese' 3 class_bases = (object,) 4 class_body = """ 5 country='China' 6 7 def __init__(self,namem,age): 8 self.name=namem 9 self.age=age 10 11 def talk(self): 12 print('%s is talking' %self.name) 13 """ 14 15 class_dic = {} 16 exec(class_body, globals(), class_dic) 17 # print(class_dic) 18 Chinese1 = type(class_name, class_bases, class_dic) 19 # print(Chinese1) 20 obj1 = Chinese1('wyb', 20) 21 print(obj1, obj1.name, obj1.age)
(4)自定义元类控制类
1 # 自定义元类控制类的行为 2 class Mymeta(type): 3 def __init__(self, class_name, class_bases, class_dic): 4 if not class_name.istitle(): 5 raise TypeError('类名的首字母必须大写') 6 7 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 8 raise TypeError('必须有注释,且注释不能为空') 9 10 super(Mymeta, self).__init__(class_name, class_bases, class_dic) 11 12 13 class Chinese(object, metaclass=Mymeta): 14 """ 15 一个基于自定义元类生成的类,类名首字母必须大写并且必须有注释,且注释不能为空 16 """ 17 country = 'China' 18 19 def __init__(self, namem, age): 20 self.name = namem 21 self.age = age 22 23 def talk(self): 24 print('%s is talking' % self.name) 25 26 # Chinese=Mymeta(class_name,class_bases,class_dic)
1 # 自定义元类控制类的实例化行为: 2 # 知识储备__call__方法 3 # class Foo: 4 # def __call__(self, *args, **kwargs): 5 # print(self) 6 # print(args) 7 # print(kwargs) 8 # 9 # 10 # obj = Foo() 11 # obj(1, 2, 3, a=1, b=2, c=3) # obj.__call__(obj,1,2,3,a=1,b=2,c=3) 12 # 注: 在元类内部也应有有一个__call__方法,会在调用元类时触发执行 13 14 15 class Mymeta(type): 16 def __init__(self, class_name, class_bases, class_dic): 17 if not class_name.istitle(): 18 raise TypeError('类名的首字母必须大写') 19 20 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 21 raise TypeError('必须有注释,且注释不能为空') 22 23 super(Mymeta, self).__init__(class_name, class_bases, class_dic) 24 25 def __call__(self, *args, **kwargs): # obj=Chinese('wyb',age=20) 26 # print(self) # self=Chinese 27 # print(args) # args=('wyb',) 28 # print(kwargs) # kwargs={'wyb': 20} 29 30 # 第一件事:先造一个空对象obj 31 obj = object.__new__(self) 32 # 第二件事:初始化obj 33 self.__init__(obj, *args, **kwargs) 34 # 第三件事:返回obj 35 return obj 36 37 38 class Chinese(object, metaclass=Mymeta): 39 ''' 40 中文人的类 41 ''' 42 country = 'China' 43 44 def __init__(self, namem, age): 45 self.name = namem 46 self.age = age 47 48 def talk(self): 49 print('%s is talking' % self.name) 50 51 52 obj = Chinese('wyb', age=20) # Chinese.__call__(Chinese,'wyb',20) 53 print(obj.__dict__)
1 # 单例模式 -> 保证一个类仅有一个实例,并提供一个访问它的全局访问点 2 # 实现方式一: 3 class MySQL: 4 __instance = None # __instance=obj1 5 6 def __init__(self): 7 self.host = '127.0.0.1' 8 self.port = 3306 9 10 @classmethod 11 def singleton(cls): 12 if not cls.__instance: 13 obj = cls() 14 cls.__instance = obj 15 return cls.__instance 16 17 def conn(self): 18 pass 19 20 def execute(self): 21 pass 22 23 24 obj1 = MySQL.singleton() 25 obj2 = MySQL.singleton() 26 obj3 = MySQL.singleton() 27 print(obj1 is obj2 is obj3) 28 29 30 # 实现方式二:元类的方式 31 class Mymeta(type): 32 def __init__(self, class_name, class_bases, class_dic): 33 if not class_name.istitle(): 34 raise TypeError('类名的首字母必须大写') 35 36 if '__doc__' not in class_dic or not class_dic['__doc__'].strip(): 37 raise TypeError('必须有注释,且注释不能为空') 38 39 super(Mymeta, self).__init__(class_name, class_bases, class_dic) 40 self.__instance = None 41 42 def __call__(self, *args, **kwargs): # obj=Chinese('egon',age=18) 43 if not self.__instance: 44 obj = object.__new__(self) 45 self.__init__(obj) 46 self.__instance = obj 47 48 return self.__instance 49 50 51 class Mysql(object, metaclass=Mymeta): 52 ''' 53 mysql xxx 54 ''' 55 56 def __init__(self): 57 self.host = '127.0.0.1' 58 self.port = 3306 59 60 def conn(self): 61 pass 62 63 def execute(self): 64 pass 65 66 67 obj1 = Mysql() 68 obj2 = Mysql() 69 obj3 = Mysql() 70 71 print(obj1 is obj2 is obj3)
7.异常处理复习总结
1 # 什么是异常:异常是错误发生的信号,一旦程序出错,并且程序没有处理这个错误,那个就会抛出异常,并且程序的运行随之终止 2 3 4 # 错误分为两种: 5 # 语法错误: 使程序无法执行,在程序执行前就要立刻改正过来 6 # print('xxxx' 7 # if 1 > 2 8 # 逻辑错误: 程序逻辑上的错误,在程序运行时才会出现 9 #ValueError 10 # int('aaa') 11 #NameError 12 # name 13 #IndexError 14 # l=[1,2,3] 15 # l[1000] 16 #KeyError 17 # d={} 18 # d['name'] 19 #AttributeError 20 # class Foo: 21 # pass 22 # 23 # Foo.xxx 24 #ZeroDivisionError: 25 # 1/0 26 #TypeError:int类型不可迭代 27 # for i in 3: 28 # pass 29 30 31 # 异常 32 # 强调一:错误发生的条件如果是可以预知的,此时应该用if判断去预防异常 33 # AGE=10 34 # age=input('>>: ').strip() 35 # 36 # if age.isdigit(): 37 # age=int(age) 38 # if age > AGE: 39 # print('太大了') 40 41 # 强调二:错误发生的条件如果是不可预知的,此时应该用异常处理机制,try...except 42 try: 43 f=open('a.txt','r',encoding='utf-8') 44 45 print(next(f),end='') 46 print(next(f),end='') 47 print(next(f),end='') 48 print(next(f),end='') 49 50 print(next(f),end='') 51 print(next(f),end='') 52 print(next(f),end='') 53 54 f.close() 55 except StopIteration: 56 print('出错啦') 57 58 59 print('====>1') 60 print('====>2') 61 print('====>3')
1 # 多分支:被监测的代码块抛出的异常有多种可能性,并且我们需要针对每一种异常类型都定制专门的处理逻辑 2 # try: 3 # print('===>1') 4 # # name 5 # print('===>2') 6 # l=[1,2,3] 7 # # l[100] 8 # print('===>3') 9 # d={} 10 # d['name'] 11 # print('===>4') 12 # 13 # except NameError as e: 14 # print('--->',e) 15 # 16 # except IndexError as e: 17 # print('--->',e) 18 # 19 # except KeyError as e: 20 # print('--->',e) 21 # 22 # print('====>afer code') 23 24 25 # 万能异常:Exception,被监测的代码块抛出的异常有多种可能性, 26 # 并且我们针对所有的异常类型都只用一种处理逻辑就可以了,那就使用Exception 27 # try: 28 # print('===>1') 29 # # name 30 # print('===>2') 31 # l=[1,2,3] 32 # l[100] 33 # print('===>3') 34 # d={} 35 # d['name'] 36 # print('===>4') 37 # 38 # except Exception as e: 39 # print('异常发生啦:',e) 40 # 41 # print('====>afer code') 42 43 44 # try: 45 # print('===>1') 46 # # name 47 # print('===>2') 48 # l=[1,2,3] 49 # # l[100] 50 # print('===>3') 51 # d={} 52 # d['name'] 53 # print('===>4') 54 # 55 # except NameError as e: 56 # print('--->',e) 57 # 58 # except IndexError as e: 59 # print('--->',e) 60 # 61 # except KeyError as e: 62 # print('--->',e) 63 # 64 # except Exception as e: 65 # print('统一的处理方法') 66 # 67 # print('====>afer code') 68 69 70 # 其他结构 71 # try: 72 # print('===>1') 73 # # name 74 # print('===>2') 75 # l=[1,2,3] 76 # # l[100] 77 # print('===>3') 78 # d={} 79 # d['name'] 80 # print('===>4') 81 # 82 # except NameError as e: 83 # print('--->',e) 84 # 85 # except IndexError as e: 86 # print('--->',e) 87 # 88 # except KeyError as e: 89 # print('--->',e) 90 # 91 # except Exception as e: 92 # print('统一的处理方法') 93 # 94 # else: # 在被检测的代码块没有发生异常时执行 95 # pass 96 # 97 # finally: # 不管被检测的代码块有无发生异常都会执行 98 # pass 99 # 100 # print('====>afer code') 101 102 103 # 主动触发异常:raise 异常类型(值) 104 # class People: 105 # def __init__(self,name,age): 106 # if not isinstance(name,str): 107 # raise TypeError('名字必须传入str类型') 108 # if not isinstance(age,int): 109 # raise TypeError('年龄必须传入int类型') 110 # 111 # self.name=name 112 # self.age=age 113 # 114 # p=People('egon',18) 115 116 117 # 自定义异常类型 118 # class MyException(BaseException): 119 # def __init__(self, msg): 120 # super(MyException, self).__init__() 121 # self.msg = msg 122 # 123 # def __str__(self): 124 # return '<%s>' % self.msg 125 # 126 # 127 # raise MyException('我自己的异常类型') # print(obj) 128 129 130 # 断言assert 131 # info={} 132 # info['name']='egon' 133 # # info['age']=18 134 # 135 # # if 'name' not in info: 136 # # raise KeyError('必须有name这个key') 137 # # 138 # # if 'age' not in info: 139 # # raise KeyError('必须有age这个key') 140 # 141 # assert ('name' in info) and ('age' in info) 142 # 143 # if info['name'] == 'egon' and info['age'] > 10: 144 # print('welcome')