多态
-
面向对象特征
-
封装:用类将属性和方法封装在一起,配合私有属性和私有方法使用
-
继承:让子类可以继承父类的属性和方法,不包括私有的,子类可以扩展自己的属性和方法
- 1.子类完全继承父类的所有属性和方法的情况,如:动物类,狗类,动物类作为父类,狗类作为子类,一般有从属关系
- 2.如果父类中有部分属性和方法不继承,则需要将它们的公共的属性和方法抽取出来作为父类,如:狗类和猫类,将狗和猫的公共属性和方法提取出来作为父类
-
多态(了解):在继承的基础上,而且需要用重写。要在父类中定义一个方法,让所有子类重写该方法,那么我们可以使用父类对象去指向不同的子类来调用同一个方法名,则有不同的状态或结果(animal看作是父类对象,Python没有真正的多态,这里将animal看作是父类的对象)
-
# 父类 class Animal: def bark(self): pass # 子类 class Dog(Animal): def bark(self): print('汪汪汪的叫') class Cat(Animal): def bark(self): print('喵喵喵的叫') class Wolf(Animal): def bark(self): print('嗷嗷嗷的叫') class Person: def __init__(self, name): self.name = name def beat_animal(self, animal): print(f'{self.name}正在殴打小动物') animal.bark() # animal看作是父类对象,Python没有真正的多态,这里将animal看作是父类的对象 # 对象 dog = Dog() cat = Cat() wolf = Wolf() xiaoming = Person('黄晓明') xiaoming.beat_animal(dog) # 调用小明,将动物子类的对象作为参数传递至对应的方法中
-
-
抽象
-
获取对象信息
- type():判断数据类型
- isinstance():判断某个对象是否属于指定的类的对象,指定的类的对象可以是一个元组
- dir():列出指定对象中所包含的所有的内容【成员变量/对象属性,成员方法】
- dir() # 获得当前模块的属性列表
- dir([ ]) # 查看列表的方法
类属性&类方法
-
如果类属性的值是引用类型,则该类属性会被当前类创建的所有对象共享;如果该引用类型属性值是成员属性,则不会共享
-
class Person: # 类属性(类变量) name = '鹿晗' age = 10 # 如果类属性的值是引用类型,则该类属性会被当前类创建的所有对象共享 likes = ['关晓彤', '舒淇'] def __init__(self, age): # 在构造函数中初始化对象属性/成员变量 # 对象属性(成员变量) self.age = age # 不会共享 self.likes2 = ['关晓彤', '舒淇'] # 对象属性直接写死,不需要在构造函数中写出来
-
-
对象属性如果直接给出初始值写死,则不需要在构造函数中写出来进行初始化
-
对象.类属性/类.类属性/对象.对象属性
-
针对相同名称的类属性和对象属性,对象调用会优先调用对象属性
-
可以对对象属性和类属性进行修改
单例模式
-
让类只能创建出一个对象
-
设计模式:一种解决问题的方式
-
设计模式:23种设计模式,比如:单例模式,工厂模式,代理模式,装饰器模式,适配器模式
-
使用new方法
-
class Person: # 构造函数:用来对属性初始化 def __init__(self): print('__init__') # 类属性 instance = None # new方法:用来创建对象 @classmethod def __new__(cls, *args, **kwargs): # 自动先调用new, 重写new print('__new__') # __new__ if not cls.instance: print('---创建新对象---') cls.instance = super(Person, cls).__new__(*args, **kwargs) # 新建对象,相当于修改类属性.Person是父类,父类对应cls(特殊形参) # cls.instance = object.__new__(cls) # object可以换成super() return cls.instance # 对象 p = Person() p2 = Person() print(p == p2) # True
- 初始化一个类属性并使其值为None
- 利用类方法重写创建对象的方法:new方法
- 隐式调用类的new方法来新建对象,并赋值给初始化的类属性,相当于修改类属性
-
-
使用装饰器
-
# 装饰器 def outer(cls): instance = None print('instance初始化为None') def inner(*args, **kwargs): # 通用装饰器 nonlocal instance if not instance: print('---创建了新的对象---') instance = cls(*args, **kwargs) # cls相当于Person类, 新建对象 print('---返回对象---') return instance return inner @outer # 加上装饰器的一瞬间调用一次instance = None,后面不会再调用 class Person: pass p1 = Person() p2 = Person() print(p1 is p2) # True
- 加上装饰器的一瞬间调用一次在外函数初始化值为None的变量,后面构建对象时,直接用的是内函数
-
-
使用类方法
-
# 使用类方法 class Singleton: instance = None @classmethod def get_instance(cls): if not cls.instance: cls.instance = cls() # 相当于修改类的属性,cls()相当于Singleton() return cls.instance s1 = Singleton.get_instance() # 通过调用类方法新建对象 s2 = Singleton.get_instance() print(s1 is s2) # True
- 在创建对象时调用类方法进行新建
-
生产者消费者模式
-
如果一个线程的运行是根据另一个线程的结果,那么需要使用生产者和消费者模式
-
import time from threading import Thread import queue q = queue.Queue() def make(): num = 1 while True: print(f'做了{num}个包子') q.put(num) num += 1 time.sleep(1) def eat(): while True: num = q.get() print(f'吃了{num}个包子') if __name__ == '__main__': t1 = Thread(target=make) t2 = Thread(target=eat) t1.start() t2.start() t1.join() t2.join()
类方法和静态方法
-
class Person: # 构造方法 def __init__(self, name): self.name = name # 成员方法(常用) def sleep(self): print('睡觉', self) # 私有方法 def __run(self): print('跑步') # 类方法 # 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存 # 2.可以使用类属性和其他类方法,但是不能使用对象属性和成员方法和私有方法 # 3.一般用在功能比较独立、和类中其他属性和方法无关的情况下 # cls: class @classmethod def eat(cls): print('吃饭:', cls==Person) # 在类方法中不能使用对象属性和成员方法,因为没有self # 静态方法 # 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存 # 2.不可以使用对象属性和成员方法和私有方法,一般也不用类属性和类方法 # 3.就是一个非常普通的函数,只是写在类里面 @staticmethod def sing(): print('唱歌') # 对象 p = Person('蔡徐坤') Person.eat() # 类.类方法 # 吃饭: True(类是不占内存的) p.eat() # 对象.类方法 # 吃饭: True Person.sleep(p) # 睡觉,类.成员方法(不推荐,尽量不这么用) p.sleep() # 睡觉,对象.成员方法 Person.sing() # 唱歌,类.静态方法,推荐 p.sing() # 唱歌,对象.静态方法
- 类方法@classmethod
- 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
- 2.可以使用类属性和其他类方法,但是不能使用对象属性和成员方法和私有方法
- 3.一般用在功能比较独立、和类中其他属性和方法无关的情况下
- 静态方法@staticmethod
- 1.可以使用类和对象调用,但是建议使用类来调用,可以节省内存
- 2.不可以使用对象属性和成员方法和私有方法,一般也不用类属性和类方法
- 3.就是一个非常普通的函数,只是写在类里面
- 类.类方法/对象.类方法/类.成员方法(不推荐,需要传入对象)/对象.成员方法/类.静态方法/对象.静态方法
- 类方法@classmethod
动态添加属性和方法
-
动态添加的属性:只存在于当前的对象中
-
动态添加方法
-
需要传入对象
-
class Person: age = 20 def __init__(self, name): self.name = name # 对象 p = Person('成龙') print(p.name) # '成龙' # 动态添加属性:只存在于当前的对象中 p.age = 10 print(p.name, p.age, Person.age) # 成龙 10 20 # print(Person('李小龙').age) # 报错 # 动态添加方法:了解 def sleep(self): print(self.name, '在睡觉') p.sleep2 = sleep p.sleep2(p) # 调用, 成龙 在睡觉 from types import MethodType def sleep(self): print(self.name, '在睡觉') p.sleep3 = MethodType(sleep, p) p.sleep3() # 调用, 成龙 在睡觉 # 类属性赋值要使用类.类属性的方式赋值 # 每个对象的对象属性是独立的内存
-
特殊属性
- 类.__name__ # 类
- 对象.__class__ # __main__.类
- 对象.__dict__ # 快速获取对象的所有属性及其属性值
- 对象.__module__ # __main__
- 类.__module__ # __main__
- 类.__bases__ # 父类
- 类.__mro__ # 查看某个类的继承顺序
- print(__name__) # __main__
运算符重载
-
class Girl: def __init__(self, name, age): self.name = name self.age = age # 加法 def __add__(self, other): # 重写运算符方法 return self.age + other.age # 对象 p1 = Girl('杨超越', 22) p2 = Girl('关晓彤', 20) print(p1.age + p2.age) # 42 print(p1 + p2) # 42
- 让类可以使用运算符
- 相当于重写内部的运算符方法