重构父类__init__方法

  1. #!/usr/bin/env python3
  2. # author:Alnk(李成果)
  3. # 需求:Dog类要新增一个实例属性,但是Cat类不需要
  4. class Animal(object):
  5. def __init__(self, name, age):
  6. self.name = name
  7. self.age = age
  8. def run(self):
  9. print('run...')
  10. def sleep(self):
  11. print('sleep...')
  12. class Cat(Animal):
  13. pass
  14. class Dog(Animal):
  15. def __init__(self, name, age, kind):
  16. super().__init__(name, age) # 执行父类方法
  17. self.kind = kind
  18. t = Dog('tom', 23, '狗子')
  19. print(t.kind)
  20. c = Cat("jerry", 1)
  21. print(c.name)

封装

封装-基本概念

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. """
  4. 封装:是指隐藏对象的属性和实现细节,仅对外提供公共访问方式
  5. 好处:将变化隔离、便于使用、提高重用性、提高安全性
  6. 封装原则:将不需要对外提供的内容都隐藏起来、把属性都隐藏,提供公共方法对其访问
  7. 使用封装有好处:
  8. 1、良好的封装能够减少耦合
  9. 2、类内部的结构可以自由修改
  10. 3、可以对成员进行更精确的控制
  11. 4、隐藏信息,隐藏实现细节
  12. 用法:
  13. 私有化变量(属性)
  14. 私有化方法
  15. property属性
  16. classmethod方法
  17. staticmethod方法
  18. """

封装-实例私有属性

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 一般属性
  4. class Student(object):
  5. def __init__(self, name, age):
  6. self.name = name # 一般属性
  7. self.age = age
  8. t = Student('tom', 24)
  9. print(t.age) # 可以直接在类的外面访问
  10. print("----------------- 1 ----------------")
  11. # 私有化属性 __变量
  12. # 保护数据,不让类外部直接访问
  13. class Student(object):
  14. def __init__(self, name, age):
  15. self.__name = name # 实例私有属性:__变量
  16. self.__age = age
  17. def print_age(self):
  18. print('年龄:%s' % self.__age) # 私有化属性可以在类的内部访问
  19. t = Student('tom', 24)
  20. # print(t.age) # 不可以直接在类的外部访问
  21. # print(t.__dict__["_Student__age"]) # python中还是有方法可以访问实例的私有属性的
  22. t.print_age()
  23. print("----------------- 2 ----------------")
  24. # 需求:要在类的外部访问私有化属性。
  25. # 开接口:能在外部修改类的私有属性,但是能更加精确的控制
  26. # 好处:可以更加精确的控制数据
  27. class Student(object):
  28. def __init__(self, name, age):
  29. self.__name = name # 私有属性
  30. self.__age = age
  31. def get_age(self): # 提供可读属性接口
  32. return self.__age
  33. def set_age(self, new_age): # 提供可写属性接口
  34. if isinstance(new_age, int) and (0 < new_age < 120):
  35. self.__age = new_age
  36. else:
  37. # raise ValueError("年龄不符合条件") # 直接让程序报错,停止程序
  38. print("年龄不符合条件")
  39. t = Student('tom', 24)
  40. # 可读接口
  41. print(t.get_age())
  42. # 可写接口
  43. t.set_age(80)
  44. print(t.get_age())
  45. t.set_age(1000)
  46. print(t.get_age())

封装-实例私有属性存储关系

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 一般属性存储关系
  4. class Student(object):
  5. x = 100
  6. def __init__(self, name, age):
  7. self.name = name # 一般属性
  8. self.age = age
  9. tom = Student('tom', 24)
  10. print(tom.name) # tom
  11. # __dict__ 打印tom实例对象的所有变量
  12. print(tom.__dict__) # {'name': 'tom', 'age': 24}
  13. tom.sex = 'F'
  14. print(tom.__dict__) # {'name': 'tom', 'age': 24, 'sex': 'F'}
  15. print("----------------- 1 ----------------")
  16. # 实例私有属性存储关系
  17. class Student(object):
  18. def __init__(self, name, age):
  19. self.__name = name # 私有属性
  20. self.__age = age
  21. def get_age(self): # 提供可读属性接口
  22. return self.__age
  23. def set_age(self, new_age): # 提供可写属性接口
  24. if isinstance(new_age, int) and (0 < new_age < 120):
  25. self.__age = new_age
  26. else:
  27. print("年龄不符合条件")
  28. # 1 外部可以控制私有属性,强烈不建议使用,不规范
  29. tom = Student('tom', 24)
  30. print(tom.__dict__) # 私有属性 "_当前类名__私有变量":实际值 {'_Student__name': 'tom', '_Student__age': 24}
  31. tom.sex = 'F'
  32. print(tom.__dict__) # {'_Student__name': 'tom', '_Student__age': 24, 'sex': 'F'}
  33. # 直接访问私有属性
  34. print(tom._Student__name) # tom
  35. # 直接修改私有属性,但是不建议这么用,不规范,私有变量不建议更改
  36. # 结论:python的私有属性\变量并不是真正的私有属性\变量,还是有方法可以控制的。
  37. # 但是,不建议使用,不规范
  38. tom._Student__age = 10000
  39. print(tom.get_age()) # 10000
  40. print("----------------- 2 ----------------")
  41. # 2
  42. tom = Student('tom', 24)
  43. # 相当于在tom的实例内存空间追加了一个变量 __age = 1000
  44. tom.__age = 1000
  45. print(tom.__age) # 1000
  46. print(tom.__dict__) # {'_Student__name': 'tom', '_Student__age': 24, '__age': 1000}

封装-类私有属性

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 类属性的私有化
  4. # 私有属性不仅适用于实例属性,也适用于类属性
  5. # 一般类 属性\变量
  6. class Parent(object):
  7. x = 100 # 一般类 属性\变量
  8. def f1(self):
  9. pass
  10. p1 = Parent() # 实例化
  11. print(p1.x) # 100
  12. print(p1.__dict__) # {} 这里空字典的原因是:实例空间没有实例属性
  13. # 类对象
  14. print(Parent.x) # 100 类属性
  15. print(Parent.__dict__) # {..., 'x': 100, 'f1': <function Parent.f1 at 0x7fa1c92eca60>, ...}
  16. print("----------------- 1 ----------------")
  17. # 类 属性\变量 的私有化
  18. class Parent(object):
  19. __x = 100
  20. def f1(self):
  21. pass
  22. p1 = Parent()
  23. # print(p1.__x) # 类私有属性,外部不能直接访问
  24. # print(Parent.__x) # 类私有属性,外部不能直接访问
  25. print(Parent.__dict__) # {'_Parent__x': 100, 'f1': <function Parent.f1 at 0x7f9ed82e19d8>,}
  26. # 可以通过这种方法访问,但是强烈建议不要这么使用
  27. print(Parent._Parent__x) # 100
  28. print(Parent.__dict__["_Parent__x"]) # 100

封装-私有属性不能继承

  1. #!/usr/bin/env python3
  2. # author:Alnk(李成果)
  3. # 私有属性不能继承
  4. class A:
  5. __x = 100 # 类私有属性
  6. y = 200 # 类一般属性
  7. def __init__(self):
  8. self.__name = "alnk"
  9. self.age = 14
  10. class B(A):
  11. z = 300
  12. b = B()
  13. # 类一般属性的继承
  14. print(b.z) # 300
  15. print(b.y) # 200
  16. # 类私有属性不能继承
  17. # print(b.__x) # 报错 AttributeError: 'B' object has no attribute '__x'
  18. # 当然有其他方法也可以访问
  19. print(b._A__x) # 100 不建议这么做
  20. print("-------------- 1 ---------------------")
  21. # 实例一般属性的继承
  22. print(b.age) # 14
  23. # 实例私有属性不能继承
  24. # print(b.__name) # 报错 AttributeError: 'B' object has no attribute '__name'
  25. # 当然有其他方法也可以访问
  26. print(b._A__name) # alnk 不建议这么做

封装-下划线

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. """
  4. 单下划线、双下划线、头尾双下划线说明
  5. __foo__: 定义的是特殊方法,一般是系统定义名字 ,类似 __init__() 之类的
  6. _foo: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问(约定成俗,不限语法)
  7. __foo: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了
  8. 变量 public 公共的
  9. _变量 protected 受保护的
  10. __变量 private 私有的
  11. """
  12. class A(object):
  13. _x = 10
  14. __y = 20
  15. z = 30
  16. a = A()
  17. # 10 约定成俗,不限语法
  18. print(a._x) # 10
  19. print(a.z) # 30
  20. # print(a.__y) # 报错
  21. print(a._A__y) # 20
  22. print(a.__dict__) # 实例空间变量 {}
  23. print(A.__dict__) # 类空间变量 {'_x': 10, '_A__y': 20, 'z': 30}
  24. print(A.__dict__["_A__y"]) # 20

封装-私有方法不能继承

  1. #!/usr/bin/env python3
  2. # author:Alnk(李成果)
  3. # 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
  4. # 私有方法不能继承
  5. # 正常情况
  6. class A(object):
  7. def fa(self):
  8. print('from A')
  9. def test(self):
  10. self.fa()
  11. class B(A):
  12. pass
  13. b = B()
  14. b.fa() # from A
  15. b.test() # from A
  16. print("---------------- 1 -----------------------")
  17. # 把 fa 定义为私有的,即 __fa
  18. class A(object):
  19. def __fa(self): # 在定义的时候就变形为 _A__fa
  20. print('from A')
  21. def test(self):
  22. self.__fa() # 只会以自己所在的类为准,基调用 _A__fa
  23. class B(A):
  24. # def __fa(self):
  25. # print('from B')
  26. pass
  27. b = B()
  28. b.test() # from A
  29. # b.__fa() # 报错 AttributeError: 'B' object has no attribute '__fa'
  30. b._A__fa() # from A

封装-property属性

  1. #!/usr/bin/env python3
  2. # author:Alnk(李成果)
  3. # 什么是特性property
  4. # property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
  5. # 把一个方法属性化
  6. # 为什么要用property?
  7. # 将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,
  8. # 这种特性的使用方式遵循了统一访问的原则在C++里一般会将所有的数据都设置为私有的,
  9. # 然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现
  10. class People(object):
  11. def __init__(self, name, weight, height):
  12. self.name = name
  13. self.wight = weight
  14. self.height = height
  15. @property # 改变一个方法的调用方式
  16. def bmi(self):
  17. return self.wight / (self.height**2)
  18. def test(self):
  19. print("in test")
  20. p1 = People('tom', 75, 1.85)
  21. p1.test() # 正常的调用一个方法
  22. print(p1.bmi) # 改变一个方法的调用方式

封装-classmethod方法

  1. #!/usr/bin/env python3
  2. # author:Alnk(李成果)
  3. # classmethod 修饰符对应的函数不需要实例化,不需要 self 参数
  4. # 但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等
  5. class Student(object):
  6. school = '清华大学'
  7. def __init__(self, name, age):
  8. self.name = name
  9. self.age = age
  10. def run(self):
  11. print('%s is running... ' % self.name)
  12. @classmethod # 类方法
  13. def foo(cls):
  14. print(cls) # 和 Student 的内存地址相同
  15. print('cls', id(cls)) # 是同一个内存地址
  16. print("student", id(Student)) # 是同一个内存地址
  17. print('学校名称:%s' % cls.school)
  18. # 实例方法是由实例对象调用的,不能直接由类调用
  19. tom = Student('tom', 23)
  20. jerry = Student('jerry', 24)
  21. tom.run()
  22. jerry.run()
  23. # Student.run() # TypeError: run() missing 1 required positional argument: 'self'
  24. print("------------- 1 -------------------")
  25. # 类方法,可以直接由类调用
  26. Student.foo()
  27. print("------------- 2 -------------------")
  28. # 当然,实例也可以调用类方法
  29. tom.foo()

封装-staticmethod方法

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 实例方法: 涉及到实例变量的时候使用
  4. # 类方法classmethod: 涉及到类变量的时候使用
  5. # 静态方法staticmethod: 不涉及到类变量和实例变量的时候使用
  6. class Student(object):
  7. school = '清华大学'
  8. def __init__(self, name, age):
  9. self.name = name
  10. self.age = age
  11. # 一般方法
  12. def run(self):
  13. print('%s is running... ' % self.name)
  14. # 类方法
  15. @classmethod
  16. def foo(cls):
  17. print('学校名称:%s' % cls.school)
  18. # 静态方法
  19. @staticmethod
  20. def calculation(x, y): # 没有self了
  21. return x * y
  22. tom = Student('tom', 26)
  23. # 一 调用静态方法
  24. # 1,实例调用静态方法
  25. ret = tom.calculation(2, 8)
  26. print(ret)
  27. # 2,类调用静态方法
  28. ret1 = Student.calculation(3, 6) # 不需要传入self了
  29. print(ret1)
  30. print("---------------- 1 ----------------------")
  31. # 二 调用类方法
  32. Student.foo()
  33. tom.foo()
  34. print("---------------- 1 ----------------------")
  35. # 三 调用一般方法
  36. tom.run()
  37. # Student.run() # TypeError: run() missing 1 required positional argument: 'self'

归一化设计

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 归一化设计
  4. # 做成一个接口
  5. lis = [1, 2, 3]
  6. dic = {1: 2, 3: 4, 5: 6}
  7. s = 'hello'
  8. # 需求
  9. # 求一个序列对象的长度
  10. print(lis.__len__())
  11. print(dic.__len__())
  12. print(s.__len__())
  13. print("---------------- 1 ------------------------")
  14. # 归一接口:len()
  15. print(len(lis))
  16. print(len(dic))
  17. print(len(s))
  18. print("---------------- 2 ------------------------")
  19. # 支付接口归一化
  20. class Payment(object):
  21. def __init__(self, name, money):
  22. self.name = name
  23. self.money = money
  24. class AliPay(Payment):
  25. def pay(self):
  26. print('%s通过支付宝消费了%s元' % (self.name, self.money))
  27. class WeChatPay(Payment):
  28. def pay(self):
  29. print('%s通过微信消费了%s元' % (self.name, self.money))
  30. def pay_func(pay_obj): # 接口归一
  31. pay_obj.pay()
  32. a = AliPay('tom', 100)
  33. w = WeChatPay('jerry', 200)
  34. # 调用归一接口
  35. pay_func(a)
  36. pay_func(w)
  37. print("---------------- 3 ------------------------")
  38. # 支付接口归一化,规范的写法
  39. """
  40. 规范化方法
  41. 支付宝 微信 银行卡 nfc支付
  42. 同事协作之间的代码规范问题
  43. 规定: Payment 就是一个规范类,这个类存在的意义不在于实现实际的功能,而是为了约束所有的子类必须实现pay的方法
  44. Payment : 抽象类
  45. pay = Payment() # 抽象类: 不能实例化
  46. 抽象类主要就是作为基类/父类,来约束子类中必须实现的某些方法
  47. 抽象类的特点:
  48. 必须在类定义的时候指定 metaclass = ABCMeta
  49. 必须在要约束的方法上方加上 @abstractmethod 方法
  50. """
  51. from abc import ABCMeta, abstractmethod # (抽象方法)
  52. class Payment(metaclass=ABCMeta): # metaclass 元类 metaclass = ABCMeta表示Payment类是一个规范类
  53. def __init__(self, name, money):
  54. self.name = name
  55. self.money = money
  56. @abstractmethod # 当子类继承的时候,必须重构pay方法,不然在子类实例化的时候就报错
  57. def pay(self):
  58. pass
  59. class AliPay(Payment):
  60. def pay(self):
  61. print('%s通过支付宝消费了%s元' % (self.name, self.money))
  62. class WeChatPay(Payment):
  63. def pay(self):
  64. print('%s通过微信消费了%s元' % (self.name, self.money))
  65. def pay_func(pay_obj): # 接口归一
  66. pay_obj.pay()
  67. a = AliPay('tom', 2000)
  68. w = WeChatPay('jerry', 4000)
  69. # 调用归一接口
  70. pay_func(a)
  71. pay_func(w)

多态

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 多态
  4. # 第一种解释
  5. # 多态:指的是一类事物有多种形态
  6. # 动物有多种形态:人,狗,猪
  7. import abc
  8. class Animal(metaclass=abc.ABCMeta): # 同一类事物:动物
  9. @abc.abstractmethod
  10. def talk(self):
  11. pass
  12. class People(Animal): # 动物形态之一:人
  13. def talk(self):
  14. print('say hello')
  15. class Dog(Animal): # 动物的形态之二:狗
  16. def talk(self):
  17. print('say 旺旺旺')
  18. class Pig(Animal): # 动物的形态之三:猪
  19. def talk(self):
  20. print('say 嗷嗷嗷')
  21. # 文件有多种形态:文本文件,可执行文件
  22. class File(metaclass=abc.ABCMeta): # 同一类事物:文件
  23. @abc.abstractmethod
  24. def click(self):
  25. pass
  26. class Text(File): # 文件的形态之一:文本文件
  27. def click(self):
  28. print('open file')
  29. class ExeFile(File): # 文件的形态之二:可执行文件
  30. def click(self):
  31. print('execute file')
  32. # 什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
  33. # 多态性是指在不考虑实例类型的情况下使用实例
  34. # 在面向对象方法中一般是这样表述多态性
  35. # 向不同的对象发送同一条消息
  36. # (obj.func(): 是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)
  37. # 也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数
  38. # 比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
  39. # 多态性
  40. peo = People()
  41. dog = Dog()
  42. pig = Pig()
  43. # peo、dog、pig都是动物,只要是动物肯定有talk方法
  44. # 于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
  45. peo.talk()
  46. dog.talk()
  47. pig.talk()
  48. print("--------------------------- 1 ---------------------------------")
  49. # 更进一步,我们可以定义一个统一的接口来使用
  50. def func(obj):
  51. obj.talk()
  52. func(peo)
  53. func(dog)
  54. func(pig)
  55. print("--------------------------- 2 ---------------------------------")
  56. # 多态
  57. # 第二种解释
  58. # from abc import ABCMeta, abstractmethod
  59. #
  60. #
  61. # class Payment(metaclass=ABCMeta):
  62. # def __init__(self, name, money):
  63. # self.money = money
  64. # self.name = name
  65. #
  66. # @abstractmethod
  67. # def pay(self):
  68. # pass
  69. #
  70. #
  71. # class AliPay(Payment):
  72. # def pay(self):
  73. # # 支付宝提供了一个网络上的联系渠道
  74. # print('%s通过支付宝消费了%s元' % (self.name, self.money))
  75. #
  76. #
  77. # class WeChatPay(Payment):
  78. # def pay(self):
  79. # # 支付宝提供了一个网络上的联系渠道
  80. # print('%s通过微信消费了%s元' % (self.name, self.money))
  81. #
  82. #
  83. # class ApplePay(Payment):
  84. # def pay(self):
  85. # print('%s通过apple消费了%s元' % (self.name, self.money))
  86. #
  87. #
  88. # al = AliPay("tom", 100)
  89. # w = WeChatPay('tom', 200)
  90. # ap = ApplePay("jerry", 1000)
  91. #
  92. #
  93. # def pay_func(pay_obj):
  94. # pay_obj.pay()
  95. #
  96. # pay_func(al)
  97. # pay_func(w)
  98. # pay_func(ap)
  99. # 多态的概念
  100. # 要理解什么是多态,我们首先要对数据类型再作一点说明
  101. # 当我们定义一个class的时候,我们实际上就定义了一种数据类型
  102. # 我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样
  103. # a = list() # a是list类型
  104. # b = Animal() # b是Animal类型
  105. # c = Dog() # c是Dog类型
  106. # 判断一个变量是否是某个类型可以用isinstance()判断:
  107. # >>> isinstance(a, list)
  108. # True
  109. # >>> isinstance(b, Animal)
  110. # True
  111. # >>> isinstance(c, Dog)
  112. # True 
  113. # 看来a、b、c确实对应着list、Animal、Dog这3种类型。
  114. # 但是等等,试试:
  115. # >>> isinstance(c, Animal)
  116. # True
  117. # 看来c不仅仅是Dog,c还是Animal!
  118. # 不过仔细想想,这是有道理的,因为Dog是从Animal继承下来的,
  119. # 当我们创建了一个Dog的实例c时,我们认为c的数据类型是Dog没错,但c同时也是Animal也没错,Dog本来就是Animal的一种!
  120. # 所以,在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类
  121. # 但是,反过来就不行:
  122. # >>> b = Animal()
  123. # >>> isinstance(b, Dog)
  124. # False
  125. # Dog可以看成Animal,但Animal不可以看成Dog
  126. # 所以,上面的支付的例子,如果我们再定义一个ApplePay类型,也从Payment类派生:
  127. # class ApplePay(Payment):
  128. # def pay(self):
  129. # print('%s通过苹果支付消费了%s元'%(self.name,self.money))
  130. #
  131. # ap=ApplePay("lisa",800)
  132. # 你会发现,新增一个Payment的子类,不必对pay()做任何修改,
  133. # 实际上,任何依赖Payment作为参数的函数或者方法都可以不加修改地正常运行,原因就在于多态。
  134. # 多态的好处就是,当我们需要传入AliPay、WeChatPay、ApplePay……时,
  135. # 我们只需要接收Payment类型就可以了,因为AliPay、WeChatPay、ApplePay……都是Payment类型,
  136. # 然后,按照Payment类型进行操作即可。由于Payment类型有pay()方法,
  137. # 因此,传入的任意类型,只要是Payment类或者子类,就会自动调用实际类型的pay()方法,这就是多态的意思
  138. # 对于一个变量,我们只需要知道它是Payment类型,无需确切地知道它的子类型,
  139. # 就可以放心地调用pay()方法,而具体调用的pay()方法是作用在AliPay、WeChatPay、ApplePay哪个类对象上,
  140. # 由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,
  141. # 而当我们新增一种Payment的子类时,只要确保pay()方法编写正确,不用管原来的代码是如何调用的
  142. # 这就是著名的“开闭”原则:
  143. # 对扩展开放:允许新增Payment子类;
  144. # 对修改封闭:不需要修改依赖Payment类型的pay()等函数

鸭子类型

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. # 鸭子类型
  4. from abc import ABCMeta, abstractmethod
  5. class Payment(metaclass=ABCMeta): # Payment看做是一只鸭子
  6. def __init__(self, name, money):
  7. self.name = name
  8. self.money = money
  9. @abstractmethod
  10. def pay(self):
  11. pass
  12. class AliPay(Payment):
  13. def pay(self):
  14. print('%s通过支付宝消费了%s元' % (self.name, self.money))
  15. class WeChatPay(Payment):
  16. def pay(self):
  17. print('%s通过微信消费了%s元' % (self.name, self.money))
  18. class CardPay(object): # 像鸭子
  19. def __init__(self, name, money):
  20. self.money = money
  21. self.name = name
  22. def pay(self):
  23. print('%s通过银联卡支付消费了%s元' % (self.name, self.money))
  24. def pay_func(pay_obj): # 传入的值只要像鸭子就行
  25. pay_obj.pay()
  26. a = AliPay('tom', 100)
  27. w = WeChatPay('jerry', 200)
  28. pay_func(a)
  29. pay_func(w)
  30. # 调用鸭子的接口
  31. cp = CardPay("lisa", 1000)
  32. pay_func(cp)
  33. # 对于静态语言(例如Java)来说,如果需要传入Payment类型,则传入的对象必须是Payment类型或者它的子类,
  34. # 否则,将无法调用pay()方法。
  35. # 对于Python这样的动态语言来说,则不一定需要传入Payment类型。我们只需要保证传入的对象有一个pay()方法就可以了
  36. # 这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,
  37. # 那它就可以被看做是鸭子

练习题

需求

  1. 需求:
  2. 从“学生选课系统” 这几个字就可以看出来,我们最核心的功能其实只有 选课
  3. 角色:
  4. 学生、管理员、讲师
  5. 功能:
  6. 登陆 管理员和学生都可以登陆,且登陆之后可以自动区分身份
  7. 选课 学生可以自由的为自己选择课程
  8. 创建用户 选课系统是面向本校学生的,因此所有的用户都应该由管理员完成
  9. 查看选课情况 :每个学生可以查看自己的选课情况,而管理员应该可以查看所有学生的信息
  10. 工作流程:
  11. 登陆 :用户输入用户名和密码
  12. 判断身份 :在登陆成果的时候应该可以直接判断出用户的身份 是学生、讲师还是管理员
  13. 学生用户 :对于学生用户来说,登陆的工作几乎不变
  14. 1、查看所有课程
  15. 2、选择课程
  16. 3、查看所选课程
  17. 4、退出程序
  18. 管理员用户:管理员用户也可以做更多的事情
  19. 1、创建课程
  20. 2、创建学生学生账号
  21. 3、查看所有课程
  22. 4、查看所有学生
  23. 5、查看所有学生的选课情况
  24. 6、创建讲师
  25. 7、为讲师指定班级
  26. 8、创建班级
  27. 9、为学生指定班级
  28. 10、退出程序
  29. 讲师用户 :对于讲师用户来说,可以完成的功能如下
  30. 1、查看所有课程
  31. 2、查看所教班级
  32. 3、查看班级中的学生
  33. 4、退出程序

逻辑图

course_system.py

  1. #!/usr/bin/env python3
  2. # author: Alnk(李成果)
  3. import sys
  4. import os
  5. import json
  6. class Base: # 基础类
  7. def __read_dic__(self, filename): # 读取json格式的文件
  8. with open(filename, encoding='utf', mode='r') as f:
  9. info_dic = json.load(f)
  10. return info_dic
  11. def __wirte_dic__(self, filename, info_dic): # 写入json类型文件
  12. with open(filename, encoding='utf', mode='w') as f:
  13. json.dump(info_dic, f)
  14. return True
  15. def __read_file__(self, filename): # 读取普通文件
  16. file_list = []
  17. with open(filename, encoding='utf', mode='r') as f:
  18. for line in f:
  19. file_list.append(line.strip())
  20. return file_list
  21. def __write_file__(self, filename, info): # 写入普通文件
  22. with open(filename, encoding='utf', mode='a') as f:
  23. f.write('%s\n' % info)
  24. return True
  25. class Parent(Base): # 父类
  26. def show_courses(self): # 查看所有课程
  27. courses_list = self.__read_file__('course_list')
  28. print('\n所有课程:%s' % courses_list)
  29. return courses_list
  30. def exit(self): # 退出
  31. exit()
  32. class Student(Parent): # 学生类
  33. option_lis = [('show_courses', '查看所有课程'),
  34. ('select_course', '选择课程'),
  35. ('check_selected_course', '查看已选课程'),
  36. ('exit', '退出'),
  37. ]
  38. def __init__(self, name):
  39. self.name = name
  40. def select_course(self): # 选择课程
  41. course_list = self.show_courses() # 查看所有课程
  42. select_course = input('输入课程名称>>')
  43. if select_course in course_list:
  44. stu_dic = self.__read_dic__(self.name) # 读取学生个人详细信息
  45. stu_dic["select_course"].append(select_course)
  46. self.__wirte_dic__(self.name, stu_dic) # 写入学生个人信息
  47. else:
  48. print('课程不存在')
  49. def check_selected_course(self): # 查看已选课程
  50. stu_dic = self.__read_dic__(self.name) # 读取学生个人信息
  51. print('已选课程:', stu_dic["select_course"])
  52. class Manage(Parent): # 管理员类
  53. option_lis = [
  54. ('create_course', '创建课程'),
  55. ('create_stu', '创建学生'),
  56. ('show_courses', '查看所有课程'),
  57. ('show_students', '查看所有学生'),
  58. ('show_students_courses', '查看所有学生的选课情况'),
  59. ('create_teacher', '创建讲师'),
  60. ('create_class', '创建班级'),
  61. ('appoint_tearcher_class', '为讲师指定班级'),
  62. ('appoint_stu_class', '为学生指定班级'),
  63. ('exit', '退出'),
  64. ]
  65. def __init__(self, name):
  66. self.name = name
  67. def create_course(self): # 创建课程
  68. course_name = input('课程名称>>>').strip()
  69. self.__write_file__('course_list', course_name) # 写入课程文件
  70. print('\n%s课程创建成功\n' % course_name)
  71. def create_stu(self): # 创建学生
  72. stu_name = input('学生账号>>>')
  73. stu_pwd = input('密码>>>')
  74. stu_info_dic = {'username': stu_name, 'passwd': stu_pwd, 'id': 'Student', 'select_course': [], 'class': []}
  75. self.__wirte_dic__(stu_name, stu_info_dic) # 写入学生详细信息
  76. self.__write_file__('students_list', stu_name) # 学生总列表
  77. print('\n学生%s创建成功\n' % stu_name)
  78. def show_students(self): # 查看所有学生
  79. students_list = self.__read_file__('students_list') # 读取学生总列表文件
  80. print('\n所有的学生:%s' % students_list)
  81. def show_students_courses(self): # 查看所有学生的选课情况
  82. stu_lis = self.__read_file__('students_list') # 读取学生总列表文件
  83. for i in stu_lis:
  84. stu_dic = self.__read_dic__(i) # 学生个人详细信息
  85. print('%s 选课情况:%s' % (i, stu_dic['select_course']))
  86. def create_teacher(self): # 创建讲师
  87. t_name = input('讲师账号>>>')
  88. t_pwd = input('密码>>>')
  89. t_dic = {"username": t_name, "passwd": t_pwd, "id": "Teacher", "class": []}
  90. self.__wirte_dic__(t_name, t_dic) # 写入老师详细信息
  91. self.__write_file__('teacher_list', t_name) # 写入老师总文件
  92. print('讲师 %s 创建成功' % t_name)
  93. def appoint_tearcher_class(self): # 为讲师指定班级
  94. teacher_list = self.__read_file__('teacher_list') # 读取老师总文件
  95. class_list = self.__read_file__('class_list') # 读取班级总文件
  96. print('所有老师:%s' % teacher_list)
  97. t_name = input('讲师名称>>>').strip()
  98. print('所有班级:%s' % class_list)
  99. c_name = input('班级名称>>>').strip()
  100. if t_name in teacher_list and c_name in class_list:
  101. teacher_dic = self.__read_dic__(t_name) # 读取老师个人信息
  102. teacher_dic['class'].append(c_name)
  103. self.__wirte_dic__(t_name, teacher_dic) # 写入老师个人信息
  104. print('已为讲师 %s 指定班级 %s' % (t_name, c_name))
  105. else:
  106. print('讲师或班级不存在')
  107. def create_class(self): # 创建班级
  108. class_name = input('创建班级名称:')
  109. self.__write_file__('class_list', class_name) # 写入班级总文件
  110. print('%s 班级创建成功' % class_name)
  111. def appoint_stu_class(self): # 为学生指定班级
  112. stu_list = self.__read_file__('students_list') # 读取学生总列表文件
  113. class_list = self.__read_file__('class_list') # 读取班级总文件
  114. print('所有学生:%s' % stu_list)
  115. stu_name = input('学生名称>>>')
  116. print('所有班级:%s' % class_list)
  117. class_name = input('班级名称>>>')
  118. if stu_name in stu_list and class_name in class_list:
  119. self.__write_file__(class_name, stu_name) # 写入班级文件
  120. stu_dic = self.__read_dic__(stu_name) # 读取学生信息
  121. stu_dic['class'].append(class_name)
  122. self.__wirte_dic__(stu_name, stu_dic)
  123. print('为学生 %s 指定班级 %s 成功' % (stu_name, class_name))
  124. else:
  125. print('班级或学生不存在')
  126. class Teacher(Parent): # 讲师类
  127. option_lis = [('show_courses', '查看所有课程'),
  128. ('show_class', '查看所教班级'),
  129. ('show_class_students', '查看班级中的学生'),
  130. ('exit', '退出'),
  131. ]
  132. def __init__(self, name):
  133. self.name = name
  134. def show_class(self): # 查看所教班级
  135. tearcher_dic = self.__read_dic__(self.name)
  136. print('所教班级%s' % tearcher_dic['class'])
  137. def show_class_students(self): # 查看班级中的学生
  138. tearcher_dic = self.__read_dic__(self.name)
  139. print('%s 班级中的学生:' % tearcher_dic['class'])
  140. for i in tearcher_dic['class']:
  141. stu_list = self.__read_file__(i)
  142. print(stu_list)
  143. def login(): # 登录函数
  144. name = input('username>>>:')
  145. pwd = input('password>>>:')
  146. if os.path.isfile(name):
  147. with open(name, encoding='utf-8', mode='r') as f:
  148. user_dic = json.load(f)
  149. if user_dic['passwd'] == pwd:
  150. return {'result': True, 'name': name, 'id': user_dic['id']}
  151. else:
  152. return {'result': False, 'name': name}
  153. else:
  154. return {'result': False, 'name': name}
  155. def main():
  156. ret = login()
  157. if ret['result']:
  158. print('登录成功')
  159. if hasattr(sys.modules[__name__], ret['id']):
  160. cls = getattr(sys.modules[__name__], ret['id']) # 类
  161. obj = cls(ret['name']) # 实例化
  162. while 1:
  163. print('\n')
  164. for k, i in enumerate(cls.option_lis, 1):
  165. print(k, i[1])
  166. try:
  167. choice = int(input(">>>:"))
  168. except ValueError:
  169. print("\n请输入编号")
  170. continue
  171. func_str = cls.option_lis[choice - 1][0]
  172. if hasattr(obj, func_str):
  173. getattr(obj, func_str)()
  174. else:
  175. print('登录失败')
  176. if __name__ == '__main__':
  177. main()

admin

  1. {"username": "admin", "passwd": "123", "id": "Manage"}

Python语言系列-07-面向对象2的更多相关文章

  1. Python语言系列-05-模块和包

    自定义模块 #!/usr/bin/env python3 # author:Alnk(李成果) # 为什么要有模块?(内置函数不够用) # 和操作系统打交道 # 和python解释器打交道 # 和时间 ...

  2. Python学习系列之面向对象

    概述 一.Python编程方式 面向过程编程:根据业务逻辑从上到下磊代码 面向函数编程:将某功能代码封装到函数中,将来直接调用即可,无需重新写 面向对象编程:对函数进行分类.封装 二.面向过程编程 w ...

  3. Python语言系列-06-面向对象1

    楔子 #!/usr/bin/env python3 # author:Alnk(李成果) # 人狗大战例子引入面向对象 # 版本1 def hero(name, sex, hp, ce, level= ...

  4. Python语言系列-02-基础数据类型

    格式化输出 #!/usr/bin/env python3 # author:Alnk(李成果) # 百分号% 格式化输出 name = input('姓名:') age = input('年龄:') ...

  5. Python语言系列-10-数据库

    MySQL 基础环境准备 readme.txt 作者:Alnk(李成果) 版本:v1.0 安装mysql数据库 略 创建student库 # mysql> create database stu ...

  6. Python语言系列-09-socket编程

    简介 软件开发的架构 1.C/S架构(client-server) 2.B/S架构 (browser-server) 网络基础概念 网络三要素: 1.ip 2.port 3.通信协议:TCP.UDP ...

  7. Python语言系列-08-面向对象3

    反射 #!/usr/bin/env python3 # author: Alnk(李成果) # 反射 # hasattr getattr setattr delattr class Animal(ob ...

  8. Python语言系列-01-入门

    python的出生与应用 #!/usr/bin/env python3 # author:Alnk(李成果) """ 1,python的出生与应用 python的创始人为 ...

  9. Python语言系列-04-高阶函数

    闭包 #!/usr/bin/env python3 # author:Alnk(李成果) # 什么是闭包 # 1,闭包存在于函数中 # 2,闭包就是内层函数对外层函数(非全局变量)的引用 # 3,最内 ...

随机推荐

  1. 海量数据Excel报表利器——EasyExcel(一 利用反射机制导出Excel)

    EasyExcel 写入(导出) 互联网的精髓就是共享,可以共享技术.共享经验.共享情感.共享快乐~ 很多年前就有这个想法了,从事IT行业时间也不短了,应该把自己工作和业余所学习的东西记录并分享出来, ...

  2. js--你需要知道的字符串使用方法(含es6及之后)

    前言 字符串作为 JavScript 的基本数据类型,在开发以及面试过程中作为程序员对基础掌握情况的重要考点,本文来总结一下字符串的相关属性以及用法.包含了ES6中的一些新语法特性. 正文 1.字符串 ...

  3. pip 下载时出现问题TypeError: unsupported operand type(s) for -=: 'Retry' and 'int'

    我这里解决就是更新下载源,马德,中科的源居然不够快,我就只能换源了,一换就成功了 1.一次性(临时使用): 可以在使用pip的时候加参数-i https://pypi.tuna.tsinghua.ed ...

  4. springboot项目启动,停止,重启

    参考博客 https://www.cnblogs.com/c-h-y/p/10460061.html 打包插件,可以指定启动类 <build> <plugins> <pl ...

  5. 羊城杯wp babyre

    肝了好久,没爆破出来,就很难受,就差这题没写了,其他三题感觉挺简单的,这题其实也不是很难,我感觉是在考算法. 在输入之前有个smc的函数,先动调,attach上去,ida打开那个关键函数. 代码逻辑还 ...

  6. 你会用哪些JavaScript循环遍历

    总结JavaScript中的循环遍历定义一个数组和对象 const arr = ['a', 'b', 'c', 'd', 'e', 'f']; const obj = { a: 1, b: 2, c: ...

  7. vue3后台管理系统(模板)

    系统简介 此管理系统是基于Vite2和Vue3.0构建生成的后台管理系统.目的在于学习vite和vue3等新技术,以便于后续用于实际开发工作中: 本文章将从管理系统页面布局.vue路由鉴权.vuex状 ...

  8. Python使用笔记005-文件操作(二)

    1.1 打开文件模式 # r r+ r+读是没问题的,写的话,会覆盖原来的内容,文件不存在时会报错# w w+ w+用来新的文件没问题,旧的文件会覆盖原来的内容# a a+ a+写是追加,读不到是因为 ...

  9. gpasswd简单记录

    gpasswd [option] GROUP 一切都是为了权限 gpasswd常用参数: -a, --add  USER 将user用户加入到组中 -d, --delete  USER 将user用户 ...

  10. C语言:GB2312编码和GBK编码,将中文存储到计算机

    计算机是一种改变世界的发明,很快就从美国传到了全球各地,得到了所有国家的认可,成为了一种不可替代的工具.计算机在广泛流行的过程中遇到的一个棘手问题就是字符编码,计算机是美国人发明的,它使用的是 ASC ...