zoukankan      html  css  js  c++  java
  • 《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__以得到更友好的用户显示

  • 相关阅读:
    Modbus RTU与Modbus TCP的区别
    《对比Excel,轻松学习Python数据分析》笔记
    字符串 批量删除
    地图服务在线资源
    Java环境变量配置及maven配置
    Android学习路线
    MySQL备份脚本,应该这么写
    Windows中mysql5.6升级5.7
    SQL Server数据分析面试题(202008)
    PYTHON-未知错误
  • 原文地址:https://www.cnblogs.com/zyling/p/12774135.html
Copyright © 2011-2022 走看看