《Python》反射、内置方法(__str__,__repr__)
一、反射
通过字符串的形式操作对象相关的属性。(使用字符串数据类型的变量名来获取这个变量的值)
Python中的一切事物都是对象(都可以使用反射)
反射类中的变量
反射对象中的变量
反射模板中的变量
反射本文件中的变量
用反射的场景:
input
网络
文件
#hasattr def hasattr(*args, **kwargs): # real signature unknown """ Return whether the object has an attribute with the given name. This is done by calling getattr(obj, name) and catching AttributeError. """ pass #getattr def getattr(object, name, default=None): # known special case of getattr """ getattr(object, name[, default]) -> value Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y. When a default argument is given, it is returned when the attribute doesn't exist; without it, an exception is raised in that case. """ pass #setattr def setattr(x, y, v): # real signature unknown; restored from __doc__ """ Sets the named attribute on the given object to the specified value. setattr(x, 'y', v) is equivalent to ``x.y = v'' """ pass #delattr def delattr(x, y): # real signature unknown; restored from __doc__ """ Deletes the named attribute from the given object. delattr(x, 'y') is equivalent to ``del x.y'' """ pass
1、getattr()
getattr(变量名:命名空间,字符串:属于一个命名空间内的变量名)
类名.静态属性 getattr(类名,‘静态属性’)
类名.类方法() getattr(类名,‘类方法’)()
类名.静态方法() getattr(类名,‘静态方法’)()
对象.对象属性 getattr(对象,‘对象属性’)
对象.方法() getattr(对象,‘方法’)()
模块名.方法名
模块名.类名
模块名.变量
模块名.函数
本文件反射 import sys
getattr(sys.modules[__name__],'所有定义在这个文件中的名字')
# 反射类中的变量: 静态属性、类方法、静态方法 class Foo: school = 'oldboy' country = 'china' language = 'chiness' @classmethod # 类方法 def class_method(cls): print(cls.school) @staticmethod # 静态方法 def static_method(): print('in staticmethod') def wahaha(self): # 普通方法 print('wahaha') print(Foo.school) # oldboy print(Foo.country) # china print(Foo.language) # chiness # 判断实现 inp = input('>>>') if inp == 'school': print(Foo.school) # oldboy elif inp == 'country': print(Foo.country) # china elif inp == 'language': print(Foo.language) # chiness # 反射实现 while 1: inp = input('>>>') # 输school,打印oldboy 输country,打印china 输language,打印chiness print(getattr(Foo,inp)) # 解析getattr方法 print(getattr(Foo,'school')) # oldboy Foo.class_method() # oldboy print(getattr(Foo,'class_method')) # <bound method Foo.class_method of <class '__main__.Foo'>> getattr(Foo,'class_method')() # oldboy 相当于:Foo.class_method() getattr(Foo,'static_method')() # in staticmethod 相当与:Foo.static_method()
class Foo: def __init__(self,name,age): self.name = name self.age = age def eating(self): print('%s is eating' % self.name) alex = Foo('alex',38) print(getattr(alex,'name')) # alex 反射对象属性 print(getattr(alex,'age')) # 38 getattr(alex,'eating')() # alex is eating 反射对象方法
# 反射模块中的变量 import os # os就是一个模块 os.rename('D:\\python_task1.py','D:\\python_task2.py') getattr(os,'rename') # 把python_task1.py改成了python_task2.py getattr(os,'D:\\python_task1.py','D:\\python_task2.py') # 效果同上
# 反射本文件中的变量 a = 1 b = 2 name = 'alex' def qqxing(): print('like eat qqxing') class Foo: pass import sys print(sys.modules['__main__']) # 本文件的命名空间 print(sys.modules['__main__'].a) # 1 print([__name__]) # ['__main__'] print(sys.modules[__name__]) # 反射本文件中的变量 固定的使用这个命名空间 print(getattr(sys.modules[__name__],'a')) # 1 print(getattr(sys.modules[__name__],'b')) # 2 print(getattr(sys.modules[__name__],'name')) # alex getattr(sys.modules[__name__],'qqxing')() # like eat qqxing print(getattr(sys.modules[__name__],'Foo')) # <class '__main__.Foo'> Foo类的地址 print(getattr(sys.modules[__name__],'Foo')()) # <__main__.Foo object at 0x0072BED0> Foo类对象的地址
2、hasattr()
hasattr(变量名:命名空间,字符串:属于一个命名空间内的变量名) 成立返回Ture,不成立返回False,一般与getattr搭配使用
class Foo: school = 'oldboy' country = 'china' language = 'chiness' @classmethod def class_method(cls): print(cls.school) @staticmethod def static_method(): print('in staticmethod') def wahaha(self): print('wahaha') inp = input('>>>') # 输入 haha print(getattr(Foo, inp)) # 如果输入的不存在则报错 # AttributeError: type object 'Foo' has no attribute 'haha' # 所以要给他定义一个判断条件 inp = input('>>>') if hasattr(Foo,inp): # 如果输入的字符串在这个类中,则成立 print(getattr(Foo,inp))
3、setattr()
setattr(名称空间,变量名,变量值) 更改变量的值
给命名空间的某一个名字设置一个值
# setattr:接受三个参数 命名空间 ‘变量名’ 变量值 class Foo: school = 'oldboy' def func(): print('wahaha') Foo.school = 'OLDBOY' # 直接更改 print(Foo.school) # OLDBOY setattr(Foo,'school','OLDOBY') # 有school这个属性则更改 print(Foo.school) # OLDBOY print(getattr(Foo,'school')) setattr(Foo,'name','alex') # 没有name这个属性则添加 print(Foo.name) # alex print(Foo.__dict__) setattr(Foo,'func',func) # 往类中添加方法,不过一般没人这么做 Foo.func() #wahaha func() #wahaha print(Foo.__dict__) ''' {'__module__': '__main__', 'Country': 'China', '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None, 'func': <function func at 0x00788D68>} '''
4、delattr()
delattr(命名空间,变量)
删除某一个命名空间中变量对应的值
class Foo: school = 'oldboy' country = 'china' language = 'chiness' def wahaha(self): print('wahaha') def qqxing(self): print('qqxing') del Foo.country # 直接删除一个属性 print(Foo.__dict__) delattr(Foo,'school') # 使用delattr删除一个属性 print(Foo.__dict__) del Foo.wahaha # 直接删除一个方法 print(Foo.__dict__) delattr(Foo,'qqxing') # 使用delattr删除一个方法 print(Foo.__dict__)
二、内置方法
在不是需要程序员定义,本身就存在在类中的方法就是内置方法
内置的方法通常都长这样:__名字__
各种不同叫法:名字+(双下方法、魔术方法、内置方法)
所有的双下方法,都不需要我们直接去调用,都有另外一种自动触发它的语法
__init__:
不需要我们主动调用,而是在实例化的时候内部自动调用的
__str__ 和 __repr__:
这俩方法的返回值必须是字符串,否则抛出异常。
__str__:
当你打印一个对象的时候 触发__str__
当你使用%s格式化的时候 触发__str__
str强转数据类型的时候 触发__str__
__repr__:
repr是str的备胎
有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__
repr(obj)内置函数对应的结果是 __repr__的返回值
当你使用%r格式化的时候 触发__repr__
class Course: def __init__(self,name,period,price,teacher): self.name = name self.period = period self.price = price self.teacher = teacher def __repr__(self): return 'repr : %s %s %s %s ' % (self.name,self.period,self.price,self.teacher) def __str__(self): return 'str : %s %s %s %s ' % (self.name, self.period, self.price, self.teacher) course_lst = [] python = Course('python','6 month',29800,'alex') course_lst.append(python) linux = Course('linux','5 month',19800,'oldboy') course_lst.append(linux) for id,course in enumerate(course_lst,1): print(id,course) # 1 str : python 6 month 29800 alex # 2 str : linux 5 month 19800 oldboy print('%s %s' % (id,course)) # 效果同上 print(str(course)) # str : python 6 month 29800 alex # str : linux 5 month 19800 oldboy print(repr(course)) # repr : python 6 month 29800 alex # repr : linux 5 month 19800 oldboy print('%r' % course) # 效果同上 # __str__ # 当你打印一个对象的时候 触发__str__ # 当你使用%s格式化的时候 触发__str__ # str强转数据类型的时候 触发__str__ # __repr__ # repr是str的备胎 # 有__str__的时候执行__str__,没有实现__str__的时候,执行__repr__ # repr(obj)内置函数对应的结果是 __repr__的返回值 # 当你使用%r格式化的时候 触发__repr__
#子类与父类的__str__和__repr__触发顺序: class Foo: def __str__(self): return 'Foo.str' def __repr__(self): return 'Foo.repr' class Son(Foo): def __str__(self): return 'Son.str' def __repr__(self): return 'Son.str' obj = Son() print(obj) ''' 当打印子类的对象时: 1、先从子类找__str__ 2、子类中没有__str__,则到父类找__str__ 3、子类和父类都没有__str__,则找子类的__repr__ 4、子类和父类都没有__str__,且子类没有__repr__,则找父类的__repr__ '''
__str__ 与__repr__的区别:
class Test(object): def __init__(self, value='hello, world!'): self.data = value >>> t = Test() >>> t <__main__.Test at 0x7fa91c307190> >>> print t <__main__.Test object at 0x7fa91c307190> # 看到了么?上面打印类对象并不是很友好,显示的是对象的内存地址 # 下面我们重构下该类的__repr__以及__str__,看看它们俩有啥区别 # 重构__repr__ class TestRepr(Test): def __repr__(self): return 'TestRepr(%s)' % self.data >>> tr = TestRepr() >>> tr 直接终端显示,不print就是面向程序员 TestRepr(hello, world!) >>> print tr print是面向程序员 TestRepr(hello, world!) # 重构__repr__方法后,不管直接输出对象还是通过print打印的信息都按我们__repr__方法中定义的格式进行显示了 # 重构__str__ calss TestStr(Test): def __str__(self): return '[Value: %s]' % self.data >>> ts = TestStr() >>> ts <__main__.TestStr at 0x7fa91c314e50> >>> print ts [Value: hello, world!] # 你会发现,直接输出对象ts时并没有按我们__str__方法中定义的格式进行输出,而用print输出的信息却改变了
__repr__和__str__这两个方法都是用于显示的,__str__是面向用户的,而__repr__面向程序员。
-
打印操作会首先尝试__str__和str内置函数(print运行的内部等价形式),它通常应该返回一个友好的显示。
-
__repr__用于所有其他的环境中:用于交互模式下提示回应以及repr函数,如果没有使用__str__,会使用print和str。它通常应该返回一个编码字符串,可以用来重新创建对象,或者给开发者详细的显示。
当我们想所有环境下都统一显示的话,可以重构__repr__方法;当我们想在不同环境下支持不同的显示,例如终端用户显示使用__str__,而程序员在开发期间则使用底层的__repr__来显示,实际上__str__只是覆盖了__repr__以得到更友好的用户显示