zoukankan      html  css  js  c++  java
  • 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__,没有就去父类找,
    #父类有就执行,没有就打印对象空间地址
    复制代码
  • 相关阅读:
    ZJOI2017 Day3 滚粗记
    ZJOI2017 Day2
    bzoj4245 [ONTAK2015]OR-XOR (贪心)
    bzoj4631 踩气球 (树状数组+线段树)
    bzoj5219 [Lydsy2017省队十连测]最长路径 (DP)
    bzoj5216 [Lydsy2017省队十连测]公路建设 (线段树)
    bzoj2754 [SCOI2012]喵星球上的点名 (后缀数组+树状数组)
    bzoj2342 [Shoi2011]双倍回文 (manacher)
    bzoj4657 tower (最小割)
    bzoj2064 分裂 (状压dp)
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10092234.html
Copyright © 2011-2022 走看看