关于本篇博文:

面向对象中所有的内容的重新梳理,其实面向对象的知识早在一个多月前就学习过并整理过,但是发现还是有所欠缺,故在此以极其简介的语言风格重新梳理一遍

面向对象详细介绍: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. def interactive():
  9. """
  10. 用户输入信息
  11. :return: 以字典形式返回注册账号的信息
  12. """
  13. name = input('name>>>').strip()
  14. pwd = input('password>>>').strip()
  15. email = input('email>>> ').strip()
  16. return {
  17. 'name': name,
  18. 'pwd': pwd,
  19. 'email': email
  20. }
  21.  
  22. def check(user_info):
  23. """
  24. 判断用户输入信息是否正确
  25. :param user_info: 用户信息
  26. :return: 返回字典(用户信息及合法性)
  27. """
  28. is_valid = True # is_valid表示合法性
  29. # 判断用户名的合法性
  30. if len(user_info['name']) == 0:
  31. print('用户名不能为空')
  32. is_valid = False
  33. # 判断密码的合法性
  34. if len(user_info['pwd']) < 6:
  35. print('密码不能少于6位')
  36. is_valid = False
  37. # 判断邮箱格式的合法性
  38. if not re.search(r'@.*?\.com$', user_info['email']):
  39. print('邮箱格式不合法')
  40. is_valid = False
  41. return {
  42. 'is_valid': is_valid,
  43. 'user_info': user_info
  44. }
  45.  
  46. def register(check_info):
  47. """
  48. 如果合法就注册用户(把用户信息导入json文件中)
  49. :param check_info: 包含用户信息及合法性的字典
  50. :return:
  51. """
  52. if check_info['is_valid']:
  53. with open('db.json', 'w', encoding='utf-8') as f:
  54. json.dump(check_info['user_info'], f)
  55.  
  56. # 程序主函数
  57. def main():
  58. user_info = interactive()
  59. check_info = check(user_info)
  60. register(check_info)
  61.  
  62. # 程序主入口
  63. if __name__ == '__main__':
  64. main()

2.面向对象

  1. # 面向对象:核心就是对象二字,对象就是特征与技能的结合体
  2. # 优点:可扩展性强
  3. # 缺点:编程复杂度高
  4. # 应用场景:用户需求经常变化,互联网应用,游戏,企业内部应用
  5.  
  6. # 类就是一系列对象相似的特征与技能的结合体 强调:站在不同的角度,得到的分类是不一样的
  7. # 另外在现实世界中一定先有对象,后有类; 在程序中一定得先定义类,后调用类来产生对象
  8.  
  9. # 先定义类
  10. class Student:
  11. # 特征:
  12. school = 'luffycity'
  13.  
  14. # 技能:
  15. def learn(self):
  16. print('is learning')
  17.  
  18. def eat(self):
  19. print('is sleeping')
  20.  
  21. # 后产生对象
  22. stu1 = Student()
  23. stu2 = Student()
  24. stu3 = Student()
  25.  
  26. print(stu1)
  27. print(stu2)
  28. 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. print(Student.__dict__)
  15. print(Student.__dict__['school'])
  16. print(Student.__dict__['learn'])
  17. print(Student.__dict__['eat'])
  18.  
  19. # 查
  20. print(Student.school) # Student.__dict__['school']
  21. print(Student.learn) # Student.__dict__['learn']
  22. print(Student.eat) # Student.__dict__['eat']
  23.  
  24. # 增
  25. Student.county = 'China'
  26. print(Student.__dict__)
  27. print(Student.county)
  28.  
  29. # 删
  30. del Student.county
  31.  
  32. # 改
  33. 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. stu1 = Student('王二丫', '女', 18) # Student.__init__(stu1,'王二丫','女',18)
  19.  
  20. # __init__方法后实例化的步骤:
  21. # 1、先产生一个空对象stu1
  22. # 2、Student.__init__(stu1,'王二丫','女',18)
  23.  
  24. # 对象的操作:
  25. # 查
  26. print(stu1.__dict__)
  27.  
  28. # 改
  29. stu1.Name = '李二丫'
  30. print(stu1.__dict__)
  31.  
  32. # 删除
  33. del stu1.Name
  34. print(stu1.__dict__)
  35.  
  36. # 增
  37. stu1.class_name = 'python开发'
  38. 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. stu1 = Student('王二丫', '女', 18)
  17. stu2 = Student('李三炮', '男', 38)
  18. stu3 = Student('张铁蛋', '男', 48)
  19.  
  20. # 对象:特征与技能的结合体
  21. # 类:类是一系列对象相似的特征与相似的技能的结合体
  22. # 类中的数据属性是所有对象共有的
  23. print(Student.school, id(Student.school))
  24. print(stu1.school, id(stu1.school))
  25. print(stu2.school, id(stu2.school))
  26. print(stu3.school, id(stu3.school))
  27. # 类中的函数属性:是绑定给对象使用的,绑定到不同的对象是不同的绑定方法,对象调用绑定方式时,会把对象本身当作第一个传入,传给self
  28. print(Student.learn)
  29. stu1.learn() # 调用对象的learn方法
  30. stu2.learn()
  31. stu3.learn()
  32.  
  33. print(stu1.eat)
  34. stu1.eat("包子") # eat(stu1, "包子")
  35. print(stu2.eat)
  36. 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. def exc2(host, port, db, charset, proc_name)
  8. conn = connect(host, port, db, charset)
  9. conn.call_proc(sql)
  10. return xxx
  11.  
  12. # 每次调用都需要重复传入一堆参数
  13. exc1('127.0.0.1', 3306, 'db1', 'utf8', 'select * from tb1;')
  14. exc2('127.0.0.1', 3306, 'db1', 'utf8', '存储过程的名字')
  15.  
  16. # 2、我们能想到的解决方法是,把这些变量都定义成全局变量
  17. HOST = '127.0.0.1'
  18. PORT = 3306
  19. DB = 'db'
  20. CHARSET = 'utf8'
  21.  
  22. def exc1(host, port, db, charset):
  23. conn = connect(host, port, db, charset)
  24. conn.execute(sql)
  25. return xxx
  26.  
  27. def exc2(host, port, db, charset, proc_name)
  28. conn = connect(host, port, db, charset)
  29. conn.call_proc(sql)
  30. return xxx
  31.  
  32. exc1(HOST, PORT, DB, CHARSET, 'select * from tb1;')
  33. exc2(HOST, PORT, DB, CHARSET, '存储过程的名字')
  34.  
  35. # 3、但是2的解决方法也是有问题的,按照2的思路,我们将会定义一大堆全局变量,这些全局变量并没有做任何区分,即能够被所有功能使用,
  36. # 然而事实上只有HOST,PORT,DB,CHARSET是给exc1和exc2这两个功能用的。言外之意:我们必须找出一种能够将数据与操作数据的方法组合
  37. # 到一起的解决方法,这就是我们说的类了
  38.  
  39. class MySQLHandler:
  40. def __init__(self, host, port, db, charset='utf8'):
  41. self.host = host
  42. self.port = port
  43. self.db = db
  44. self.charset = charset
  45.  
  46. def exc1(self, sql):
  47. conn = connect(self.host, self.port, self.db, self.charset)
  48. res = conn.execute(sql)
  49. return res
  50.  
  51. def exc2(self, sql):
  52. conn = connect(self.host, self.port, self.db, self.charset)
  53. res = conn.call_proc(sql)
  54. return res
  55.  
  56. obj = MySQLHandler('127.0.0.1', 3306, 'db1')
  57. obj.exc1('select * from tb1;')
  58. obj.exc2('存储过程的名字')
  59.  
  60. # 改进
  61. class MySQLHandler:
  62. def __init__(self, host, port, db, charset='utf8'):
  63. self.host = host
  64. self.port = port
  65. self.db = db
  66. self.charset = charset
  67. self.conn = connect(self.host, self.port, self.db, self.charset)
  68.  
  69. def exc1(self, sql):
  70. return self.conn.execute(sql)
  71.  
  72. def exc2(self, sql):
  73. return self.conn.call_proc(sql)
  74.  
  75. obj = MySQLHandler('127.0.0.1', 3306, 'db1')
  76. obj.exc1('select * from tb1;')
  77. obj.exc2('存储过程的名字')

(2)练习1

  1. # 练习1:编写一个学生类,产生一堆学生对象
  2. # 要求: 有一个计数器(属性),统计总共实例了多少个对象
  3.  
  4. class Student:
  5. school = 'luffycity'
  6. count = 0
  7.  
  8. def __init__(self, name, age, sex):
  9. self.name = name
  10. self.age = age
  11. self.sex = sex
  12. Student.count += 1 # 等价于self.count+=1
  13.  
  14. def learn(self):
  15. print('%s is learing' % self.name)
  16.  
  17. stu1 = Student('alex', 'male', 38)
  18. stu2 = Student('jinxing', 'female', 78)
  19. stu3 = Student('egon', 'male', 18)
  20.  
  21. print(Student.count)
  22. print(stu1.count)
  23. print(stu2.count)
  24. print(stu3.count)
  25. print(stu1.__dict__)
  26. print(stu2.__dict__)
  27. print(stu3.__dict__)

(3)练习2

  1. # 练习2:模仿LoL定义两个英雄类
  2. # 要求:
  3. # 英雄需要有昵称、攻击力、生命值等属性;
  4. # 实例化出两个英雄对象;
  5. # 英雄之间可以互殴,被殴打的一方掉血,血量小于0则判定为死亡。
  6.  
  7. class Garen:
  8. camp = 'Demacia'
  9.  
  10. def __init__(self, nickname, life_value, aggresivity):
  11. self.nickname = nickname
  12. self.life_value = life_value
  13. self.aggresivity = aggresivity
  14.  
  15. def attack(self, enemy):
  16. enemy.life_value -= self.aggresivity
  17.  
  18. class Riven:
  19. camp = 'Noxus'
  20.  
  21. def __init__(self, nickname, life_value, aggresivity):
  22. self.nickname = nickname
  23. self.life_value = life_value
  24. self.aggresivity = aggresivity
  25.  
  26. def attack(self, enemy):
  27. enemy.life_value -= self.aggresivity
  28.  
  29. # 用类实例化对象
  30. g1 = Garen('草丛伦', 100, 30)
  31. r1 = Riven('可爱的锐雯雯', 80, 50)
  32.  
  33. print(r1.life_value)
  34. g1.attack(r1)
  35. 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. 只在python2中才分新式类和经典类,python3中统一都是新式类
  16. python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
  17. python2中,显式地声明继承object的类,以及该类的子类,都是新式类
  18. python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类
  19.  
  20. 提示:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现
  21.  
  22. # 上面练习2可以用继承重写:
  23. class Hero:
  24. x=3
  25. def __init__(self,nickname,life_value,aggresivity):
  26. self.nickname=nickname
  27. self.life_value=life_value
  28. self.aggresivity=aggresivity
  29. def attack(self,enemy):
  30. enemy.life_value-=self.aggresivity
  31.  
  32. class Garen(Hero):
  33. pass
  34.  
  35. class Riven(Hero):
  36. pass
  37.  
  38. g1=Garen('刚们',29,30)
  39. print(g1.nickname,g1.life_value,g1.aggresivity)
  40. g1.x=1
  41. print(g1.x)
  42.  
  43. # 属性查找小练习:
  44. # 一切属性查找均从对象开始查找,找不到就向上找父类
  45. class Foo:
  46. def f1(self):
  47. print('from Foo.f1')
  48.  
  49. def f2(self):
  50. print('from Foo.f2')
  51. self.f1() #b.f1()
  52.  
  53. class Bar(Foo):
  54. def f1(self):
  55. print('from Bar.f1')
  56.  
  57. b=Bar()
  58. # print(b.__dict__)
  59. 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. class Garen(Hero):
  11. camp = 'Demacia'
  12.  
  13. def attack(self, enemy):
  14. print('from Garen Class')
  15.  
  16. class Riven(Hero):
  17. camp = 'Noxus'
  18.  
  19. def __init__(self, nickname, aggressivity, life_value, skin):
  20. Hero.__init__(self, nickname, aggressivity, life_value) # 调用父类功能
  21. self.skin = skin # 新属性
  22.  
  23. def attack(self, enemy): # 在自己这里定义新的attack,不再使用父类的attack,且不会影响父类
  24. Hero.attack(self, enemy) # 调用功能
  25. print('from riven')
  26.  
  27. def fly(self): # 在自己这里定义新的
  28. print('%s is flying' % self.nickname)
  29.  
  30. g = Garen('草丛伦', 100, 30)
  31. r = Riven('锐雯雯', 80, 50, '比基尼')
  32. # print(g.camp)
  33. # g.attack(r)
  34. # print(r.life_value)
  35. 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. # 在python3中-》新式类:一个类没有继承object类,默认就继承object
  20. # class Foo():
  21. # pass
  22. # print(Foo.__bases__)

多继承的测试代码:

  1. # 验证多继承情况下的属性查找:
  2. class A:
  3. # def test(self):
  4. # print('from A')
  5. pass
  6.  
  7. class B(A):
  8. # def test(self):
  9. # print('from B')
  10. pass
  11.  
  12. class C(A):
  13. # def test(self):
  14. # print('from C')
  15. pass
  16.  
  17. class D(B):
  18. # def test(self):
  19. # print('from D')
  20. pass
  21.  
  22. class E(C):
  23. # def test(self):
  24. # print('from E')
  25. pass
  26.  
  27. class F(D, E):
  28. # def test(self):
  29. # print('from F')
  30. pass
  31.  
  32. # F,D,B,E,C,A
  33.  
  34. print(F.mro())
  35. f = F()
  36. 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. class Garen(Hero):
  10. camp='Demacia'
  11.  
  12. def __init__(self,nickname,life_value,aggresivity,weapon):
  13. # self.nickname=nickname
  14. # self.life_value=life_value
  15. # self.aggresivity=aggresivity
  16. Hero.__init__(self,nickname,life_value,aggresivity)
  17.  
  18. self.weapon=weapon
  19.  
  20. def attack(self,enemy):
  21. Hero.attack(self,enemy) # 指名道姓
  22. print('from Garen Class')
  23.  
  24. g=Garen('草丛伦',100,30,'金箍棒')
  25. 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. class Garen(Hero):
  10. camp='Demacia'
  11.  
  12. def __init__(self,nickname,life_value,aggresivity,weapon):
  13. # self.nickname=nickname
  14. # self.life_value=life_value
  15. # self.aggresivity=aggresivity
  16.  
  17. # super(Garen,self).__init__(nickname,life_value,aggresivity)
  18. super().__init__(nickname,life_value,aggresivity)
  19. self.weapon=weapon
  20.  
  21. def attack(self,enemy):
  22. Hero.attack(self,enemy) # 指名道姓
  23. print('from Garen Class')
  24.  
  25. g=Garen('草丛伦',100,30,'金箍棒')
  26. print(g.__dict__)

(3)思考

  1. class A:
  2. def f1(self):
  3. print('from A')
  4. super().f1()
  5.  
  6. class B:
  7. def f1(self):
  8. print('from B')
  9.  
  10. class C(A, B):
  11. pass
  12.  
  13. print(C.mro())
  14. # [<class '__main__.C'>,
  15. # <class '__main__.A'>,
  16. # <class '__main__.B'>,
  17. # <class 'object'>]
  18.  
  19. c = C()
  20. 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. class Teacher(People):
  10. def __init__(self, name, age, sex, level, salary, ):
  11. super().__init__(name, age, sex)
  12.  
  13. self.level = level
  14. self.salary = salary
  15.  
  16. def teach(self):
  17. print('%s is teaching' % self.name)
  18.  
  19. class Student(People):
  20. def __init__(self, name, age, sex, class_time, ):
  21. super().__init__(name, age, sex)
  22. self.class_time = class_time
  23.  
  24. def learn(self):
  25. print('%s is learning' % self.name)
  26.  
  27. class Course:
  28. def __init__(self, course_name, course_price, course_period):
  29. self.course_name = course_name
  30. self.course_price = course_price
  31. self.course_period = course_period
  32.  
  33. def tell_info(self):
  34. print('课程名<%s> 课程价钱<%s> 课程周期<%s>' % (self.course_name, self.course_price, self.course_period))
  35.  
  36. class Date:
  37. def __init__(self, year, mon, day):
  38. self.year = year
  39. self.mon = mon
  40. self.day = day
  41.  
  42. def tell_info(self):
  43. print('%s-%s-%s' % (self.year, self.mon, self.day))
  44.  
  45. # 实例化对象
  46. teacher1 = Teacher('alex', 18, 'male', 10, 3000, )
  47. teacher2 = Teacher('egon', 28, 'male', 30, 3000, )
  48. python = Course('python', 3000, '3mons')
  49. linux = Course('linux', 2000, '4mons')
  50.  
  51. # 组合实例:
  52. # 设置教师课程
  53. teacher1.course = python
  54. teacher2.course = python
  55. print(teacher1.course)
  56. print(teacher2.course)
  57. print(teacher1.course.course_name)
  58. print(teacher2.course.course_name)
  59. teacher1.course.tell_info()
  60.  
  61. # 实例化学生对象并设置学生课程
  62. student1 = Student('张三', 28, 'female', '08:30:00')
  63. student1.course1 = python
  64. student1.course2 = linux
  65. student1.course1.tell_info()
  66. student1.course2.tell_info()
  67. student1.courses = []
  68. student1.courses.append(python)
  69. student1.courses.append(linux)
  70.  
  71. # 实例化学生对象并设置学生生日及学生课程
  72. student1 = Student('张三', 28, 'female', '08:30:00')
  73. d = Date(1988, 4, 20)
  74. python = Course('python', 3000, '3mons')
  75. student1.birh = d
  76. student1.birh.tell_info()
  77. student1.course = python
  78. 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. # Pig.java:猪”的类设计,实现了IAnnimal接口
  18. package com.oo.demo;
  19. public class Pig implements IAnimal{ //如下每个函数都需要详细实现
  20. public void eat(){
  21. System.out.println("Pig like to eat grass");
  22. }
  23.  
  24. public void run(){
  25. System.out.println("Pig run: front legs, back legs");
  26. }
  27.  
  28. public void sleep(){
  29. System.out.println("Pig sleep 16 hours every day");
  30. }
  31.  
  32. public void speak(){
  33. System.out.println("Pig can not speak"); }
  34. }
  35.  
  36. # Person2.java
  37. /*
  38. *实现了IAnimal的“人”,有几点说明一下:
  39. * 1)同样都实现了IAnimal的接口,但“人”和“猪”的实现不一样,为了避免太多代码导致影响阅读,这里的代码简化成一行,但输出的内容不一样,实际项目中同一接口的同一功能点,不同的类实现完全不一样
  40. * 2)这里同样是“人”这个类,但和前面介绍类时给的类“Person”完全不一样,这是因为同样的逻辑概念,在不同的应用场景下,具备的属性和功能是完全不一样的 */
  41.  
  42. package com.oo.demo;
  43. public class Person2 implements IAnimal {
  44. public void eat(){
  45. System.out.println("Person like to eat meat");
  46. }
  47.  
  48. public void run(){
  49. System.out.println("Person run: left leg, right leg");
  50. }
  51.  
  52. public void sleep(){
  53. System.out.println("Person sleep 8 hours every dat");
  54. }
  55.  
  56. public void speak(){
  57. System.out.println("Hellow world, I am a person");
  58. }
  59. }
  60.  
  61. # Tester03.java
  62. package com.oo.demo;
  63.  
  64. public class Tester03 {
  65. public static void main(String[] args) {
  66. System.out.println("===This is a person===");
  67. IAnimal person = new Person2();
  68. person.eat();
  69. person.run();
  70. person.sleep();
  71. person.speak();
  72.  
  73. System.out.println("\n===This is a pig===");
  74. IAnimal pig = new Pig();
  75. pig.eat();
  76. pig.run();
  77. pig.sleep();
  78. pig.speak();
  79. }
  80. }

java中的接口(Interface)

注: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. class Animal(metaclass=abc.ABCMeta): # 只能被继承,不能被实例化
  5. all_type = 'animal'
  6.  
  7. @abc.abstractmethod # 被装饰的方法必须被子类重写
  8. def run(self):
  9. pass
  10.  
  11. @abc.abstractmethod
  12. def eat(self):
  13. pass
  14.  
  15. # animal=Animal() -》 该代码无法运行会报错
  16.  
  17. class People(Animal):
  18. def run(self):
  19. print('people is running')
  20.  
  21. def eat(self):
  22. print('people is eating')
  23.  
  24. class Pig(Animal):
  25. def run(self):
  26. print('people is walking')
  27.  
  28. def eat(self):
  29. print('people is eating')
  30.  
  31. class Dog(Animal):
  32. def run(self):
  33. print('people is walking')
  34.  
  35. def eat(self):
  36. print('people is eating')
  37.  
  38. peo1 = People()
  39. pig1 = Pig()
  40. dog1 = Dog()
  41.  
  42. peo1.eat()
  43. pig1.eat()
  44. dog1.eat()
  45.  
  46. print(peo1.all_type)

(3)多态与多态性

多态详细解释: http://www.cnblogs.com/linhaifeng/articles/7340687.html

  1. # 多态:同一类事物的多种形态
  2. import abc
  3.  
  4. class Animal(metaclass=abc.ABCMeta): # 同一类事物:动物
  5. @abc.abstractmethod
  6. def talk(self):
  7. pass
  8.  
  9. class People(Animal): # 动物的形态之一:人
  10. def talk(self):
  11. print('say hello')
  12.  
  13. class Dog(Animal): # 动物的形态之二:狗
  14. def talk(self):
  15. print('say wangwang')
  16.  
  17. class Pig(Animal): # 动物的形态之三:猪
  18. def talk(self):
  19. print('say aoao')
  20.  
  21. class Cat(Animal):
  22. def talk(self):
  23. print('say miamiao')
  24.  
  25. # 多态性:指的是可以在不考虑对象的类型的情况下而直接使用对象
  26. peo1 = People()
  27. dog1 = Dog()
  28. pig1 = Pig()
  29. cat1 = Cat()
  30.  
  31. peo1.talk()
  32. dog1.talk()
  33. pig1.talk()
  34.  
  35. def func(animal):
  36. animal.talk()
  37.  
  38. func(peo1)
  39. func(pig1)
  40. func(dog1)
  41. 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. print(A.__dict__)
  16. # 接下来的两句都会报错:
  17. # print(A.__x)
  18. # print(A.__foo)
  19.  
  20. a = A('egon')
  21. print(a._A__x)
  22. print(a._A__foo())
  23.  
  24. # 接下来这句也会报错:
  25. # print(a.__name) # a.__dict__['__name']
  26. print(a.__dict__)
  27.  
  28. a.bar()
  29.  
  30. # python实际上是通过使用变形来让这些属性无法被直接访问
  31. # 这种变形的特点:
  32. # 1、在类外部无法直接obj.__AttrName
  33. # 2、在类内部是可以直接使用:obj.__AttrName
  34. # 3、子类无法覆盖父类__开头的属性
  35. # 4、这种变形在类定义的阶段就会生成
  36.  
  37. # 子类无法覆盖父类__开头的属性:
  38. class Foo:
  39. def __func(self): #_Foo__func
  40. print('from foo')
  41.  
  42. class Bar(Foo):
  43. def __func(self): #_Bar__func
  44. print('from bar')
  45.  
  46. b=Bar()
  47. b.func()
  48.  
  49. # 这种变形需要注意的问题是:
  50. # (1)这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N,
  51. # 即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形,主要用来限制外部的直接访问
  52. # (2)变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
  53. # (3)在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有
  54.  
  55. class B:
  56. __x = 1
  57.  
  58. def __init__(self, name):
  59. self.__name = name # self._B__name=name
  60.  
  61. # 验证问题一:
  62. print(B._B__x)
  63.  
  64. # 验证问题二:
  65. B.__y = 2
  66. print(B.__dict__)
  67. b = B('egon')
  68. print(b.__dict__)
  69.  
  70. b.__age = 18
  71. print(b.__dict__)
  72. print(b.__age)
  73.  
  74. # 验证问题三:
  75. class A:
  76. def foo(self):
  77. print('A.foo')
  78.  
  79. def bar(self):
  80. print('A.bar')
  81. self.foo() # self.foo() -> b.foo()
  82.  
  83. class B(A):
  84. def foo(self):
  85. print('B.foo')
  86.  
  87. b = B()
  88. b.bar()
  89.  
  90. class A:
  91. def __foo(self): # _A__foo
  92. print('A.foo')
  93.  
  94. def bar(self):
  95. print('A.bar')
  96. self.__foo() # self._A__foo()
  97.  
  98. class B(A):
  99. def __foo(self): # _B__foo
  100. print('B.foo')
  101.  
  102. b = B()
  103. 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. # 外部对姓名和年龄的操作只能通过tell_info和set_info这两个函数实现
  21. p = People('wyb', 21)
  22. p.tell_info()
  23. p.set_info('woz', 22)
  24. p.tell_info()
  25.  
  26. # 二、 封装方法:隔离复杂度
  27. # 取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
  28. # 对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
  29. # 隔离了复杂度,同时也提升了安全性
  30. class ATM:
  31. def __card(self):
  32. print('插卡')
  33.  
  34. def __auth(self):
  35. print('用户认证')
  36.  
  37. def __input(self):
  38. print('输入取款金额')
  39.  
  40. def __print_bill(self):
  41. print('打印账单')
  42.  
  43. def __take_money(self):
  44. print('取款')
  45.  
  46. def withdraw(self):
  47. self.__card()
  48. self.__auth()
  49. self.__input()
  50. self.__print_bill()
  51. self.__take_money()
  52.  
  53. a = ATM()
  54. 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. p = BMI('egon', 75, 1.81)
  23. print(p.bmi)
  24. p.height = 1.82
  25. print(p.bmi)
  26. # p.bmi=3333 # 报错AttributeError: can't set attribute
  27.  
  28. class People:
  29. def __init__(self, name):
  30. self.__name = name
  31.  
  32. @property # 像访问数据一样调用类中函数
  33. def name(self):
  34. # print('getter')
  35. return self.__name
  36.  
  37. @name.setter # 设置值操作
  38. def name(self, val):
  39. # print('setter',val)
  40. if not isinstance(val, str):
  41. print('名字必须是字符串类型')
  42. return
  43. self.__name = val
  44.  
  45. @name.deleter # 删除值操作
  46. def name(self):
  47. # print('deleter')
  48. print('不允许删除')
  49.  
  50. p = People('egon')
  51. print(p.name)
  52. p.name = 'wyb'
  53. print(p.name)
  54. p.name = 123
  55. 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. # p.tell_info() # tell_info(p)
  30.  
  31. # 绑定给类,就应该由类来调用,自动将类本身当作第一个参数传入
  32. # p=People.from_conf() # from_conf(People)
  33. # p.tell_info()
  34.  
  35. # 非绑定方法,不与类或者对象绑定,谁都可以调用,没有自动传值一说
  36. p1 = People('egon1', 18, 'male')
  37. p2 = People('egon2', 28, 'male')
  38. p3 = People('egon3', 38, 'male')
  39. print(p1.id)
  40. print(p2.id)
  41. 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. class Service:
  33. def run(self):
  34. while True:
  35. inp = input('>>: ').strip() # cmd='get a.txt'
  36. cmds = inp.split() # cmds=['get','a.txt']
  37. if hasattr(self, cmds[0]):
  38. func = getattr(self, cmds[0]) # 获得绑定方法
  39. func(cmds) # 调用绑定方法
  40.  
  41. def get(self, cmds):
  42. print('get.......', cmds)
  43.  
  44. def put(self, cmds):
  45. print('put.......', cmds)
  46.  
  47. obj = Service()
  48. 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. # 可以把exec命令的执行当成是一个函数的执行,会将执行期间产生的名字存放于局部名称空间中
  7. # 实例如下:
  8. g={
  9. 'x':1,
  10. 'y':2
  11. }
  12. l={}
  13.  
  14. exec('''
  15. global x,z
  16. x=100
  17. z=200
  18.  
  19. m=300
  20. ''',g,l)
  21.  
  22. print(g) # {'x': 100, 'y': 2,'z':200,......}
  23. 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. class Chinese(object, metaclass=Mymeta):
  13. """
  14. 一个基于自定义元类生成的类,类名首字母必须大写并且必须有注释,且注释不能为空
  15. """
  16. country = 'China'
  17.  
  18. def __init__(self, namem, age):
  19. self.name = namem
  20. self.age = age
  21.  
  22. def talk(self):
  23. print('%s is talking' % self.name)
  24.  
  25. # 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. class Mymeta(type):
  15. def __init__(self, class_name, class_bases, class_dic):
  16. if not class_name.istitle():
  17. raise TypeError('类名的首字母必须大写')
  18.  
  19. if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
  20. raise TypeError('必须有注释,且注释不能为空')
  21.  
  22. super(Mymeta, self).__init__(class_name, class_bases, class_dic)
  23.  
  24. def __call__(self, *args, **kwargs): # obj=Chinese('wyb',age=20)
  25. # print(self) # self=Chinese
  26. # print(args) # args=('wyb',)
  27. # print(kwargs) # kwargs={'wyb': 20}
  28.  
  29. # 第一件事:先造一个空对象obj
  30. obj = object.__new__(self)
  31. # 第二件事:初始化obj
  32. self.__init__(obj, *args, **kwargs)
  33. # 第三件事:返回obj
  34. return obj
  35.  
  36. class Chinese(object, metaclass=Mymeta):
  37. '''
  38. 中文人的类
  39. '''
  40. country = 'China'
  41.  
  42. def __init__(self, namem, age):
  43. self.name = namem
  44. self.age = age
  45.  
  46. def talk(self):
  47. print('%s is talking' % self.name)
  48.  
  49. obj = Chinese('wyb', age=20) # Chinese.__call__(Chinese,'wyb',20)
  50. 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. obj1 = MySQL.singleton()
  24. obj2 = MySQL.singleton()
  25. obj3 = MySQL.singleton()
  26. print(obj1 is obj2 is obj3)
  27.  
  28. # 实现方式二:元类的方式
  29. class Mymeta(type):
  30. def __init__(self, class_name, class_bases, class_dic):
  31. if not class_name.istitle():
  32. raise TypeError('类名的首字母必须大写')
  33.  
  34. if '__doc__' not in class_dic or not class_dic['__doc__'].strip():
  35. raise TypeError('必须有注释,且注释不能为空')
  36.  
  37. super(Mymeta, self).__init__(class_name, class_bases, class_dic)
  38. self.__instance = None
  39.  
  40. def __call__(self, *args, **kwargs): # obj=Chinese('egon',age=18)
  41. if not self.__instance:
  42. obj = object.__new__(self)
  43. self.__init__(obj)
  44. self.__instance = obj
  45.  
  46. return self.__instance
  47.  
  48. class Mysql(object, metaclass=Mymeta):
  49. '''
  50. mysql xxx
  51. '''
  52.  
  53. def __init__(self):
  54. self.host = '127.0.0.1'
  55. self.port = 3306
  56.  
  57. def conn(self):
  58. pass
  59.  
  60. def execute(self):
  61. pass
  62.  
  63. obj1 = Mysql()
  64. obj2 = Mysql()
  65. obj3 = Mysql()
  66.  
  67. print(obj1 is obj2 is obj3)

7.异常处理复习总结

  1. # 什么是异常:异常是错误发生的信号,一旦程序出错,并且程序没有处理这个错误,那个就会抛出异常,并且程序的运行随之终止
  2.  
  3. # 错误分为两种:
  4. # 语法错误: 使程序无法执行,在程序执行前就要立刻改正过来
  5. # print('xxxx'
  6. # if 1 > 2
  7. # 逻辑错误: 程序逻辑上的错误,在程序运行时才会出现
  8. #ValueError
  9. # int('aaa')
  10. #NameError
  11. # name
  12. #IndexError
  13. # l=[1,2,3]
  14. # l[1000]
  15. #KeyError
  16. # d={}
  17. # d['name']
  18. #AttributeError
  19. # class Foo:
  20. # pass
  21. #
  22. # Foo.xxx
  23. #ZeroDivisionError:
  24. # 1/0
  25. #TypeError:int类型不可迭代
  26. # for i in 3:
  27. # pass
  28.  
  29. # 异常
  30. # 强调一:错误发生的条件如果是可以预知的,此时应该用if判断去预防异常
  31. # AGE=10
  32. # age=input('>>: ').strip()
  33. #
  34. # if age.isdigit():
  35. # age=int(age)
  36. # if age > AGE:
  37. # print('太大了')
  38.  
  39. # 强调二:错误发生的条件如果是不可预知的,此时应该用异常处理机制,try...except
  40. try:
  41. f=open('a.txt','r',encoding='utf-8')
  42.  
  43. print(next(f),end='')
  44. print(next(f),end='')
  45. print(next(f),end='')
  46. print(next(f),end='')
  47.  
  48. print(next(f),end='')
  49. print(next(f),end='')
  50. print(next(f),end='')
  51.  
  52. f.close()
  53. except StopIteration:
  54. print('出错啦')
  55.  
  56. print('====>1')
  57. print('====>2')
  58. 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. # 万能异常:Exception,被监测的代码块抛出的异常有多种可能性,
  25. # 并且我们针对所有的异常类型都只用一种处理逻辑就可以了,那就使用Exception
  26. # try:
  27. # print('===>1')
  28. # # name
  29. # print('===>2')
  30. # l=[1,2,3]
  31. # l[100]
  32. # print('===>3')
  33. # d={}
  34. # d['name']
  35. # print('===>4')
  36. #
  37. # except Exception as e:
  38. # print('异常发生啦:',e)
  39. #
  40. # print('====>afer code')
  41.  
  42. # try:
  43. # print('===>1')
  44. # # name
  45. # print('===>2')
  46. # l=[1,2,3]
  47. # # l[100]
  48. # print('===>3')
  49. # d={}
  50. # d['name']
  51. # print('===>4')
  52. #
  53. # except NameError as e:
  54. # print('--->',e)
  55. #
  56. # except IndexError as e:
  57. # print('--->',e)
  58. #
  59. # except KeyError as e:
  60. # print('--->',e)
  61. #
  62. # except Exception as e:
  63. # print('统一的处理方法')
  64. #
  65. # print('====>afer code')
  66.  
  67. # 其他结构
  68. # try:
  69. # print('===>1')
  70. # # name
  71. # print('===>2')
  72. # l=[1,2,3]
  73. # # l[100]
  74. # print('===>3')
  75. # d={}
  76. # d['name']
  77. # print('===>4')
  78. #
  79. # except NameError as e:
  80. # print('--->',e)
  81. #
  82. # except IndexError as e:
  83. # print('--->',e)
  84. #
  85. # except KeyError as e:
  86. # print('--->',e)
  87. #
  88. # except Exception as e:
  89. # print('统一的处理方法')
  90. #
  91. # else: # 在被检测的代码块没有发生异常时执行
  92. # pass
  93. #
  94. # finally: # 不管被检测的代码块有无发生异常都会执行
  95. # pass
  96. #
  97. # print('====>afer code')
  98.  
  99. # 主动触发异常:raise 异常类型(值)
  100. # class People:
  101. # def __init__(self,name,age):
  102. # if not isinstance(name,str):
  103. # raise TypeError('名字必须传入str类型')
  104. # if not isinstance(age,int):
  105. # raise TypeError('年龄必须传入int类型')
  106. #
  107. # self.name=name
  108. # self.age=age
  109. #
  110. # p=People('egon',18)
  111.  
  112. # 自定义异常类型
  113. # class MyException(BaseException):
  114. # def __init__(self, msg):
  115. # super(MyException, self).__init__()
  116. # self.msg = msg
  117. #
  118. # def __str__(self):
  119. # return '<%s>' % self.msg
  120. #
  121. #
  122. # raise MyException('我自己的异常类型') # print(obj)
  123.  
  124. # 断言assert
  125. # info={}
  126. # info['name']='egon'
  127. # # info['age']=18
  128. #
  129. # # if 'name' not in info:
  130. # # raise KeyError('必须有name这个key')
  131. # #
  132. # # if 'age' not in info:
  133. # # raise KeyError('必须有age这个key')
  134. #
  135. # assert ('name' in info) and ('age' in info)
  136. #
  137. # if info['name'] == 'egon' and info['age'] > 10:
  138. # print('welcome')

try-except详细用法

python面向对象重新梳理的更多相关文章

  1. ~~番外:说说Python 面向对象编程~~

    进击のpython Python 是支持面向对象的 很多情况下使用面向对象编程会使得代码更加容易扩展,并且可维护性更高 但是如果你写的多了或者某一对象非常复杂了,其中的一些写法会相当相当繁琐 而且我们 ...

  2. Python面向对象之:三大特性:继承,封装,多态以及类的约束

    前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情 ...

  3. python 面向对象初级篇

    Python 面向对象(初级篇) 概述 面向过程:根据业务逻辑从上到下写垒代码 函数式:将某功能代码封装到函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类和封装,让开发" ...

  4. Python 面向对象 基础

    编程范式概述:面向过程 和 面向对象 以及函数式编程 面向过程:(Procedure Oriented)是一种以事件为中心的编程思想. 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现 ...

  5. python面向对象进阶(八)

    上一篇<Python 面向对象初级(七)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  6. python 面向对象(进阶篇)

    上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...

  7. python 面向对象编程学习

    1. 问题:将所有代码放入一个py文件:无法维护 方案:如果将代码才分放到多个py文件,好处: 1. 同一个名字的变量互相不影响 2.易于维护 3.引用模块: import module 2.包:解决 ...

  8. Python面向对象详解

    Python面向对象的"怜人之处" Python的待客之道--谁能进来 Python的封装--只给你想要的 Python的继承--到处认干爹 Python的多态--说是就是

  9. python 面向对象和类成员和异常处理

    python 面向对象 你把自己想象成一个上帝,你要创造一个星球,首先你要把它揉成一个个球,两个直径就能创造一个球 class star: '''名字(name),赤道直径(equatorial di ...

随机推荐

  1. 批量读取文件matlab

    前言 工程实现的过程中经常需要依次读取文件夹中的图像(或者其他文件),本文就对此进行实现. 代码 % /************************************************ ...

  2. MP算法、OMP算法及其在人脸识别的应用

    主要内容: 1.MP算法 2.OMP算法 3.OMP算法的matlab实现 4.OMP在压缩感知和人脸识别的应用 一.MP(Matching Pursuits)与OMP(Orthogonal Matc ...

  3. WinRAR备份技巧 - imsoft.cnblogs

    RAR控制台日常备份策略 run.batrar a -ep1 -agYYYY{年}MM{月}DD{日} 备份 @list.txt-ep1是忽略原文件路径,rar包里是一堆文件,没有目录结构-ag附加命 ...

  4. MySQL主从数据库配置

    使用工具 MySQL数据版本:5.6.36-log. 两台云服务器(Linux系统) 首先,需要在Linux系统下安装MySQL,具体步骤可以参考这里,并且确保两台主机可以相互访问,可以直接ping一 ...

  5. Codeforces gym101955 A【树形dp】

    LINK 有n个大号和m个小号 然后需要对这些号进行匹配,一个大号最多匹配2个小号 匹配条件是大号和小号构成了前缀关系 字符串长度不超过10 问方案数 思路 因为要构成前缀关系 所以就考虑在trie树 ...

  6. ACCESS不可识别的数据库格式!

    在Access07之前的数据库后缀名均为*.mdb 而连接字符串写成Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\myFolder\*.mdb ;Pe ...

  7. 前端jquery---表单验证

    重点: 1.表单的提交 2.触发blur事件 3.判断是否正确,提交与否 return False <!DOCTYPE html> <html lang="en" ...

  8. 【spring data jpa】好文储备

    [spring data jpa]带有条件的查询后分页和不带条件查询后分页实现  :  https://blog.csdn.net/lihuapiao/article/details/48782843 ...

  9. WC游记

    第一次来WC,感觉这种集训真吼啊 day0 火车上快速补习了莫队,和AC自动姬,AC自动姬以前就会写只不过太久没写忘了我会了= = 莫队只是学习了做法,还没有做过题…… 本来想再复习一下后缀数组,然后 ...

  10. 【正则表达式】java应用正则表达式

    一:简单应用 /** * * ' * & * ' * & * & * ' * ' * ' * sources=sdcg'hde&xyz'dfa&&ad' ...