python之反射和内置函数__str__、__repr__
一、反射 反射类中的变量 反射对象中的变量 反射模块中的变量 反射本文件中的变量 1、定义:使用字符串数据类型的变量名 来获取这个变量的值 例如: name = 'xiaoming' print(name) # xiaoming print('name') # name 平时我们要想获取'xiaoming'这个值,要用name去获取,但是如果想用字符串'name' 获取这个值呢, 就需要用到反射。 2、反射应用的场景(就是把接收的字符串转换成变量的名字便于使用) 1,input 用户输入的如果是a,那么就打印1,如果输入的是b就打印2,如果输入的是name,就打印xiaoming 2,文件 从文件中读出的字符串,想转换成变量的名字 3,网络 将网络传输的字符串转换成变量的名字
3、反射类中的变量 : 静态属性,类方法,静态方法 class Foo: School = 'Zhbit' Country = 'China' language = 'Chiness' @classmethod def class_method(cls): print('in class_method') @staticmethod def static_method(): print('in staticmethod') def hahaha(self): print('hahaha') # 如果要实现输入School就打印对应的值,Country也打印对应的值,那么: # 1,用判断实现: inp = input('请输入:') if inp == 'School':print(Foo.School) elif inp == 'Country':print(Foo.Country) elif inp == 'language':print(Foo.language) # 在属性少的时候这样写,没什么问题,但是想一想,如果有100个属性呢,你要写100次判断吗? 所以,请看反射。 # 2,反射实现 while True: inp = input('>>>') print(getattr(Foo,inp)) # OK,这就实现了,而且无论多少个属性,都可以实现,很简单吧! # 那么下面就来解析反射需要用到的方法 2-1getattr方法 用法:getattr(变量名(命名空间),字符串(属于一个命名空间内的变量名)) # 获取静态属性 print(getattr(Foo,'School')) # 就等于 Foo.School print(getattr(Foo,'class_method')) # 就等于 Foo.class_method 得到的是一个函数地址 print(getattr(Foo,'static_method')) #就等于 Foo.static_method 得到的是一个函数地址 # 若想执行这个函数 getattr(Foo,'class_method')() # in class_method getattr(Foo,'static_method')() # in staticmethod 2-2hasattr方法 # 要是没有这个属性或者方法就会报错,那么出于安全考虑,就需要判断有没有这个属性或者方法才去执行 # 就要用到hasattr() print(hasattr(Foo,'class_method')) #True print(hasattr(Foo,'hello')) # False while True: inp = input('请输入:') if hasattr(Foo,inp): print(getattr(Foo,inp)) 4、反射对象属性,普通方法 class Foo: def __init__(self,name,age): self.name = name self.age = age def sleep(self): print('%s在睡觉,快打死他' %self.name) xiaobai = Foo('小白',12) print(getattr(xiaobai,'name')) getattr(xiaobai,'sleep')() 5、反射模块中的变量 import os # os就是一个模块 os.rename('a.txt','a.bak') getattr(os,'rename')('a.bak','a.txt') 6、反射本文件中的变量 a = 1 b = 2 age = 18 # 函数 def func(): print(666) # 类 class A:pass import sys print(sys.modules['__main__']) # 本文件的命名空间 print(sys.modules['__main__'].a) # 本文件的命名空间中的a变量的值:1 print(sys.modules['__main__'].func) # 本文件的命名空间中函数func的地址:<function func at 0x000001C735B81E18> print(sys.modules['__main__'].A) # 本文件的命名空间中类A的地址:<class '__main__.A'> # __name__ 与 '__main__' 一样,代表本文件的命名空间 print(sys.modules['__main__']) print(sys.modules[__name__]) # 反射 print(getattr(sys.modules[__name__],'a')) # 1 print(getattr(sys.modules['__main__'],'a')) # 1 print(getattr(sys.modules[__name__],'age')) # 18 getattr(sys.modules[__name__],'func')() #执行函数func:666 obj = getattr(sys.modules[__name__],'A')() #实例化对象 print(obj) 7、setattr:增和改 # 类 class Foo: country = 'China' # 函数 def func(): print(666) print(getattr(Foo,'country')) # China setattr(Foo,'country','Big China') # 接受三个参数:命名空间 '变量名' 变量值 print(getattr(Foo,'country')) # Big China setattr(Foo,'fun',func) # 为类Foo新增一个属性fun,值为func函数的地址 print(func) # <function func at 0x00000188B34F2D08> print(Foo.fun) # <function func at 0x0000026DC4A21E18> getattr(Foo,'fun')() # 666 8、delattr:删 class Foo: language = '火星文' country = 'China' def func(): print(666) print(Foo.__dict__) delattr(Foo,'language') print(Foo.__dict__) 二、内置方法__str__和__repr__ 1、内置方法的定义 不需要程序员定义,本身就存在类中的方法就是内置方法, 它不用我们直接调用,当遇到特定的场景就会自动触发, 内置的方法通常都长这样 : __名字__ 可以叫 : 双下方法、 魔术方法、 内置方法 比如我们熟悉的初始化函数__init__()就是内置方法, 实例化对象的时候就自动执行 2、__str__和__repr__ __str__ 当你打印一个对象的时候print(obj) 触发__str__ 当你使用%s格式化的输出对象时候print('%s' %obj) 触发__str__ str强转数据类型的时候str(obj) 触发__str__ __repr__ repr是str的备胎 直接打印对象,有__str__的时候执行__str__,没有__str__的时候,执行__repr__ 当你使用%r输出对象时候print('%r' %obj) 触发__repr__ repr强转数据类型的时候repr(obj) 触发__repr__ 注意:__str__ 和__perp__都必须要用return,而且返回值必须是字符串 例子: class Fruit: def __init__(self,name,price): self.name = name self.price = price def __str__(self): return 'in str:%s的价格是:%s' %(self.name,self.price) def __repr__(self): return 'in repr:%s的价格是:%s' % (self.name, self.price) apple = Fruit('苹果',5) # 直接打印对象,有__str__的时候执行__str__,没有__str__的时候,执行__repr__ print(apple) # in str:苹果的价格是:5 # 当你使用%s格式化的输出对象时候print('%s' %obj) 触发__str__ print('%s' %apple) # in str:苹果的价格是:5 # 当你使用%r输出对象时候print('%r' %obj) 触发__repr__ print('%r' %apple) # in repr:苹果的价格是:5 # str强转数据类型的时候str(obj) 触发__str__ print(str(apple)) # in str:苹果的价格是:5 # repr强转数据类型的时候repr(obj) 触发__repr__ print(repr(apple)) # in repr:苹果的价格是:5 升级: class Fruit: def __str__(self): return 'Fruit_str' def __repr__(self): return 'Fruit_repr' class Apple(Fruit): def __str__(self): return 'Apple_str' def __repr__(self): return 'Apple_repr' apple = Apple() print(apple) # apple是Apple类对象,直接打印,先从Apple类找,有__str__的时候执行Apple的__str__,没有__str__的时候, # 从父类去找__str__,父类有就执行,如果父类没有,就找子类的__repr__,有就执行子类的__repr__,没有就去父类找, #父类有就执行,没有就打印对象空间地址