Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究...

mac2022-06-30  63

Python进阶----反射(四个方法),函数vs方法(模块types 与 instance()方法校验 ),双下方法的研究

一丶反射

什么是反射:

​ 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(反射)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

Python面向对象的反射:

​ 通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)如: 一个py文件, 一个类,一个实例对象,等等都是对象.

#### 四个实现反射的函数 # hasattr(), getattr(), setattr(), delattr() #### 反射 整合版 class Foo: public_attr='静态属性' def __init__(self,name,age): self.name=name self.age=age def func(self): print('Hello Python') obj=Foo('张三',18) # 实例化对象 ## 检测是否含有XX属性 print(hasattr(obj,'public_attr')) #当前实例对象,是否含有静态变量public_attr print(hasattr(obj,'func')) #当前实例对象,是否含有func方法 ## 获取属性 getattr(对象,字符串,None) print(getattr(obj,'public_attr'),None) #静态属性,不存在就返回None print(getattr(obj,'func')) # <bound method Foo.func of <__main__.Foo object at 0x0000015FF30EC8D0>> ## 设置属性 setattr(对象,字符串,值) setattr(obj,'sex','男') # 设置对象属性 print(obj.__dict__) # {'name': '张三', 'age': 18, 'sex': '男'} ## 设置匿名方法 self为参数 setattr(obj,'show_name',lambda self:self.name) print(obj.show_name(obj)) # 设置方法, print(obj.__dict__)# { 'show_name': <function <lambda> at 0x0000018512932EA0>} ## 删除属性 delattr(obj,'name') delattr(obj,'name') # 不存在就报错 print(obj.__dict__) # {'age': 18, 'sex': '男', 'show_name': <function <lambda> at 0x000001D901BE2EA0>} ### 从当前 脚本(本类) 研究反射 class B: sta_='abc' def func1(): print('in func1') import sys this_module=sys.modules[__name__] # 获取py文件对象 print(this_module) # 这是一个对象 <module '__main__' from 'E:/File/oldboy学习笔记/Python之路/day26/01 反射.py'> print(hasattr(this_module,'func1')) # 判断函数名属性 存在不存在, True print(getattr(this_module,'func1')) # 获得函数名属性 <function func1 at 0x00000225EBA92EA0> getattr(this_module,'func1')() #获得函数名属性+()执行func1函数 print(hasattr(this_module,'B')) # 判断类名属性 存在不存在 True print(getattr(this_module,'B')) # 获得类名属性打印 <class '__main__.B'> cls=getattr(this_module,'B') # cls 得到是一个B类的地址 print(cls) # <class '__main__.B'> obj=cls() # cls+() 实例化一个对象 print(obj.sta_) # obj对象.B对象中的静态属性

​ 案例:

class Auth: funcli=[('login','请登录'),('register','请注册'),('exit','退出')] def login(self): print('登录函数') def register(self): print('注册函数') def exit(self): print('退出...') while 1: obj=Auth() for num , option in enumerate(obj.funcli,1): print(num,option[0],option[1]) func_name = input('请输入选择:').strip() if hasattr(obj,obj.funcli[int(func_name)-1][0]): getattr(obj,obj.funcli[int(func_name)-1][0],'不存在')()

二丶函数vs方法

函数和方法有什么区别和相同之处?

​ 函数是显性传参, 方法是隐性传参

#### 通过打印函数名确定 def func(): pass print(func) # 函数 <function func at 0x00000260A2E690D0> class A: def func(self): pass print(A.func) # 函数 <function A.func at 0x0000026E65AE9C80> obj = A() print(obj.func) # 方法 <bound method A.func of <__main__.A object at 0x00000230BAD4C9E8>> #### 通过types模块验证 from types import FunctionType # 函数 from types import MethodType # 方法 def func(): pass class A: def func(self): pass obj = A() ## isinstance(obj,M) 判断 obj对象 ,是不是由M类 或 M类的派生类 实例化的对象 print(isinstance(func,FunctionType)) # True 函数 print(isinstance(A.func,FunctionType)) # True 类调用类中的func 是函数 print(isinstance(obj.func,FunctionType)) # False 实例对象调用 不是函数 print(isinstance(obj.func,MethodType)) # True 实例对象调用 是方法

研究类中的三个特殊的方法(静态方法,类方法,属性)

#### 类中的静态方法是函数(静态函数) from types import FunctionType from types import MethodType class A: def func(self): pass @classmethod def func1(self): pass @staticmethod def func2(self): pass obj = A() # 静态方法其实是函数 print(isinstance(A.func2,FunctionType)) # True print(isinstance(obj.func2,FunctionType)) # True #### 类中的类方法是方法(类方法) from types import FunctionType from types import MethodType class A: @classmethod def paas(cls): pass @property def a(self): pass obj=A() # 类方法 类和对象 调用 都是方法 print(isinstance(obj.paas,FunctionType)) # False print(isinstance(obj.paas,MethodType)) # True print(isinstance(A.paas,FunctionType)) # False print(isinstance(A.paas,MethodType)) # True #### 类中的属性伪装函数 . 什么也不是,单纯的伪装属性 from types import FunctionType from types import MethodType class A: @classmethod def paas(cls): # 类方法是 cls, 实例对象或类调用.默认将从属的类地址传给cls (隐性传参) pass @property def a(self): pass obj=A() # 实例化对象 # 属性 , 类和对象 调用 什么都不是 print(isinstance(obj.a,FunctionType)) # False print(isinstance(obj.a,MethodType)) # False print(isinstance(A.a,FunctionType)) # False print(isinstance(A.a,MethodType)) # False ## 总结: #1.类名 或 实例对象 调用类方法 都是 方法 method #2.类名 或 实例对象 调用静态方法 都是 函数 function #3.类名 或 实例对象 调用伪装属性函数. 什么都不是,单纯属性 ## 函数 和方法的本质区别: ## 函数是显性传参, 方法是隐性传参

三丶特殊的双下方法

定义:

​ ' __ 方法名 __ ' 的具有特殊意义的方法,不同的双下方法有不同的触发方式,开发中尽量不要使用双下方法

' __ len __ ' 一个对象可以使用len()函数 ,根本原因是这个对象从属的类有__len__方法

class A: def __init__(self,name,sex,age): self.name=name self.sex=sex self.age=age def __len__(self): # 必须有返回值 , 如果没有会报错(TypeError: 'NoneType' object cannot be interpreted as an integer) print('触发了__len__') return len(self.__dict__) # 返回当前实例对象具有几个属性 obj=A('张三','男',10) print(len(obj)) # 从属的类中没有__len__方法就报错 TypeError: object of type 'A' has no len()

' __ hash __ '对象使用hash()函数,调用当前本类__hash__方法 ,本类没有就从父类找__hash__

class A: def __init__(self): self.a=1 self.b=2 # 重写父类的__hash__方法 def __hash__(self): #需要返回值 , 没有返回值 报错:TypeError: __hash__ method should return an integer return hash(str(self.a)+str(self.b)) a=A() print(hash(a)) # 主动触发 __hash__方法, 当前类如果没有__hash__ 就从父类找

' __ str __ ' 和' __ repr __ '

### 这俩方法的返回值必须是字符串,否则抛出异常 ### str函数或者print函数--->obj.__str__() ### repr或者交互式解释器--->obj.__repr__() ### 如果__str__没有被定义,那么就会使用__repr__来代替输出 format_dict={ 'nat':'{obj.name}-{obj.age}-{obj.sex}',#学校名-学校地址-学校类型 'tna':'{obj.sex}:{obj.name}:{obj.age}',#学校类型:学校名:学校地址 'tan':'{obj.sex}/{obj.age}/{obj.name}',#学校类型/学校地址/学校名 } class School: def __init__(self,name,sex,age): self.name=name self.age=age self.sex=sex def __repr__(self): return f'__repr__ {self.name} {self.age}' def __str__(self): return f'__str__ {self.name}{self.age}' def __format__(self, format_spec): if not format_spec or format_spec not in format_dict: format_spec = 'nat' fmt = format_dict[format_spec] return fmt.format(obj=self) s1=School('ABC','男','123') print(repr(s1)) # 现在本类本类找__repr__ 如果没有 . 直接去父类找,返回一个对象地址 print(str(s1)) # 会触发__str__ , 先在本类找__str__ 如果没有 ,找__repr__ .如果还没有去object类找,返回的是一个对象地址 print('%s'%obj) # %s 调用__str__ print('%r'%obj) # %r 调用 __repr__ print(s1) ### __str__的优先级高于__repr__ ### 现在一般不再使用format()函数 print(format(s1,'nat')) # ABC-123-男 print(format(s1,'tna')) # 男:ABC:123 print(format(s1,'tan')) # 男/123/ABC print(format(s1,'asfdasdffd')) # ABC-123-男

' __ call __ '

class A: def __init__(self): self.a=1 print(111) def __call__(self, *args, **kwargs): # 不需要返回值,如果当前不存__call__在报错: TypeError: 'A' object is not callable print(666) obj1=A() obj1() # 实例对象+() 调用__call__方法

' __ eq __'

class A: def __init__(self): self.a=1 self.b=2 def __eq__(self, other): # 没有return 默认返回None if self.a==other.a and self.b==other.b: # 条件不成立时,也返回None return True a=A() b=A() print(a==b) # 调用__eq__方法 ### 面试题: ### set方法依赖集合中元素对象的__hash__ __eq__ class Person: def __init__(self,name,age,sex): self.name = name self.age = age self.sex = sex def __hash__(self): # TypeError: unhashable type: 'Person' # print('调用了1') return hash(self.name+self.sex) def __eq__(self, other): # 判断当前对象是否 和其他对象的某些属性相同 other 接收set集合每次迭代的对象 # print('调用了') # 解读 : 第一次实例化对象,self.name是列表中第一个对象执行__init__封装了 if self.name == other.name and self.sex == other.sex:return True p_lst = [] for i in range(84): p_lst.append(Person('egon',i,'male')) # 存放实例化对象 print(p_lst) print(set(p_lst)) # 必须调用 __hash__ , 如果有__eq__ 就调用 , 没有就不调用. 迭代去重. so 第一次的时候 name 的值为列表第一个元素执行__init__封装的属性 # print(dir(set))

' __ del __ '析构方法,当对象在内存中被释放时,自动触发执行。

​ 此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

class Foo: def __del__(self): print('执行我啦') f1=Foo() del f1 print('------->')

' __ new __ '

class A: def __init__(self,name): self.name=name print('in the __init__') def __new__(cls, *args, **kwargs): # cls 自动接收 类名地址 print('in the __new__') result=object.__new__(A)#由于重写了父类的__new__,需要调用父类的__new__方法才能创造对象空间 print(result) # 生成对象空间的内存地址 return result # 必须返回这个对象空间地址返回 ,才能执行__init__为对象封装属性 #### 类名() 先触发__new__ 并且将类名自动传递给cls obj=A('ale') # 先执行__new__方法,如果没有执行父类的__new__. # 只有返回对象空间,才继续执行__init__方法,如果没有返回对象空间,对象为None print(obj.name) print(obj) # __new__ 没有返回对象内存空间 对象=None

单例模式 : 节省内存

class F: __instance=None def __init__(self): print('执行了init方法') def __new__(cls, *args, **kwargs): if not cls.__instance: object1=object.__new__(cls) cls.__instance=object1 return cls.__instance obj=F() obj1=F() obj2=F() print(obj,obj1,obj2) # 三个内存地址都一样

' __ item __ ' 对对象进行类似于字典的操作

### 类似于 @property class Foo: def __init__(self, name): self.name = name def __getitem__(self, item): # print('调用时执行 get') print(self.__dict__[item]) def __setitem__(self, key, value): print('设置时调用 set') self.__dict__[key] = value def __delitem__(self, key): print('del obj[key]时,我执行') self.__dict__.pop(key) def __delattr__(self, item): print('del obj.key时,我执行') self.__dict__.pop(item) f1 = Foo('sb') f1['name'] # 调用时执行 __getitem__ f1['age'] = 18 #设置新属性 __setitem__ f1['age1'] = 19 # 设置新属性 __setitem__ del f1.age1 # 删除属性 __delitem__ del f1['age'] #删除属性 __delattr__ f1['name'] = 'alex' # 修改属性 __setitem__ print(f1.__dict__)

' __ enter __ __ exit __

## __enter__ __exit__ # 如果想要对一个类的对象进行with as 的操作 ## 案例一: with语句 class A: def __enter__(self): # 开启上下文管理器对象时触发此方法 print('before') def __exit__(self, exc_type, exc_val, exc_tb): # 执行完上下文管理器对象f1时触发此方法 print('after') with A() as a: print('123') # before # 123 # after ## 案例二: with语句和init class A: def __init__(self): print('init') def __enter__(self): print('before') def __exit__(self, exc_type, exc_val, exc_tb): print('after') with A() as a: print('123') # init 先执行 ### 案例三:with和文件操作 class Myfile: def __init__(self,path,mode='r',encoding = 'utf-8'): self.path = path self.mode = mode self.encoding = encoding def __enter__(self): print('进来了') self.f = open(self.path, mode=self.mode, encoding=self.encoding) return self.f def __exit__(self, exc_type, exc_val, exc_tb): print('关闭了') self.f.close() with Myfile('file',mode='a') as f: f.write('wahaha') print('写完; ') ### 案例四: with和pickle import pickle class MyPickledump: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='ab') return self def dump(self,content): pickle.dump(content,self.f) def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() class Mypickleload: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='rb') return self def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() def load(self): return pickle.load(self.f) def loaditer(self): while True: try: yield self.load() except EOFError: break # with MyPickledump('file') as f: # f.dump({1,2,3,4}) with Mypickleload('file') as f: for item in f.loaditer(): print(item) ### 案例五: with和pickle和iter import pickle class MyPickledump: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='ab') return self def dump(self,content): pickle.dump(content,self.f) def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() class Mypickleload: def __init__(self,path): self.path = path def __enter__(self): self.f = open(self.path, mode='rb') return self def __exit__(self, exc_type, exc_val, exc_tb): self.f.close() def __iter__(self): while True: try: yield pickle.load(self.f) except EOFError: break # with MyPickledump('file') as f: # f.dump({1,2,3,4}) with Mypickleload('file') as f: for item in f: print(item)

转载于:https://www.cnblogs.com/dengl/p/11178826.html

最新回复(0)