5.1 类定义和方法
1.类的定义: 类 是一个独立存放变量(属性/方法)的空间
1 class 类名: 2 pass 3 4 实例名 = 类名()
2.运算符“.” 调用类的属性或方法
实例可以访问类的属性
类不可以访问实例的属性
实例也是一个独立存放变量的空间
实例和实例没有关联 本身没有这个属性 就会去类中找
3.私有属性
在python中有两私有属性,分别是在属性前加
一个下换线(_) 和两个下划线(__)
一个下滑线外部可以直接访问,二个下划线外部不可以直接访问
4.方法
就是封装在类里的一种特殊的函数
5.“实例方法” self代表实例本身
表示的是“实例”的行为给实例用的,和函数的传参一样,只是会先传一个自身的实例self,
方法总是定义在类中的,但是却叫“实例方法”,因为它表示该类所有实例所共有的行为
1 class persson(object): 2 def eat(self): 3 print('{}正在吃烦'.format(self.name)) 4 return 100 5 6 nanbei=persson() 7 nanbei.name='南北' 8 a=nanbei.eat() 9 print(a)
5.2 初始化和析构 (dir查看属性与方法)
Python中有很多以双下划线开头且以双下划线结尾的固定方法。他们会在特定的时机被触发执行。
init 就是其中之一,它会在实例化之后自动被调用。以完成实例的初始化。
1. init 的参数传递过程:
1 class person (object): 2 def __init__(self,name): 3 self.name=name 4 print('{}正在上课'.format(self.name)) 5 6 nanbei=person('南北') 7 nanbei.__init__('南北') 8 person.__init__(nanbei,'南北')
2. “析构”:
通常在实例被销毁的时候, 长时间不用即可析构
__del__”就是一个析构函数了,当使用del 删除对象时,会调用他本身的析构函数。
提示开发者,对象被销毁了,方便调试。进行以写必要的清理工作。
当没有一个变量指向某个对象的时候,Python会自动销毁这个对象,以便回收内存空间。
程序报错时 相当于结束 会进行空间释放
3. del 关键字
可以删除一个变量的指向。
5.3 继承和魔术方法 super
1.继承
一个类可以继承一个类,继承之后可以使用父类的方法和属性,
公用部分可以写成父类 在子类中重写不同部分
先在子类中找 再去父类中找
1 class Rec(object): 2 def say_hello(self): 3 print('aiwozhonghua ') 4 5 class Son(Rec): 6 pass 7 8 s=Son() 9 s.say_hello()
每个类中bases 特殊属性(返回tuple)
__bases__:查看类的直接父类
__mro__:查看类的继承路径
2.多继承
当继承多个父类时,如果父类中有相同的方法,
那么子类会优先使用最先被继承的方法 (左边的)
当子类继承父类之后,如果子类不想使用父类的方法,可以通过重写来覆盖父类的方法
1 class Base(object): 2 def play (self): 3 print('asdasd') 4 5 class A (Base): 6 def play(self): 7 print('健身卡') 8 class B(Base): 9 def play(self): 10 print('健身ASD卡') 11 12 class C(A,B): 13 pass 14 15 c=C() 16 c.play() 17 print(C.__mro__)
当子类重写父类方法之后,子类如果想再次调用父类的方法, 可以使用这两种方法
方法一:
1 class C(A, B): 2 3 def play(self): 4 5 A.play(self) 6 print('这是C') 7 8 方法二: 9 class C(A, B): 10 11 def play(self): 12 13 super().play() 14 print('这是C')
3.super 函数
可以调用父类的方法 (调用上一级)
在父类中也可以使用super函数
可以通过调用类的__mor__属性或者mro方法来查看类的继承关系
4.魔术方法 (应用并不多)
在python中,str和repr方法在处理对象的时候,分别调用的是对象的__str__和__repr__方法
print打印对象,调用str函数,如果对象没有定义__str__方法,则调用__repr__方法处理
在交互模式下,直接输出对象,显示 __repr__ 的返回值
1.str
尽可能的提供简洁且有用的信息。
让用户尽可能吸收到必要的信息。
必须要有返回值 且是字符串类型
2.repr
尽可能向开发者提供创建该对象时的必要信息。
让开发者可以直接通过复制粘贴来重建对象。
必须要有返回值 且是字符串类型
3.类的实例向函数一样被调用
正常情况下,实例是不能像函数一样被调用的,要想实例能够被调用,就需要定义 __call__ 方法
1 class Test (object): 2 def hi (self): 3 print('hi ') 4 5 def __call__(self, *args, **kwargs): 6 self.hi() 7 8 def test2(): 9 print('haha') 10 11 t=Test() 12 t() #此时只会调用__call__方法 13 test2()
4、class 查看类名
格式: 实例.__class__
5、dict 查看全部属性,返回属性和属性值键值对形式
格式:实例.__dict__
6、doc 查看对象文档,即类中(用三个引号引起来的部分)
格式:类名.__dict__
7、bases 查看父类
格式:类名.__base__
8.mro 查看多继承的情况下,子类调用父类方法时,搜索顺序
格式:子类名.__mro__
1 class Rectang(object): 2 def __init__(self,length,width): 3 self.length=length 4 self.width=width 5 6 def get_area(self): 7 print(self.length*self.width) 8 9 def __add__(self, other): 10 length=self.length+other.length 11 width=self.width+other.width 12 result=Rectang(length,width) 13 return result 14 15 class Square(Rectang): 16 def __init__(self,side_length): 17 super().__init__(side_length,side_length) 18 19 def __call__(self, *args, **kwargs): 20 return self.get_area() 21 22 def __str__(self): 23 return '边长为:{}'.format(self.length) 24 25 s=Square(150) 26 print(s) 27 s() 28 29 a=Rectang(20,10) 30 b=Rectang(50,30) 31 new_rec=a+b # a.__add__(b) 32 print(type(new_rec)) 33 new_rec.get_area()
5.4 new方法 (重写后必须return一个实例出来)
1.new方法
return super().__new__(cls)
1、__new__方法是在类创建实例的时候自动调用的。
2、实例是通过类里面的__new__方法是在 类 创建出来的。
3、先调用__new__方法创建实例,再调用 __init__方法初始化实例。
4、__new__方法,后面括号里的cls代表的是类本身
在上面的例子中,我们可以看到创建实例的时候,自动调用了new,方法和init方法,并且 是先调用的new再调用的init方法,打印 cls 的时候显示的这个Base类
1 class Test (object): 2 def __init__(self): 3 print('init 方法') 4 5 def __new__(cls, *args, **kwargs): 6 print('new 方法') 7 return super().__new__(cls) 8 9 t=Test()
2.单例模式 (只生成一个实例)
1 class Test (object): 2 __insance=None #1. 定义一个私有属性等于None 3 def __init__(self): 4 print('init 方法') 5 6 def __new__(cls, *args, **kwargs): 7 if cls.__insance is None: 8 cls.__insance=super().__new__(cls) 9 return cls.__insance 10 a=Test 11 b=Test 12 print(a is b) 13 print(id(a)) 14 print(id(b))
#2. (然后我们判断它是不是等于None,如果等于None,我们调用父类的方法创建一个实例对象,并把返回的对象赋值给 __instance,并且返回__instance)
#3. 如果__instance不等于None,那就说明已经创建了对象 我们直接把__instance返回出去。
#单例模式实现的原理:通过重写__new__方法,让__new__只能进行一次实例创建。
#在上面的例子中,我们可以看到两个实例的ID是相同的,意味着第二次创建的时候,并没有真正的去创建,而是引用的第一次创的实例,只是同一个实例的不同名字
5.5 定制属性访问
-
查:
hasattr(re, 'length') # 返回bool值 是否有这个属性 getattr(re, 'length') # 返回属性值 获取属性的值 re . getattribute('length') 该方法在访问实例属性时,自动调用
re . getattr('length') 该方法在访问不存在的属性时,调用
-
改:
setattr(re , 'length', 6) 有则改 无则增 re .setattr('length', 5) 该方法在访问实例属性时,自动调用
-
增:
re .aaa = 1 setattr(re, 'bbb', 2) # 有bbb属性就改,没有就增 re.setattr('ccc', 3) # 同上
-
删:
delattr(re , 'ccc') 删除实例属性 re .delattr('bbb') del re
5.6 描述方法 (了解)
__get__() #在访问该类创建的实例时调用
__set__() #在修改该类创建的实例时调用
__delete__() #在删除该类创建的实例时调用
5.7 装饰器
1 def girl(): 2 return '这是一个女孩' 3 print(girl()) 4 5 def modify(func): 6 def wrapper(): 7 result =func() 8 return result+'很6' 9 return wrapper 10 11 girl= modify(girl) 12 print(girl()) 13 14 15 ############################ 16 17 def modify(func): 18 def wrapper(): 19 result =func() 20 return result+'很6' 21 return wrapper 22 23 @modify 24 def girl(): 25 return '这是一个女孩' 26 print(girl()) 27 28 29 python自带的三个内置装饰器 30 class Rectangle: 31 def __init__(self, length, width): 32 self.length = length 33 self.width = width 34 def area(self): 35 areas = self.length * self.width 36 return areas 37 @property # 就像访问属性一样 少一个括号 38 def area(self): 39 return self.width * self.length 40 @staticmethod # 静态方法 和class类断开联系 41 def func(): 42 print(‘staticmethod func’) 43 @classmethod # 类方法 44 def show(cls): # cls代表类本身 不用实例化即可调用 45 print(cls) 46 print('show fun')
5.8 类装饰器
1 class Test_Class: 2 def __init__(self, func): 3 self.func = func 4 def __call__(self): 5 print('类') 6 return self.func 7 @Test_Class 8 def fun_test(): 9 print('这是个测试函数')
类也可以做装饰器,但是需要定义 call 方法
1 class Rectangle: 2 def __init__(self, length, width): 3 self.length = length 4 self.width = width 5 6 def area(self): 7 areas = self.length * self.width 8 return areas 9 @property 10 def get_area(self): 11 return self.length*self.width 12 @staticmethod # 静态方法 和class类断开联系 13 def func(): 14 print('staticmethod func') 15 16 rec=Rectangle(10,8) 17 print(rec.get_area) 18 Rectangle.func() 19 20 ######################################## 21 # 类装饰器 22 23 import time 24 class Myclass (object): 25 def __init__(self,func): 26 self.func=func 27 28 def __call__(self, *args, **kwargs): 29 start_time = time.time() 30 self.func(*args) 31 r_time = time.time() - start_time 32 print(r_time) 33 34 @Myclass 35 def girl (name): 36 print('girl name is {} '.format(name )) 37 38 girl('ada') 39 40 ######################################## 41 42 查看函数运行时间: 43 44 import time 45 def run_time (func): 46 def wrapper(): 47 start_time=time.time() 48 result=func() 49 r_time=time.time()-start_time 50 print(r_time) 51 return result 52 return wrapper 53 54 @run_time 55 def say_hello(): 56 print('hello') 57 58 say_hello() 59 60 61 ######################################## 62 63 import time 64 def run_time (func): 65 def wrapper(): 66 start_time=time.time() 67 func() 68 t=time.time()-start_time 69 print('shijianwei{} '.format(t)) 70 return wrapper() 71 72 @run_time 73 def test_type(): 74 for i in range(1000): 75 type(1) 76 77 @run_time 78 def test_isinstance(): 79 for i in range(1000): 80 isinstance(1,int)
5.9、补充
5.9.1、什么是装饰器?
装饰器本质上就是一个python函数,他可以让其他函数在不需要做任何代码变动的前提下,
增加额外的功能,装饰器的返回值也是一个函数对象。
5.9.2、装饰器的原则
- 不修改被装饰对象的源代码
- 不修改被装饰对象的调用方式
5.9.3、装饰器的目标
在遵守装饰器原则的前提下,为被装饰对象添加上新功能
5.9.4、装饰器应用场景:插入日志,性能测试,事务处理,缓存等等
5.9.5、装饰器的形成过程
现在有一个需求,需要在不改变原函数代码的情况下去计算这个函数的执行时间
1 import time 2 def fun(): 3 time.sleep(1) 4 print("hello world") 5 def timer(f): 6 def inner(): 7 start = time.time() 8 f() 9 end = time.time() 10 print("run time is %s"%(end-start)) 11 return inner 12 fun = timer(fun) 13 fun()
执行结果:
如果有多个函数想让你测试他们的执行时间,每次是不是都得是:函数名=timer(函数名),这样还是有点麻烦,所以更简单的方法就是Python提供的语法糖
1 import time 2 def timer(f): 3 def inner(): 4 start = time.time() 5 f() 6 end = time.time() 7 print("run time is %s"%(end-start)) 8 return inner 9 @timer #语法糖 10 def fun(): 11 time.sleep(1) 12 print("hello world") 13 14 fun()
刚刚我们讨论的装饰器都是装饰不带参数的函数,现在要装饰一个带参数的函数怎么办呢?
1 import time 2 def timer(f): 3 def inner(*args,**kwargs): 4 start = time.time() 5 f(*args,**kwargs) 6 end = time.time() 7 print("run time is %s"%(end-start)) 8 return inner 9 @timer #语法糖 10 def fun(a): 11 print(a) 12 time.sleep(1) 13 print("hello world") 14 @timer 15 def fun1(a,b): 16 print(a,b) 17 18 fun(1) 19 fun1(23,21)
执行结果:
5.9.6、带参数的装饰器
假如你有500个函数使用了一个装饰器,现在你需要把这些装饰器都取消掉,你要怎么做?过两天你又需要加上...
1 import time 2 flag=False #通过flag的值来判断是否进行装饰 3 def fun(flag): 4 def demo(func): 5 def inner(*args,**kwargs): 6 if flag: 7 start=time.time() 8 func(*args,**kwargs) 9 end=time.time() 10 print("run time is %s"%(end-start)) 11 else: 12 func(*args,**kwargs) 13 return inner 14 return demo 15 @fun(flag) 16 def fun1(): 17 time.sleep(0.1) 18 print("welocme you") 19 20 fun1()
登录认证例子:
1 user = "crazyjump" 2 passwd = "123" 3 def auth(auth_type): 4 def func(f): 5 def wrapper(*args, **kwargs): 6 if auth_type == "local": 7 username = input("Username:").strip() 8 password = input("Password:").strip() 9 if user == username and passwd == password: 10 print("