面向对象的三要素

封装

  1. class Turtle: # python 中的类
  2. age = 'green'
  3. weight = 10
  4. legs = 4
  5. shell = True
  6. mouth = '大嘴'
  7. # 方法
  8. def climb(self):
  9. print('我在很努力')
  10. def run(self):
  11. print('运行')
  12. def bite(self):
  13. print('陶死你')
  14. def add(self):
  15. print('加法运算')
  16. t = Turtle()
  17. t.climb()

继承

继承是子类自动共享父类之间数据和方法的机制

  1. '''
  2. Mylist 继承 list 列表的方法
  3. pass 表示占位
  4. Mylist 这个类不做任何事情, 达到信息隐蔽
  5. '''
  6. class Mylist(list):
  7. pass
  8. # 实例化 Mylist 实例对象
  9. list2 = Mylist()
  10. list2.append(5)
  11. list2.append(9)
  12. list2.append(15)
  13. print(list2)
  14. # 也可以进行排序
  15. print(list2.stor())
  16. -------------------------------
  17. >>>>[5, 19, 15]
  18. >>>>[5, 15, 19]

多态

  1. '''
  2. 多态就是 不同对象 对同一方法 响应不同的行动
  3. '''
  4. class A:
  5. def fun(self):
  6. print('我是A对象里的函数')
  7. class B:
  8. def fun(self):
  9. print('我是B对象里的函数')
  10. a = A()
  11. b = B()
  12. a.fun()
  13. b.fun()
  14. ------------------
  15. >>>我叫张三, 该死的, 谁踢我....
  16. >>>我叫李四, 该死的, 谁踢我....
  17. >>>我叫小明, 该死的, 谁踢我....

self 是什么?

python的 self 就相当于 JavaScript 中的 this 的指针

  1. # self 指针 相当于 JavaScript中的 this 指针
  2. # 这个类相当于模版一样,
  3. class Ball:
  4. def setName(self, name):
  5. self.name = name
  6. def cick(self):
  7. print("我叫%s, 该死的, 谁踢我...." %self.name)
  8. a = Ball()
  9. a.setName("张三")
  10. b = Ball()
  11. b.setName("李四")
  12. c = Ball()
  13. c.setName("小明")
  14. a.cick()
  15. b.cick()
  16. c.cick()
  17. --------------------
  18. >>>我叫张三, 该死的, 谁踢我....
  19. >>>我叫李四, 该死的, 谁踢我....
  20. >>>我叫小明, 该死的, 谁踢我....

访问控制与属性装饰器

在python 中定义私有变量 只需要在变量或者函数名前加上 “__” 两个下划线, 那么这个函数或变量就会为私有 外部访问不了 , 同时也称为装饰器

共有变量函数

  1. # 共有 ,可以被外部访问的
  2. class temp:
  3. age = 18
  4. def setName(self, name):
  5. print('我叫:%s' % name)
  6. A = temp()
  7. print(A.age)
  8. A.setName('张三')
  9. -------------------
  10. >>>18
  11. >>>我叫:张三

访问私有变量函数1

  1. '''
  2. 定义私有函数或者变量 在变量或者函数前 添加 __ 双下划线即可
  3. 然后调用共有的方法, 获取内部私有的变量或者函数
  4. '''
  5. class temp:
  6. __age = 18
  7. def __setName(self, name):
  8. print('我叫:%s' % name)
  9. def getAge(self):
  10. print('age的值:%s' % self.__age)
  11. def getName(self,name):
  12. self.__setName(name)
  13. A = temp()
  14. A.getAge()
  15. A.getName('李四')
  16. ---------------------------------
  17. >>>18
  18. >>>我叫:李四

访问私有变量函数2

  1. class temp:
  2. __age = 18
  3. def __setName(self, name):
  4. # print('我叫:%s' % name)
  5. return '我叫:%s' % name
  6. def getAge(self):
  7. print('age的值:%s' % self.__age)
  8. def getName(self,name):
  9. self.__setName(name)
  10. A = temp()
  11. A.getAge()
  12. A.getName('李四')
  13. # 还可以通过 下划线类名 进行访问也可以
  14. print(A._temp__age)
  15. print(A._temp__setName('王五'))
  16. ---------------------------------
  17. >>>age的值:18
  18. >>>18
  19. >>>我叫:王五

类和实例

  1. # 类
  2. class Turbo:
  3. name = '张三'
  4. def add(a,b):
  5. return a + b
  6. # 实例化 出了 t
  7. t = Turbo()
  8. t.name

类方法与静态方法

静态方法 @staticmethod

为什么会报错?

静态方法不能访问实例属性、类属性、实例方法、类方法

  1. class Test2:
  2. name ="你好世界"
  3. @staticmethod
  4. def static(self):
  5. print("我的口号是:" +self.name)
  6. temp2 = Test2()
  7. temp2.static()
  8. # static 已经通过 @staticmethod 定义成静态方法, 所以不能直接这样访问,
  9. 因为 self是上下文访问 属性name, 当然也包括这个 self
  10. ---------------------报错
  11. TypeError: static() missing 1 required positional argument: 'self'

静态方法的特别之处

  • 它跟类与对象无关
  • 跟在模块中直接定义普通函数没有什么区别,只是把“静态方法”放到了类里面,所以只能设置形参
  • 只能通过 类名.静态方法 来调用 ```python

class Test: name =”你好世界”

  1. @staticmethod
  2. def static(name):
  3. print("我的口号是:" +name)

temp = Test()

temp.static(temp.name)

Test.static(temp.name)

我的口号是:你好世界 我的口号是:你好世界

  1. <a name="Bqd4L"></a>
  2. ### 类方法 @classmethod
  3. ```python
  4. class person:
  5. name = "cool man"
  6. @classmethod
  7. def class_m(cls):
  8. print("--第一个类方法--", id(cls))
  9. print("--第一个类方法--", cls.name)
  10. cls.self_m(cls)
  11. cls.class_m2()
  12. def self_m(self):
  13. print("--实例方法--", id(self))
  14. print("--实例方法--", self.name)
  15. @classmethod
  16. def class_m2(cls):
  17. print("--第二个类方法--", id(cls))
  18. p = person()
  19. p.name = "bad boy" # 绑定实例属性
  20. p.class_m()
  21. person.class_m()

知识点

  • 类方法内部可以直接访问类属性、类方法、实例方法
  • 可以理解成类对象的引用,哪一个类对象调用的方法, cls 就是哪个一个类的引用, 类对象.类方法 ;和实例方法中的 self 很像, 实例对象.实例方法

cls

  • 调用其他类方法时,不用传递cls参数;但调用其他实例方法时,需要传递cls参数
  • 在类方法内部调用的实例方法,接收的是一个类对象而不是实例对象,当实例对象绑定实例属性时,在实例方法中打印的仍然是类属性;表明类方法无法访问实例属性
  • 一个类只有一个类对象,即使通过实例对象调用类方法,传递的仍然是类对象的引用,所有类方法都被同一个类对象调用

    思考题

    如果方法内部 即需要访问 实例属性,又需要访问 类属性,应该定义成什么方法?
    答案:实例方法,因为可以通过 类对象.类属性 来访问,但在类方法中无法访问实例属性 ```python class Person: name = “bad boy”

    def self_m(self):

    1. Person.name = "yep"
    2. print(self.name)

p = Person() p.name = “陈十八” # 绑定实例属性 p.self_m()

Person.self_m(Person)

陈十八 yep

  1. <a name="h3sYt"></a>
  2. ## 继承与多态
  3. <a name="usqCm"></a>
  4. ### 子继承父类
  5. ```python
  6. class Panent:
  7. def hello(self):
  8. print('正在调用父类的方法....')
  9. class Child(Panent):
  10. pass
  11. p = Panent()
  12. p.hello()
  13. c=Child()
  14. c.hello()
  15. -----------
  16. >>>正在调用父类的方法....
  17. >>>正在调用父类的方法....

如果子类中定义与父类同名的方法或者属性, 则会自动覆盖父类对应的方法或属性

  1. class Panent: # 这个是父类
  2. def hello(self):
  3. print('正在调用父类的方法....')
  4. class Child(Panent): # 这个是子类
  5. def hello(self):
  6. print('正在调用子类的方法....')
  7. p = Panent()
  8. p.hello()
  9. c=Child()
  10. c.hello()
  11. -----------
  12. >>>正在调用父类的方法....
  13. >>>正在调用子类的方法....


小案列

鲨鱼移动 的代码 会报错 为什么呢, 可是代码都相同啊!
因为 我们重写 init方法, 子类重写了父类的方法, 就会覆盖原来的方法

  1. import random as r
  2. class Fish: # 鱼
  3. def __init__(self):
  4. self.x = r.randint(0, 10)
  5. self.y = r.randint(0, 10)
  6. def move(self):
  7. self.x -= 1
  8. print("我的位置是:", self.x, self.y)
  9. class Goldfish(Fish): # 金鱼
  10. pass
  11. class Carp(Fish): # 鲤鱼
  12. pass
  13. class Salmon(Fish): # 三文鱼
  14. pass
  15. class Shark(Fish):
  16. def __init__(self):
  17. self.hungry = True
  18. def eat(self):
  19. if self.hungry:
  20. print("吃货的梦想就是天天有的吃")
  21. self.hungry = False
  22. else:
  23. print("太撑了, 吃不下")
  24. fish = Fish()
  25. fish.move()
  26. goldfish = Goldfish() # 金鱼移动
  27. goldfish.move()
  28. shark = Shark() # 鲨鱼移动
  29. shark.move()
  30. ---------------------
  31. 我的位置是: 5 8
  32. 我的位置是: 5 5
  33. Traceback (most recent call last):
  34. File "e:/001笔记大全/008Python01/demon10.py", line 40, in <module>
  35. shark.move()
  36. File "e:/001笔记大全/008Python01/demon10.py", line 8, in move
  37. self.x -=1
  38. AttributeError: 'Shark' object has no attribute 'x'

我们要在重写init 方法的时候

解决方法1

调用未绑定的父类方法
应该要在鲨鱼的类里面 重写init 方法的时候先调用子类的init方法
只需要书写父类的名字 Fish.init(self)

  1. import random as r
  2. class Fish: # 鱼
  3. def __init__(self):
  4. self.x = r.randint(0, 10)
  5. self.y = r.randint(0, 10)
  6. def move(self):
  7. self.x -= 1
  8. print("我的位置是:", self.x, self.y)
  9. class Goldfish(Fish): # 金鱼
  10. pass
  11. class Carp(Fish): # 鲤鱼
  12. pass
  13. class Salmon(Fish): # 三文鱼
  14. pass
  15. class Shark(Fish):
  16. def __init__(self):
  17. '''
  18. 原理, 子类中有跟父类一样的方法会覆盖父类的方法, 所以在修改前 添加这段代码即可
  19. 注意: Fish.__init__(self)是调用父类的
  20. 而self 是子类的实列对象
  21. '''
  22. Fish.__init__(self)
  23. self.hungry = True
  24. def eat(self):
  25. if self.hungry:
  26. print("吃货的梦想就是天天有的吃")
  27. self.hungry = False
  28. else:
  29. print("太撑了, 吃不下")
  30. fish = Fish()
  31. fish.move()
  32. goldfish = Goldfish() # 金鱼移动
  33. goldfish.move()
  34. shark = Shark() # 鲨鱼移动
  35. shark.move()
  36. ---------------------
  37. 我的位置是: 9 0
  38. 我的位置是: 9 9
  39. 我的位置是: 8 8

解决办法2

使用 super 函数 能够帮我们自动找到基类的方法, 还能帮我们传参数

  1. import random as r
  2. class Fish: # 鱼
  3. def __init__(self):
  4. self.x = r.randint(0, 10)
  5. self.y = r.randint(0, 10)
  6. def move(self):
  7. self.x -= 1
  8. print("我的位置是:", self.x, self.y)
  9. class Goldfish(Fish): # 金鱼
  10. pass
  11. class Carp(Fish): # 鲤鱼
  12. pass
  13. class Salmon(Fish): # 三文鱼
  14. pass
  15. class Shark(Fish):
  16. def __init__(self):
  17. # Fish.__init__(self)
  18. super().__init__()
  19. self.hungry = True
  20. def eat(self):
  21. if self.hungry:
  22. print("吃货的梦想就是天天有的吃")
  23. self.hungry = False
  24. else:
  25. print("太撑了, 吃不下")
  26. fish = Fish()
  27. fish.move()
  28. goldfish = Goldfish() # 金鱼移动
  29. goldfish.move()
  30. shark = Shark() # 鲨鱼移动
  31. shark.move()
  32. --------------------------------
  33. 我的位置是: 2 0
  34. 我的位置是: 1 9
  35. 我的位置是: 2 3

多重继承

可以继承多重父类的方法
注意, 请尽量避免使用它

  1. class Base1:
  2. def fun1(self):
  3. print("我是fun1d.")
  4. class Base2:
  5. def fun2(self):
  6. print("我是fun2.")
  7. class C(Base1, Base2):
  8. pass
  9. b = C()
  10. b.fun1()
  11. b.fun2()
  12. ---------------------
  13. 我是fun1d.
  14. 我是fun2.

继承与多继承(组合)

思路提示 :
定义一个水池类
水池里有乌龟类, 金鱼类等等
如果使用继承和多继承显然不行, 乱搞
那怎么样才能组成一个和谐的类呢? 使用组合即可

所谓的组合就是把旧类放到新类里, 这样就组合进去了

  1. # 水池组合
  2. class Turtle: # 乌龟
  3. def __init__(self, x): # x 表示有多少个乌龟进来
  4. self.num = x
  5. class Fish: # 金鱼
  6. def __init__(self, x): # x
  7. self.num = x
  8. class Pool: # 水池
  9. def __init__(self, x, y):
  10. self.turtle = Turtle(x)
  11. self.fish = Fish(y)
  12. def print_num(self):
  13. print("水池里总共有乌龟 %d 只, 小鱼 %d 条" % (self.turtle.num, self.fish.num))
  14. # 组合就是 把2 个旧类 实列化 放到 新的类里面 那么就把旧类 组合进去了,
  15. pool = Pool(2,10)
  16. pool.print_num()
  17. --------------------------
  18. 水池里总共有乌龟 1 只, 小鱼 10