组合 反射 魔术方法的使用
1. 组合
组合:把另外一个类的对象属性赋值给当前对象的属性 首先要明白 什么是什么的区别 为什么要继承父类 比如三个类 老师类 学生类 课程类; 虽然老师和学生有课程 但是老师和学生是课程吗? 还是老师和同学是课程 """ is a 的关系 代表的是 继承的关系 和什么有什么的关系 就是组合 """ 所以不想继承 又想用到其他类中的属性 就需要 创建超级对象 来 获取其他类中的属性和方法 class Student: pass class Teacher: pass class cuosce: pass 案例如下: """ 1. 老师类 : 初始化属性有 name,gender,age ,evol.salary 2. 学生类 : 初始化属性有 name , gender age uid class_name 3. 课程类: name gender age course price day 4. 把类中冗余的代码写一个类 来继承 """ class Tar_Stu: def __init__(self,name,age,gender): self.name = name self.age = age self.gender = gender class Teacher(Tar_Stu): def __init__(self,name,age,gender,evol,salary,course): super().__init__(name,age,gender) self.evol = evol self.salary = salary self.course = course def ter_course(self): print('%s 老师有 %s 课 ' % (self.name,self.course)) class Student(Tar_Stu): def __init__(self, name, age, gender,uid,class_name,course): super().__init__(name, age, gender) self.uid = uid self.class_name = class_name self.course = course def stu_course(self): print('%s 同学有 %s 课 ' % (self.name,self.course)) class Course: def __init__(self,course,price,day): self.course = course self.price = price self.day = day def course_time(self): print('%s 课程 %s 钱 %s 天' % (self.course,self.price,self.day)) terchar = Teacher('huang',28,'male','10级',15000,'python') # 老师对象 stu = Student('lu',88,'male',88,'九五班','python') # 学生对象 python = Course('python',22000,'180') # 课程对象 linux = Course('linux',25000,200) # 课程对象 terchar.tar_course = python # python 对象会赋值给 tar_course terchar.tar_course.course_time() # 调用的时候 调用的对象.被赋值的名字.方法即可 完成了不用继承也可以用其他类 stu.stu_course = linux stu.stu_course.course_time() stu.stu_course = [python,linux] # 可以用列表来装多个 赋值对象 for i in stu.stu_course: # 调用的时候 for 循环即可 i.course_time()
2. 反射
"""反射:就是通过字符串的形式来操作对象的属性""" 四个内置函数: getattr: 获取属性 ##### 用的最多 setattr:设置属性 hasattr:判断是否有某个属性 delattr:删除 class Student(): school = 'SH' def __init__(self,name, age): self.name=name self.age = age def func(self): print('from func') def index(self): print('from index') stu = Student('kevin', 20) # 1. 获取属性 """当你查询的属性不存在的时候,如果给了第三个参数,就返回第三个参数""" """如果你给了第三个参数,查询的属性也存在,那就直接返回属性对应的值,默认值就没用了""" # res=getattr(stu, 'school1', 666) # SH 666 res=getattr(stu, 'func1', stu.index) # 获取类中的方法 第一个参数是 对象 第二的参数是 类中的方法 没有找到的情况下 就返回第三个默认值 print(res()) ## 设置 setattr(stu, 'x', 666) # 类中有这个属性就修改 没有就增加 print(stu.__dict__) ### hasattr 判断有没有这个属性 返回布尔值 print(hasattr(stu, 'func')) if hasattr(stu, 'func'): getattr(stu, 'func')() else: ... ## delattr 删除属性 没有就报错 有就删除 delattr(stu, 'name1') del stu.name print(stu.__dict__)
3. 魔术方法
它的特点就是双下划线开头的方法,它满足一定的条件就会自动触发,简称魔法 1. __str__ 和 __repr__ 方法 class Student(): def __init__(self,name,age): self.name = name self.age = age def __str__(self): print('%s 姓名 %s 年龄' % (self.name,self.age)) return '11' def __repr__(self): print(self.name,self.age) return '22' """ __str__ 和 __repr__ 这两个都是在打印对象或者输出对象的时候触发 但是 都必须返回字符串类型 否则报错 而且__str__优先级更高 """ obj = Student('huang',18) print(obj) print(str(obj)) print(repr(obj)) 2. __del__ 方法: class Student(): def __init__(self,name,age): self.name = name self.age = age self.f = open('a.txt', 'w') def __del__(self): print('form del') self.f.close() stu = Student('huang',18) del stu print(123) """ 1.当你删除对象的时候会触发__del__的执行 2. 当整个脚本的程序都执行完毕的时候,也会触发__del__的执行 3. 一般用在用来在对象被删除时自动触发回收系统资源的操作 """ 3. with 上下文管理器执行原理 和魔术方法 __enter__ 和 __exit__ class Open: def __init__(self, name): self.name = name def __enter__(self): print('出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量') # return self def __exit__(self, exc_type, exc_val, exc_tb): print('with中代码块执行完毕时执行我啊') print(exc_type) # 异常类型 print(exc_val) # 异常值 print(exc_tb) # 追溯信息 return True # 如果你在这个方法里面返回了True,with代码块中出现了异常,就相当于没有出现异常 """with它可以用在很多地方,但是,出现with语句后面的对象中得类必须要声明__enter__和__exit__""" with Open('a.txt') as f: print('=====>执行代码块') print('=====>执行代码块') # # print(f,f.name) """如果with代码块中出现了异常,则with语句之后的代码都不能正常执行""" with Open('a.txt') as f: print('=====>执行代码块') raise AttributeError('***着火啦,救火啊***') # 抛出异常,主动报错 print('0' * 100) # ------------------------------->不会执行 """ 1. with的执行顺序 第一步 有个类名字叫 Open 里面有三个方法 一个是__init__,传一个文件名字的 第二个是 __enter__ 方法,这个是出现with语句,对象的__enter__被触发,有返回值则赋值给as声明的变量 第三个 执行with代码块的时候 执行__exit__ 方法 如果with代码块中出现了异常,则with语句之后的代码都不能正常执行 raise AttributeError('***着火啦,救火啊***') # 抛出异常,主动报错 后面的代码不会执行了 __exit__ 里面有三个参数 异常类型 异常值 追溯信息 """ 4. __dco__ class Foo: """ '我是描述信息asdasd' '我是描述信息asdasd' '我是描述信息asdasd' """ pass print(Bar.__doc__) # 打印类中的描述信息 但只能是当前类 5. isinstance 判断类型 返回布尔值 issubclass print(isinstance(123, str)) print(issubclass(Bar, Foo)) # 第一个参数是子类 第二个是父类 判断是否是继承类 返回布尔值
4. __setattr__,__delattr__,__getattr__
class Foo: x=1 def __init__(self,y): self.y=y """当你找的属性不存在的时候,会触发__getattr__,但是必须是点语法的时候才会 __dict__ 不会""" def __getattr__(self, item): print('----> from getattr:你找的属性不存在') def __setattr__(self, key, value): print('----> from setattr') # self.key=value # self.a=20 # self.key=value #这就无限递归了,你好好想想 self.__dict__[key] = value #应该使用它 def __delattr__(self, item): print('----> from delattr') # del self.item #无限递归了 self.__dict__.pop(item) obj=Foo(10) obj.z # 找不到属性的情况下 先执行 __setattr__ 查找,找不到就执行__getattr__ obj.a = 'a' # 如果是进行赋值操作 第一次执行 __setattr__ 查找字典 没有找到 就添加进去字典 在执行一次 # print(obj.a) del obj.a # 删除的时候触发 __delattr__ """ ----> from setattr ----> from getattr:你找的属性不存在 ----> from setattr ----> from delattr """
5. __setitem__,__getitem,__delitem__
class Foo: def __init__(self, name): self.name = name """当你通过中括号获取对象的属性的时候,会自动触发__getitem__""" def __getitem__(self, item): print('__getitem__') print(self.__dict__[item]) def __setitem__(self, key, value): # key:age # value:18 print('__setitem__') self.__dict__[key] = value # self.__dict__['age'] = 18 def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) pass # def __delattr__(self, item): # print('del obj.key时,我执行') # self.__dict__.pop(item) obj=Foo('tom') print(obj.name) # 直接获取的是 属性 obj['name'] # """当你通过中括号获取对象的属性的时候,会自动触发__getitem__""" obj['age'] = 18 # 通过字典设置值 或者修改值 的时候触发 __setitme__ obj['age'] = 19 # print(obj.age) # # del obj['age'] # 通过字典删除值的时候触发
6. __call__方法
class Foo: def __init__(self): pass #### 当对象加括号的时候会触发__call__的执行 def __call__(self, *args, **kwargs): print('__call__') obj=Foo() print(obj) obj() # #### 当对象加括号的时候会触发__call__的执行