小知识点:
面向对象和面向过程:::
(1)面向过程(亲力亲为): 煮饭,洗菜,洗碗,切菜,炒菜,出锅 吃饭
(2)面向对象(凡事都是对象来做):女朋友(煮饭,洗菜,洗碗,切菜,炒菜,出锅) 我们直接 吃饭
点外卖 吃饭
一.类 (抽象)
类是一个独立存放变量(属性/方法)的空间。(把一些事物的共有特点封装起来。)
实例也是一个独立存放变量的空间。(每个实例都是一个独立的变量空间,不同实例之间的空间不可见)
类名要大写,实例名要小写。
实例名.属性名 调用某一个实例属性。
类名.属性名 调用封装在类里面的类的属性。
类编码风格:
类名应采用驼峰命名法,即将类名中的每个单词的首字母都大写,而不使用下划线。实例名
和模块名都采用小写格式,并在单词之间加上下划线。
对于每个类,都应紧跟在类定义后面包含一个文档字符串。这种文档字符串简要地描述类的
功能,并遵循编写函数的文档字符串时采用的格式约定。每个模块也都应包含一个文档字符串,
对其中的类可用于做什么进行描述。
可使用空行来组织代码,但不要滥用。在类中,可使用一个空行来分隔方法;而在模块中,
可使用两个空行来分隔类。
需要同时导入标准库中的模块和你编写的模块时,先编写导入标准库模块的 import 语句,再
添加一个空行,然后编写导入你自己编写的模块的 import 语句。在包含多条 import 语句的程序中,
这种做法让人更容易明白程序使用的各个模块都来自何方。
定义:
class 类名:
pass
1.例如:
class Person: #定义类名要首字母大写。
a = ‘两只手,两条腿’ #封装在类里面类中的属性
#类,是一个独立存放变量(属性/方法)的空间。
wumou = Person() #实例名 = 类名() 实例
zhangmou = Person()
wumou.name = “吴某” #实例的特征 实例属性 (一个实例的特征,就是属性)
wumou.age = 18
zhangmou.age = 20
print(Person.a) #调用类的属性
print(wumou.age) #调用实例属性
类与实例之间的关系:::
(1)类:::
是一类事物的抽象,不是真实存在的,描绘了该类事物的共性。
例如:“人”,“动物”
(2)实例:::
某类事物的具体个体,是该类事物的具体表现,它是真实存在的。
例如:“吴某”是具体的某个人,
“张某”也是具体的某个人。
2.私有属性:
在python中有两个私有属性,分别是在属性前加一个下划线()和两个下划线()
一个下划线外部可以直接访问,两个下划线外部不能直接访问。
一个下划线只是做简单的标记。
两个是私有属性,不能够直接使用。
python当中的私有属性没有绝对的私有。
class Person:
_sex = “男”
__age = 18
wuhan = Person() #实例
print(Person._sex) #调用类属性
print(Person.__age) #双下划线会报错,不可以直接访问双下划线变量名
print(Person._Person__money) #这样就可以访问双下划线的属性
###在python中,_和__的使用更多的是一种规范/约定,没有真正限制的目的###
###定义类中的私有属性也可以被子类继承###
小知识点:::
dir() 可以查看方法,里面可以放类名。
3.类里面的方法
方法就是封装在类里面的一种特殊函数。
例:
class Person:
def sing(self): #方法,在类里面写函数叫做在类里面定义方法。
print(“我最帅!”) #里面有一个默认值none。 print(“我最帅!”,none)
wuhan = Person() #定义实例,写类必备。
wuhan.sing() #调用类里面的方法。 格式:实例化对象.方法()
Person.sing(self = ‘要传入的东西’)
实例方法 的调用过程和 self:::
(1)self:通常,将默认会传入的那个参数命名为self,用来表示调用这个方法的实例对象本身。
(2)实例方法:方法总是定义在类中,但是却叫“实例方法”,因为它表示该类所有实例所共有的行为。
小知识点:::self指的是实例,谁去使用它,那么它就是谁。
例:
class Person:
def sing(self):
print(“老师在唱歌%s”%self.geci)
print(id(self)) #会发现此处的self的id和下面的laoshi的id是一样的
laoshi = Person() #在这个实例中,laoshi使用了self,所以self就是laoshi
print(id(laoshi))
#和函数的传参一样,只是会先传一个自身的实例self
laoshi.geci = “温暖了寂寞”
laoshi.sing()
- init 双下划线
初始化方法,作用是在实例化的时候,自动调用。(魔法方法)
“初始化”特殊方法:
在Python中有很多以双下划线开头且以双下划线结尾的固定方法,它们会在特定的时机被处罚执行。
__init__就是其中之一,它会在实例化之后自动被调用。以完成实例的初始化。
可以在创建对象时,为对象实现一些初始化的操作,提供一些默认值,需要为类定义实例属性的时候才会执行__init__方法。
class Person:
def init(self.name):
self.name = name #self.name是实例属性;name是方法。
def sing(self):
print('吴某最帅')
wumou = Person(“吴某”) # 实例化 自动调用我们的初始化方法,把吴某这个名字给了name
(这句代码意味着 wumou.name = “吴某”(定义一个实例属性) wumou.name相当于self.name,"吴某"相当于给了name)
魔法方法:每一个魔法方法都有它特定的功能。
小知识点:
在python中,指向被删除了,就会被回收。
del删除指向,一个变量指向没有了就会被回收。
del调用的就是__init__魔法方法。
例如:列表方法中,del 列表名,再查看这个列表的时候就会报错,因为del把指向删除了。
del 析构,也叫销毁初始化方法(销毁上面的那个),是在这个文件运行完然后触发。(魔法方法)
__del__就是一个析构函数,当使用del删除对象时,会调用它本身的析构函数。提示开发者,对象被销毁了,方便调试,进行一些必要的清理工作
浅显点理解就是:(当实例对象引用数为0的时候就会调用这个魔术方法)
即当类里面使用了del魔法方法的时候,如果使用了del删除,那么就会调用__del__魔法方法;如果没有使用del删除,那么在程序的最后,会自动回收内存地址,就会调用__del__魔法方法。
入门:
class Person:
pass
hansha = Person()
print(hansha) #输出为:hansha这个实例化的对象指向的对象。即为:<main.Person object at 0x00000175C3AFC1D0>
del hansha
print(hansha) #输出会报错,因为指向被删除了。即为:NameError: name ‘hansha’ is not defined
稍微升一点级:
python中一个程序执行完了,内存空间就会被回收,回收掉那么指向就没有了。
class Person:
def del(self): #相当于重写了python的__del__方法。在列表里使用del删除时调用的是python默认的__del__方法。
print(‘好好学习’)
hansha = Person()
print(11111)
print(22222)
输出为:
11111
22222
好好学习
来个对比的例子仔细看看:
当指向删除完了之后会调用__del__魔法方法。
class Person:
def del(self):
print(‘好好学习’)
hansha = Person()
print(11111)
del hansha
print(22222)
输出为:
11111
好好学习
22222
总结的高级版:
基于变量计数的对象销毁机制
当没有一个变量指向某个对象的时候,python会自动销毁这个对象,以便回收内存空间。
del关键字,可以删除一个变量的指向。
class Person:
def __init__(self,name): #初始化方法
self.name = name
def __del__(self): #析构方法(销毁方法)
print(self.name,"被销毁了")
wuhan = person(“无名”)
del wuhan #输出为:被销毁了
这里为引用了《python编程从入门到实践》
二,
继承:
例子:
class Car():
“”“一次模拟汽车的简单尝试”""
def init(self, make, model, year):
self.make = make
self.model = model
self.year = year
self.odometer_reading = 0
def get_descriptive_name(self):
long_name = str(self.year) + ’ ’ + self.make + ’ ’ + self.model
return long_name.title()
def read_odometer(self):
print(“This car has " + str(self.odometer_reading) + " miles on it.”)
def update_odometer(self, mileage):
if mileage >= self.odometer_reading:
self.odometer_reading = mileage
else:
print(“You can’t roll back an odometer!”)
def increment_odometer(self, miles):
self.odometer_reading += miles
class ElectricCar(Car):
“”“电动汽车的独特之处”""
def init(self, make, model, year):
“”“初始化父类的属性”""
super().init(make, model, year)
#让一个类继承另一个类后,可添加区分子类和父类所需的新属性和方法。
如:self.battery_size = 70
我们还添加了一个名为 describe_battery() 的方法,它打印有关电瓶的信息
( def describe_battery(self):
“”“打印一条描述电瓶容量的消息”""
print("This car has a " + str(self.battery_size) + “-kWh battery.”)
my_tesla = ElectricCar(‘tesla’, ‘model s’, 2016)
print(my_tesla.get_descriptive_name())
my_tesla.describe_battery() )
my_tesla = ElectricCar(‘tesla’, ‘model s’, 2016)
print(my_tesla.get_descriptive_name())
首先是 Car 类的代码。创建子类时,父类必须包含在当前文件中,且位于子类前面。
我们定义了子类 ElectricCar 。定义子类时,必须在括号内指定父类的名称。方法 init()
接受创建 Car 实例所需的信息。
super() 是一个特殊函数,帮助Python将父类和子类关联起来。这行代码让Python调用
ElectricCar 的父类的方法 init() ,让 ElectricCar 实例包含父类的所有属性。父类也称为超
类(superclass),名称super因此而得名。也可以直接Car.init()。
在子类中调用父类的初始化方法格式是:父类名.init(self) 但是super是直角包括所有父类,但是父类名的需要一个个写。
为测试继承是否能够正确地发挥作用,我们尝试创建一辆电动汽车,但提供的信息与创建普
通汽车时相同。我们创建 ElectricCar 类的一个实例,并将其存储在变量 my_tesla 中。这
行代码调用 ElectricCar 类中定义的方法 init() ,后者让Python调用父类 Car 中定义的方法
init() 。我们提供了实参 ‘tesla’ 、 ‘model s’ 和 2016 。
除方法 init() 外,电动汽车没有其他特有的属性和方法。当前,我们只想确认电动汽车
具备普通汽车的行为:
2016 Tesla Model S
#####1.
重写父类的方法:
对于父类的方法,只要它不符合子类模拟的实物的行为,都可对其进行重写。为此,可在子
类中定义一个这样的方法,即它与要重写的父类方法同名。这样,Python将不会考虑这个父类方
法,而只关注你在子类中定义的相应方法。
多继承中super调用所有父类的被重写的方法。super本质是用mor算法的顺序调用的。
父类也称为基类。
######2.
导入类:
Python允许你将类存储在模块
中,然后在主程序中导入所需的模块。
将 Car 类存储在一个名为car.py的模块中,使用该模块的程序都必须使用更具体的文件名,如my_car.py,其中只包含 Car 类的代码。
我们包含了一个模块级文档字符串(在该模块的最上面),对该模块的内容做了简要的描述。你应为自己
创建的每个模块都编写文档字符串。
下面来创建另一个文件——my_car.py,在其中导入 Car 类并创建其实例:
from car import Car #从一个只包含一个类的模块中导入这个类
from car import ElectricCar #从一个包含多个类的模块中导入一个类
from car import Car, ElectricCar #从一个有多个类的模块中导入多个类
import car #导入整个模块 我们使用语法 module_name.class_name 访问需要的类
from module_name import * #导入模块中的所有类 (不建议使用,如果要用,推荐使用导入整个模块)
import 语句让Python打开模块 car ,并导入其中的 Car 类。这样我们就可以使用 Car 类了,
就像它是在这个文件中定义的一样。
######3.
继承:
可以处理功能的迭代更新,以及拓展
重用代码,方便代码的管理和修改。
类名.bases 可以查看类的父类有哪些,注意要print。
每一个类,如果你不写继承,那么这个类继承的就是object。
class Father(object): #object默认自动创建了__init__初始化方法
#父类
pass
fa = Father() #实例,自动调用父类的__init__ 初始化方法就叫做继承。
例子:
class Father: 父类
def eat(self):
print('大吃一顿')
class Son1(Father): #子类Son1继承父类Father
pass
hansha = Son1()
hansha.eat() #子类Son1可以使用父类Father中的eat方法。
高级的来咯!!!
多继承:::
多继承优先级:从左往右,优先级由高到低。
如果继承的两个父类有同样的方法,那么会选择优先级高的方法,即子类会优先使用最先被继承的方法。
class Father:
def init(self,name,age):
self.name = name
def eat(self):
print('大吃一顿')
class Mother:
def init(self,name,age,sex):
self.name = name
def cook(self):
print('做菜')
class Son(Father,Mother):
pass
hansha = Son(‘寒沙’,18)
hansha.eat()
hansha.cook()
最高级的来啦!!!
class Base:
def play(self):
print(‘这是Base’)
class A(Base):
def play(self):
print(‘这是A’)
super().play() #这里调用的是B
class B(Base):
def play(self):
print(‘这是B’)
super().play() #这里调用的是Base
class C(A,B):
#当子类继承父类之后,如果子类不想使用父类的方法,可以通过重写来覆盖父类的方法
def play(self):
print(‘这是C’)
# #重写父类方法之后,如果又需要使用父类的方法:
# B().play() #第一种方法 实例化,再使用方法
# A.play(self) #第二种方法 类名使用这个方法
super().play() #这里调用的是A
c = C()
c.play()
print(C.mro) #可以通过调用类的__mro__属性或者mro方法来查看类的继承关系
#输出为(<class ‘main.C’>, <class ‘main.A’>, <class ‘main.B’>, <class ‘main.Base’>, <class ‘object’>)
#super可以使用父类的方法;在父类中也可以使用super函数;要满足mro算法规则
#根据mro的顺序来决定调用的是谁
#在python3中,类被创建时会自动创建方法解析顺序mro
######4.
mro顺序 算法 保证程序能够按序执行。
mro顺序的作用:
#保证所有的类在用(构造)他的时候只被用(构造)一次!
保证多继承的时候,每个类只出现一次。
super().init() 相当于使用了mro。
#######6.
定制属性访问 (增,删,改,查)
就是对类里的属性进行增删改查的操作
(1)增
setattr(实例名,“属性名”,值) 或者 实例名.属性 = 值
(2)删
delattr(实例名,“属性名”) #只能删除自己家的属性
(3)改
setattr(实例名,“属性名”,“新属性”) #有这个属性才可以修改
(4)查
hasattr(实例名,“属性名”) #返回布尔值,有就True,没有就False
或者
getattr(实例名,“属性名”) #存在就能取到这个值,不存在就报错
可以用成 实例名.getattr(“属性名”) 上面的几个也可以(因为在python里面已经定义好了,已经有源码),但是hasattr不可以,没有这个方法。
但是用这种方法时,要在类里面定义这种方法。(重写方法)
例如:
def getattribute(self,item):
return “属性不在”
把这个写在类里面作为一个方法。
重写一个源码,python会返回你重写的这个方法的返回值,而不会再执行源码。
举例说明:
class Rectangle:
#__init__不能使用return
def init(self,length,width):
self.length = length
self.width = width
def area(self):
#使用self 那个实例去使用它,它就是谁
return(self.length*self.width)
a = Rectangle(4,5)
################查
#判断实例有没有这个属性
print(hasattr(a,‘length’)) #输出aTrue
#实例的这个属性值是什么 获取值,没有就报错
print(getattr(a,‘length’)) #输出4
################改
setattr(a,‘width’,50) #本来应该是5,现在改成了50
#还可以写成: re .setattr(‘width’, 50)
print(getattr(a,‘width’)) #输出就是50
################增
#第一种:
#setattr 有则改,无则增
print(hasattr(a,‘name’)) #在这里实例a里面没有属性name。输出False
setattr(a,‘name’,‘hansha’) #没有就增加属性name
#还可以写成:a.setattr(‘name’, ‘hansha’)
print(hasattr(a,‘name’)) #上一句增加了name属性。输出True
#第二种:
a.age = 18
################删
print(getattr(a,‘age’)) #因为上面增加了属性age。输出为True
delattr(a,‘age’) #删除属性age
#还可以写成:a.delattr(‘age’)
print(getattr(a,‘age’)) #上面删除了属性age。输出为False
(1) + 调用的是__add__
class A:
def init(self,num1,num2):
self.num1 = num1
self.num2 = num2
def __add__(self,other): #self 实例对象 ; other 另外一个实例对象
sum1 = self.num1 + other.num1
sum2 = self.num2 + other.num2
return sum1,sum2
a = A(1,2)
b = A(3,4)
print(a+b) #输出为 (4,6)
运算符方法(了解即可)
add(self,other) # x+y
sub(self,other) # x-y
mul(self,other) # xy
mod(self,other) # x%y
iadd(self,other) # x+=y
isub(self,other) # x-=y
radd(self,other) # y+x
rsub(self,other) # y-x
imul(self,other) # x=y
imod(self,other) # x%=y
(2)在交互模式下输出的交互信息与直接print的信息有些不同,
背后的原理是 ?
str和repr原理:
return返回的必须是字符串。
print打印实例对象的时候(没有重写__repr__方法,直接是pass)显示的是 地址
如果重写了__repr__方法,那么打印的就是__repr__方法里面的东西
如果同时重写了__repr__和__str__方法,打印实例对象的时候,只会显示__str__里面的内容
例一:::
class Person:
def __repr__(self):
return '这是一个repr方法'
def __str__(self):
return '这是一个str方法'
p = Person()
print§ 输出为: 这是一个str方法
%s 使用的是__str__方法; %r 使用的是__repr__方法
例二:::
class Person:
def __repr__(self):
return '这是一个repr方法'
def __str__(self):
return '这是一个str方法'
p = Person()
print(’ %s’%p) 输出为:这是一个str方法
print(’ %r’%p) 输出为:这是一个repr方法
在python中,str和repr方法在处理对象的时候,分别调用的是对象的__str__和__repr__方法
print打印对象,调用str函数,如果对象没有定义__str__方法,则调用__repr__方法处理
在交互模式下,直接输出对象,显示 repr 的返回值
(3) 魔术方法 def call(self)
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 call 方法
class Person:
def a(self):
print('this is a ')
#实例对象加上括号就会自动调用call方法
def __call__(self,*args,**kwargs):
print('this is call')
p = Person()
p() #输出为: this is call
拓展:
类中的一些查询相关信息的方法(了解既可)
1、class 查看类名
格式: 实例.__class__
2、dict 查看全部属性,返回属性和属性值键值对形式
格式:实例.__dict__
3、doc 查看对象文档,即类中(用三个引号引起来的部分)
格式:类名.__dict__
4、bases 查看父类
格式:类名.__base__
5.mro 查看多继承的情况下,子类调用父类方法时,搜索顺序
格式:子类名.__mro__
实例.__class__.__mro__
(4)再来个魔术方法
类每次实例化的时候都会创建一个新的对象,如果要求类只能被实例化一次该怎么做呢?
__new__方法
举个例子:::
class Person:
#初始化
def __init__(self):
print('this is init')
def __new__(cls, *args , **kwargs):
print('这new方法在init之前就进行了调用')
#重写new方法
#new方法是最先被调用的
#new 必须返回父类的new方法,程序才能继续往下运行,如果不返回,即没有下面这行程序就不会往下运行。
return super().__new__(cls)
hansha = Person()
四个点理解__new__方法:
1、__new__方法是在类创建实例的时候
自动调用的。
2、实例是通过类里面的__new__方法是在
类 创建出来的。
3、先调用__new__方法创建实例,再调用 __init__方法初始化实例。
4、__new__方法,后面括号里的cls代表
的是类本身
在上面的例子中,我们可以看到创建实例的时候,自动调用了__new__,方法和__init__方法,并且
是先调用的__new__(__new__方法会在内存当中开辟一个空间)再调用的__init__方法,打印 cls 的时候显示的这个Person类
#######
new方法会开辟空间
每次实例化,这个new方法都会开辟一个新的空间
可不可以让这new方法只开辟一个空间:::单例模式
单例模式:
提前引入一些小知识点:::
第一个:
hasattr() #has attribute
hasattr() 函数用于判断对象是否包含对应的属性
hasattr(object(对象),name(“字符串,属性名”))
返回True(有的时候) False(没有的时候)
class Person:
#范式:固定的公式;固定的写法
def new(cls,*args,**kwargs):
#hasattr 判断类里面有没有这个方法
#如果类没有instance这个属性
if not hasattr(cls,‘instance’): #cls就是Person这个类本身
#没有instance这个属性就会执行下面这句
#创建instance这个属性,等于父类的new方法
#new返回父类的new方法,和返回instance都可以
cls.instance = super().new(cls) #上面说如果类没有instance这个属性就执行这句,把父类的new方法添加为类本身的属性
#在下一句在return这个类本身的这个instance属性,这样在第二次实例化的时候,return
#的仍然是第一次实例化的cls.instance,就没有返回父类的new方法,也就没有创建新的内存
#空间,而是仍然指向第一次创建的内存空间
return cls.instance #如果把返回的改为 super().new(cls),直接返回父类的new方法,这就不是单例模式,因为每次实例化都会返回父类
#的new方法,即创建一个新的内存空间。
def init(self,name):
self.name = name
a = Person(‘寒沙’)
b = Person(‘敢敢’)
print(id(a))
print(id(b))
会发现两次的id都一样了,即两次指向同一片内存空间,相当于a被b覆盖了。
意味着这两个其实引用的是同一个实例,是一个实例的不同名字
(3)描述符
描述符协议:python描述符是一个“绑定行为”的对象属性,在描述符协议中,
它可以通过方法重写属性的访问。这些方法有__get__(), set(), 和__delete__()。
如果这些方法中的任何一个被定义在一个对象中,这个对象就是一个描述符
举例说明:
#描述符:描述符就是类里面的属性base
#控制实例对象a访问 这个属性 (base) 可以做一些额外的操作
#描述符 定义了__get__ set delete 当中的一种
class Base:
def get(self,instance,owner):
print(‘恭喜玩家获得荒古宝典’)
def set(self, instance,value):
print(‘强化%s’%value)
def delete(self,instance):
print(‘武器已经损坏’)
class A:
base = Base()
#实例化
a = A()
a.base # get 会直接输出__get__方法里面的内容
a.base = 50 # set 会直接输出__set__方法里面的内容
del a.base # delete 会直接输出__delete__方法里面的内容
(4)装饰器:
原因:python是一个动态语言,因为一切都是对象。是一个脚本语言。
#########################第一个:
首先咱再看遍闭包是啥:
#闭包
def fun1():
print(‘fun1’)
def fun2():
print(‘fun2’)
return fun2
#fun1()() ===> fun2()
a = fun1()
a() #会执行两个函数
然后,咱稍微高级点,看看闭包参数。这种方法比较麻烦,所以下面就引入了装饰器,和这个的功能一模一样,不过
简单了许多:
#闭包里面有参数 回调函数
def aa(fun): #fun = f1
print(’------------aa’)
def bb():
fun() #fun() = f1()
print(’----------bb’)
return bb
def f1():
print(‘this is f1’)
def f2():
print(‘this is f2’)
cc = aa(f1)
cc() #输出为 ------------aa
this is f1
----------bb
最后,就来看看第一种装饰器:
#装饰器 在不改变原有函数的基础上面增加额外的功能
#装饰器
def aa(fun): #fun = f1
print(’------------aa’)
def bb():
fun() #fun() = f1()
print(’----------bb’)
return bb
#装饰器 被装饰的函数名字(f1)会被当做参数传递给装饰函数(aa)
#代码就是: aa(f1)
#装饰函数(aa)执行完它自己内部的代码之后,会把它的结果返回给
#被装饰的函数(f1)
#代码就是: f1 = aa(f1)
#然后下面又是f1() 就相当于 aa(f1)()
@aa # 就相当于 f1 = aa(f1) 要使用嵌套函数里面的内容 aa(f1)(),就是最后调用的时候f1加个括号
# 而注意函数外部的只要用到装饰器就会执行,而嵌套的内层函数需要调用才会执行,所以
# 用处就是把重要的东西写到嵌套的内层函数,在调用的时候才会执行
def f1():
print(‘this is f1’)
def f2():
print(‘this is f2’)
f1() #输出和上面一个一模一样
############################第二个:
#类里面的内置装饰器
引入:
class Base:
def fun(self):
print('好好学习,天天向上')
b = Base()
b.fun() # 调用类里面的方法,就会执行类里面的方法fun,打印 好好学习,天天向上
########
第一个是把类里面的方法变为属性:
class Base:
name = ‘寒沙’
@property #将方法变为属性 更加简洁
def fun(self):
return('好好学习,天天向上')
b = Base()
print(b.name) #属性的使用不需要加括号;方法的使用才要加括号
print(b.fun) #现在类里面的方法fun就变成了类的属性
#输出为:
寒沙
好好学习,天天向上
########
第二个是把类里面的方法变为静态方法,让其可以像使用函数一样去使用,而不需要再实例化才能使用:
class Base:
@staticmethod #静态方法 方法能够像函数一样的去使用, 比如在类里面,你要写一些闭包什么的就可以在这里面写,相当于扩展了一些功能。
def fun2(): # 注意:这里已经不需要self 和class类断开联系
print('过年好,新年好')
#再来个不加装饰器的
def func(self):
print('这是普通方法')
Base.fun2() # fun2已经变为静态方法,可以像使用函数一样的使用
#输出为: 过年好,新年好
Base是类名;Base() 就是实例化
Base().func() # 而没有使用装饰器的方法就需要先实例化,才能去使用
#输出为:这是普通方法
########
第三个是类方法
class Base:
def func(self):
print('这是普通方法')
@classmethod
def fun3(cls): #没有self 和实例无关,这是类方法 ; 有self的是实例方法,需要先实例化才能使用
print('cls类方法')
cls().func() #cls 代表类本身,即Base这个类
#类方法的使用,也不用实例化 直接类名点方法
Base.fun3()
###########################第三个:
#类装饰器 必须使用__call__方法
class Base:
def __init__(self,name):
self.name = name
def __call__(self,*args,**kwargs):
print('this is call')
@Base # func = Base(func) 被装饰函数(func)当做参数传递给装饰函数(Base)
def func():
print(‘this is func’)
func() # 此处的括号就相当于 func() = Base(func)()
# __call__方法只要实例化就会被调用
#输出为: this is call
看看高级点的:
class Base:
def __init__(self,fun):
self.fun = fun
def __call__(self,*args,**kwargs):
self.fun() #就会打印 this is func
print('this is call')
def __str__(self):
return 'this is str'
@Base # func = Base(func) 相当于实例化 被装饰函数(func)当做参数传递给装饰函数(Base)
def func():
print(‘this is func’)
func() # 此处的括号就相当于 func() = Base(func)()
# __call__方法只要实例化就会被调用
print(func) # 打印类的实例,就会调用类里面的__str__方法
#输出为:
this is func
this is call
this is str
拓展一下呗:::
来个装饰器的习题:
测试type和isinstance两个函数,那个速度更加的快
#程序运行速度比较快 只查看上面两个
函数 运行一次的时间显示不出来效果
可以查看循环一万次的时间
#time.time() 计算目前的时间 时间戳(格林威治时间, 1970.1.1到现在的总秒数)
import time
def funa(fun):
def funb():
a = time.time()
fun()
b = time.time()
print(‘函数运行了%s’%(b-a))
return funb
@funa
def f1():
for i in range(100000):
type(1)
f1()
@funa
def f2():
for i in range(100000):
isinstance(1,int)
f2()
(3)多态
:提高了方法的灵活程度
class Student(object):
def print_uid(self):
print(“我是UID”)
class VIPStudent(Student):
print(“我是VIP学院”)
class PutongStudent(Student):
print(“我是普通学员”)
class BaianStudent(Student):
print(“我是卖课程的,为你们服务的”)
class Jiezhang(object):
def jiezhang(self,student:Student):
student.print_uid()
zhouzhanghong = Student() #实例化
baiyintao = VIPStudent()
cuihaolin = PutongStudent()
baian = BaianStudent()
check = Jiezhang()
check.jiezhang(zhouzhanghong)
check.jiezhang(baiyintao)
check.jiezhang(cuihaolin)
check.jiezhang(baian)