单例模式 继承
基础
https://www.cnblogs.com/Eva-J/articles/7293890.html
进阶
https://www.cnblogs.com/Eva-J/articles/7351812.html
封装 继承 多态
一、特性property property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值 1、什么事特性property import math class Circle: def __init__(self,radius): self.radius =radius @property 方法化属性 def area(self): return math.pi*self.radius**2 #计算圆的面积 @property def perimeter(self): return 2*math.pi*self.radius #计算圆的周长 c = Circle(5) print(c.area) #可以向访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值 print(c.perimeter)
课程:⾯向对象-继承 ⽬标 继承的概念 单继承 多继承 ⼦类重写⽗类的同名属性和⽅法 ⼦类调⽤⽗类的同名属性和⽅法 多层继承 super() 私有属性和私有⽅法 ⼀. 继承的概念 ⽣活中的继承,⼀般指的是⼦⼥继承⽗辈的财产。 拓展1:经典类或旧式类 不由任意内置类型派⽣出的类,称之为经典类。 拓展2:新式类 class 类名: 代码 ...... class 类名(object): 代码 Python⾯向对象的继承指的是多个类之间的所属关系,即⼦类默认继承⽗类的所有属性和⽅法,具体如 下: 在Python中,所有类默认继承object类,object类是顶级类或基类;其他⼦类叫做派⽣类。 ⼆. 单继承 故事主线:⼀个煎饼果⼦⽼师傅,在煎饼果⼦界摸爬滚打多年,研发了⼀套精湛的摊煎饼果⼦的 技术。师⽗要把这套技术传授给他的唯⼀的最得意的徒弟。 分析:徒弟是不是要继承师⽗的所有技术? # ⽗类A class A(object): def __init__(self): self.num = 1 def info_print(self): print(self.num) # ⼦类B class B(A): pass result = B() result.info_print() # 1 # 1. 师⽗类 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') # 2. 徒弟类 class Prentice(Master): pass # 3. 创建对象daqiu daqiu = Prentice() # 4. 对象访问实例属性 print(daqiu.kongfu) 123456789 三. 多继承 故事推进:daqiu是个爱学习的好孩⼦,想学习更多的煎饼果⼦技术,于是,在百度搜索到⿊⻢程 序员,报班学习煎饼果⼦技术。 所谓多继承意思就是⼀个类同时继承了多个⽗类。 注意:当⼀个类有多个⽗类的时候,默认使⽤第⼀个⽗类的同名属性和⽅法。 四. ⼦类重写⽗类同名⽅法和属性 故事:daqiu掌握了师⽗和培训的技术后,⾃⼰潜⼼钻研出⾃⼰的独⻔配⽅的⼀套全新的煎饼果⼦ 技术。 # 5. 对象调⽤实例⽅法 daqiu.make_cake() class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') # 创建学校类 class School(object): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class Prentice(School, Master): pass daqiu = Prentice() print(daqiu.kongfu) daqiu.make_cake() class Master(object): def __init__(self): ⼦类和⽗类具有同名属性和⽅法,默认使⽤⼦类的同名属性和⽅法。 五. ⼦类调⽤⽗类的同名⽅法和属性 故事:很多顾客都希望也能吃到古法和⿊⻢的技术的煎饼果⼦。 self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class School(object): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') # 独创配⽅ class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') daqiu = Prentice() print(daqiu.kongfu) daqiu.make_cake() print(Prentice.__mro__) 3456789 class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class School(object): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' 六. 多层继承 故事:N年后,daqiu⽼了,想要把所有技术传承给⾃⼰的徒弟。 def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果⼦配⽅]' def make_cake(self): # 如果是先调⽤了⽗类的属性和⽅法,⽗类属性会覆盖⼦类属性,故在调⽤属性前,先调⽤ ⾃⼰⼦类的初始化 self.__init__() print(f'运⽤{self.kongfu}制作煎饼果⼦') # 调⽤⽗类⽅法,但是为保证调⽤到的也是⽗类的属性,必须在调⽤⽅法前调⽤⽗类的初始化 def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) daqiu = Prentice() daqiu.make_cake() daqiu.make_master_cake() daqiu.make_school_cake() daqiu.make_cake() class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') 1234567 七. super()调⽤⽗类⽅法 class School(object): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果⼦配⽅]' def make_cake(self): self.__init__() print(f'运⽤{self.kongfu}制作煎饼果⼦') def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) # 徒孙类 class Tusun(Prentice): pass xiaoqiu = Tusun() xiaoqiu.make_cake() xiaoqiu.make_school_cake() xiaoqiu.make_master_cake() class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' 1234 def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class School(Master): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') # ⽅法2.1 # super(School, self).__init__() # super(School, self).make_cake() # ⽅法2.2 super().__init__() super().make_cake() class Prentice(School): def __init__(self): self.kongfu = '[独创煎饼果⼦技术]' def make_cake(self): self.__init__() print(f'运⽤{self.kongfu}制作煎饼果⼦') # ⼦类调⽤⽗类的同名⽅法和属性:把⽗类的同名属性和⽅法再次封装 def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) # ⼀次性调⽤⽗类的同名属性和⽅法 def make_old_cake(self): # ⽅法⼀:代码冗余;⽗类类名如果变化,这⾥代码需要频繁修改 # Master.__init__(self) # Master.make_cake(self) # School.__init__(self) # School.make_cake(self) # ⽅法⼆: super() # ⽅法2.1 super(当前类名, self).函数() # super(Prentice, self).__init__() # super(Prentice, self).make_cake() 注意:使⽤super() 可以⾃动查找⽗类。调⽤顺序遵循 __mro__ 类属性的顺序。⽐较适合单继承 使⽤。 ⼋. 私有权限 8.1 定义私有属性和⽅法 在Python中,可以为实例属性和⽅法设置私有权限,即设置某个实例属性或实例⽅法不继承给⼦类。 故事:daqiu把技术传承给徒弟的同时,不想把⾃⼰的钱(2000000个亿)继承给徒弟,这个时候就 要为 钱 这个实例属性设置私有权限。 设置私有权限的⽅法:在属性名和⽅法名 前⾯ 加上两个下划线 __。 # ⽅法2.2 super().函数() super().__init__() super().make_cake() daqiu = Prentice() daqiu.make_old_cake() class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class School(object): def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果⼦配⽅]' # 定义私有属性 self.__money = 2000000 注意:私有属性和私有⽅法只能在类⾥⾯访问和修改。 8.2 获取和修改私有属性值 在Python中,⼀般定义函数名 get_xx ⽤来获取私有属性,定义 set_xx ⽤来修改私有属性值。 # 定义私有⽅法 def __info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): self.__init__() print(f'运⽤{self.kongfu}制作煎饼果⼦') def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) # 徒孙类 class Tusun(Prentice): pass daqiu = Prentice() # 对象不能访问私有属性和私有⽅法 # print(daqiu.__money) # daqiu.__info_print() xiaoqiu = Tusun() # ⼦类⽆法继承⽗类的私有属性和私有⽅法 # print(xiaoqiu.__money) # ⽆法访问实例属性__money # xiaoqiu.__info_print() class Master(object): def __init__(self): self.kongfu = '[古法煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class School(object): 123456789 def __init__(self): self.kongfu = '[⿊⻢煎饼果⼦配⽅]' def make_cake(self): print(f'运⽤{self.kongfu}制作煎饼果⼦') class Prentice(School, Master): def __init__(self): self.kongfu = '[独创煎饼果⼦配⽅]' self.__money = 2000000 # 获取私有属性 def get_money(self): return self.__money # 修改私有属性 def set_money(self): self.__money = 500 def __info_print(self): print(self.kongfu) print(self.__money) def make_cake(self): self.__init__() print(f'运⽤{self.kongfu}制作煎饼果⼦') def make_master_cake(self): Master.__init__(self) Master.make_cake(self) def make_school_cake(self): School.__init__(self) School.make_cake(self) # 徒孙类 class Tusun(Prentice): pass daqiu = Prentice() xiaoqiu = Tusun() # 调⽤get_money函数获取私有属性money的值 print(xiaoqiu.get_money()) # 调⽤set_money函数修改私有属性money的值 xiaoqiu.set_money() 九. 总结 继承的特点 ⼦类默认拥有⽗类的所有属性和⽅法 ⼦类重写⽗类同名⽅法和属性 ⼦类调⽤⽗类同名⽅法和属性 super()⽅法快速调⽤⽗类⽅法 私有权限 不能继承给⼦类的属性和⽅法需要添加私有权限 语法 59 print(xiaoqiu.get_money()) class 类名(): # 私有属性 __属性名 = 值 # 私有⽅法 def __函数名(self): 代码
⼆. 多态 2.1 了解多态 多态指的是⼀类事物有多种形态,(⼀个抽象类有多个⼦类,因⽽多态的概念依赖于继承)。 定义:多态是⼀种使⽤对象的⽅式,⼦类重写⽗类⽅法,调⽤不同⼦类对象的相同⽗类⽅法,可以 产⽣不同的执⾏结果 好处:调⽤灵活,有了多态,更容易编写出通⽤的代码,做出通⽤的编程,以适应需求的不断变 化! 实现步骤: 定义⽗类,并提供公共⽅法 定义⼦类,并重写⽗类⽅法 传递⼦类对象给调⽤者,可以看到不同⼦类执⾏效果不同 2.2 体验多态 class Dog(object): def work(self): # ⽗类提供统⼀的⽅法,哪怕是空⽅法 三. 类属性和实例属性 3.1 类属性 3.1.1 设置和访问类属性 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。 类属性可以使⽤ 类对象 或 实例对象 访问。 class Dog(object): def work(self): # ⽗类提供统⼀的⽅法,哪怕是空⽅法 12 三. 类属性和实例属性 3.1 类属性 3.1.1 设置和访问类属性 类属性就是 类对象 所拥有的属性,它被 该类的所有实例对象 所共有。 类属性可以使⽤ 类对象 或 实例对象 访问。 class Dog(object): def work(self): # ⽗类提供统⼀的⽅法,哪怕是空⽅法 print('指哪打哪...') class ArmyDog(Dog): # 继承Dog类 def work(self): # ⼦类重写⽗类同名⽅法 print('追击敌⼈...') class DrugDog(Dog): def work(self): print('追查毒品...') class Person(object): def work_with_dog(self, dog): # 传⼊不同的对象,执⾏不同的代码,即不同的work函数 dog.work() ad = ArmyDog() dd = DrugDog() daqiu = Person() daqiu.work_with_dog(ad) daqiu.work_with_dog(dd) --》追击敌⼈... 追查毒品... class Dog(object): tooth = 10 wangcai = Dog() xiaohei = Dog() print(Dog.tooth) # 10 print(wangcai.tooth) # 10 print(xiaohei.tooth) # 10 类属性的优点 记录的某项数据 始终保持⼀致时,则定义类属性。 实例属性 要求 每个对象 为其 单独开辟⼀份内存空间 来记录数据,⽽ 类属性 为全类所共有 ,仅占⽤⼀份内存,更加节省内存空间。 3.1.2 修改类属性 类属性只能通过类对象修改,不能通过实例对象修改,如果通过实例对象修改类属性,表示的是创建了 ⼀个实例属性。 3.2 实例属性 class Dog(object): tooth = 10 wangcai = Dog() xiaohei = Dog() # 修改类属性 Dog.tooth = 12 print(Dog.tooth) # 12 print(wangcai.tooth) # 12 print(xiaohei.tooth) # 12 # 不能通过对象修改属性,如果这样操作,实则是创建了⼀个实例属性 wangcai.tooth = 20 print(Dog.tooth) # 12 print(wangcai.tooth) # 20 print(xiaohei.tooth) # 12 class Dog(object): def __init__(self): self.age = 5 def info_print(self): print(self.age) wangcai = Dog() print(wangcai.age) # 5 # print(Dog.age) # 报错:实例属性不能通过类访问 wangcai.info_print() # 5 四. 类⽅法和静态⽅法 4.1 类⽅法 4.1.1 类⽅法特点 需要⽤装饰器 @classmethod 来标识其为类⽅法,对于类⽅法,第⼀个参数必须是类对象,⼀般以 cls 作为第⼀个参数。 4.1.2 类⽅法使⽤场景 当⽅法中 需要使⽤类对象 (如访问私有类属性等)时,定义类⽅法 类⽅法⼀般和类属性配合使⽤ 4.2 静态⽅法 4.2.1 静态⽅法特点 需要通过装饰器 @staticmethod 来进⾏修饰,静态⽅法既不需要传递类对象也不需要传递实例对象 (形参没有self/cls)。 静态⽅法 也能够通过 实例对象 和 类对象 去访问。 4.2.2 静态⽅法使⽤场景 当⽅法中 既不需要使⽤实例对象(如实例对象,实例属性),也不需要使⽤类对象 (如类属性、类⽅ 法、创建实例等)时,定义静态⽅法 取消不需要的参数传递,有利于 减少不必要的内存占⽤和性能消耗 class Dog(object): __tooth = 10 @classmethod def get_tooth(cls): return cls.__tooth wangcai = Dog() result = wangcai.get_tooth() print(result) # 10 五. 总结 ⾯向对象三⼤特性 封装 继承 多态 类属性 归属于类对象的属性,所有对象共有的属性 实例属性 类⽅法 静态⽅法 class Dog(object): @staticmethod def info_print(): print('这是⼀个狗类,⽤于创建狗实例....') wangcai = Dog() # 静态⽅法既可以使⽤对象访问⼜可以使⽤类访问 wangcai.info_print() Dog.info_print() @classmethod def xx(): 代码 @staticmethod def xx(): 代码
创建classmethod时,该对象实例的class cls
是作为第一个输入变量的,而不是该实例本身(如果是实例本身的话,第一个输入变量就是self
, 就是一个普通的我们常用的情况了)
这样创建的classmethod 有什么好处呢? 好处就是你可以直接用class来call这个函数,而不需要费周折地先去创建一个实例(class instance)。
而staticmethods呢,它没有默认的第一个输入变量。 它跟我们在一个空白的script里写的一个普通的函数 def fund():...
没有任何实质的区别。唯一的不同就是你要通过 类class
或者实例instance
来call它。
import time
class Date:
def __init__(self,year,month,day):
self.year = year
self.month = month
self.day = day
@staticmethod
def now():
t = time.localtime()
return Date(t.tm_year,t.tm_mon,t.tm_mday)
class EuroDate(Date):
def __str__(self):
return "year:%s month:%s day:%s" %(self.year,self.month,self.day)
e = EuroDate.now()
print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
# 代码的规范没有建立起来 from abc import ABCMeta,abstractmethod class Payment(metaclass=ABCMeta): # 抽象类 @abstractmethod # 如果我必须要实现pay方法,那么我需要给pay加一个装饰器 def pay(self): pass # 创建的这个pay并没有内容, # 之所以写一个pay是为了提醒所有子类你一定要实现一个pay方法 @abstractmethod def back(self): pass class Wechatpay(Payment): def __init__(self,name,money): self.name = name self.money = money def pay(self): print('%s通过微信支付了%s元'%(self.name,self.money)) class Alipay(Payment): def __init__(self,name,money): self.name = name self.money = money def pay(self): print('%s通过支付宝支付了%s元'%(self.name,self.money)) class ApplePay(Payment): def __init__(self, name, money): self.name = name self.money = money def pay(self): print('%s通过apple pay支付了%s元' % (self.name, self.money)) def back(self): print('退款') # 归一化设计 def pay(person): person.pay() ApplePay('alex',20000)
抽象类 :Payment这个类是一个抽象类 抽象类做什么事儿 : 约束所有的子类 必须实现被abstractmethod装饰的方法名 给我们的代码指定规范 特点 : 抽象类不能实例化,只是作为具体的类的规范 抽象类长什么样 class 类名(metaclass = 'ABCMeta'): @abstractmethod def 规定的方法名(self):pass @abstractmethod def 规定的方法名(self):pass @abstractmethod def 规定的方法名(self):pass
类只能单继承,所以抽象类 只能是所有的子类只有一个规范 # java 当中没有多继承的类 # 接口 接口可以多继承 # 在python里没有接口的专用语法 # 我们只是通过类的多继承 模仿接口的效果 from abc import ABCMeta,abstractmethod class NormalAnnimal(metaclass=ABCMeta): @abstractmethod def eat(self):pass @abstractmethod def drink(self):pass class FlyAnimal(metaclass=ABCMeta): @abstractmethod def fly(self):pass class SwimAnimal(metaclass=ABCMeta): @abstractmethod def swim(self):pass class WalkAnimal(metaclass=ABCMeta): @abstractmethod def walk(self):pass class Frog(NormalAnnimal,SwimAnimal,WalkAnimal): def eat(self): pass class Tiger(NormalAnnimal,SwimAnimal,WalkAnimal):pass class Swan(NormalAnnimal,FlyAnimal,SwimAnimal,WalkAnimal):pass class Parrot(NormalAnnimal,FlyAnimal,WalkAnimal): def talk(self): pass # 抽象类 是单继承的规范 # 接口类 是多继承的规范 # java # 接口里面定义的所有的方法 都不能写具体的实现 pass # 抽象类里面定义的所有的抽象方法 内部是可以完成一些简单的代码
namedtuple
from collections import namedtuple Course = namedtuple('Course',['name','price','period']) python = Course('python',20000,'6 month') print(python.name) print(python.price) print(python.period) print(type(python)) print(python)
---->
python
20000
6 month
<class '__main__.Course'>
Course(name='python', price=20000, period='6 month')
单例模式
Python单例模式的四种方法 在这之前,先了解super()和__new__()方法 super()方法: 返回一个父类或兄弟类类型的代理对象,让你能够调用一些从继承过来的方法。 它有两个典型作用: a. 在单继承的类层次结构中,super()可用于引用父类而不显式父类名称,从而使代码更易于维护。 b. 在多重继承中,可以保证公共父类仅被执行一次。 __new__方法: a.它是一个类级别的静态方法。通常用于控制生成一个新实例的过程。 b.返回的是一个实例化出来的实例 下面为四种实现单例模式的方法 1. 使用__new__方法 复制代码 class Singleton(object): def __new__(cls, *args, **kwargs): if not hasattr(cls, '_instance'): orig = super(Singleton, cls) cls._instance = orig.__new__(cls, *args, **kwargs) rerurn cls._instance class A(Singleton): pass # 类A即为单例类 复制代码 2.共享属性 复制代码 # 创建实例时把所有实例的__dict__指向同一个字典,这样它们都具有相同的属性和方法(类的__dict__存储对象属性) class Singleton(object): _state = {} def __new__(cls, *args, **kwargs): ob = super(Singleton,cls).__new__(cls, *args, **kwargs) ob.__dict__ = cls._state return ob class B(Singleton): pass # 类B即为单例类 复制代码 3.使用装饰器 复制代码 def singleton(cls): instance = {} def wapper(): if cls not in instance: instance[cls] = cls(*args, **kwargs) return instance[cls] return wapper @singleton class C: pass # 类C即为单例类 复制代码 4.import方法 复制代码 # 作为Python模块时是天然的单例模式 #创建一个sington.py文件,内容如下: class Singleton(object): def foo(self): pass mysington = Singleton() # 运用 from sington import mysington mysington.foo()