zoukankan      html  css  js  c++  java
  • day27:反射和双下方法

    1,

    # 面向对象的三大特性:继承,多态和封装
    # 继承:
        # 单继承: ****
            #  父类(超类,基类)
            #  子类(派生类)  派生方法和派生属性
            #  子类的对象在调用方法和属性:先用自己的,自己没有,采用父类的
        # 多继承:(面试)
            # 不会超过三个父类,不要超过三层 ***
            # 如果子类自己有用自己的,如果没有就用离子类最近的那个父类的
            # 抽象类和接口类 **
            # 经典类和新式类 继承规则不同,深度优先和广度优先 ***** (面试)
        # super 只有在python3中使用 mro ****
            # super 是根据mro 广度优先顺序找上一个类
    # 多态:(面试)
        # 多态和鸭子类型
    
    # 封装:***(面试)
        # 私有的
        #__名字
        # 只能在类的内部调用,子类都无法继承
    
    # 三个装饰器
        # @property **** 规范 面试 # @name.setter
        # @staticmethod ***
        # @classmethod  ***** 当一个方法使用了类的静态变量时,就给这个方法加上@classmethod装饰器,默认传cls参数
    View Code

    2,

    class Goods():
        __discount = 0.8
        @classmethod
        def change_discount(cls):
            cls.__discount = 0.5
    
    Goods.change_discount()

    3,组合:表达的是什么有什么的关系 五颗星,一个类的属性是另外一个类的对象

    4,面向对象的进阶

    # isinstance() 和 issubclass()  ***
    # 反射 ****** 非常非常的重要,高级的设置,JAVA里面也有反射,会让程序变得很简洁,任何地方都可以用,模块函数都可以
    #     setattr()
    #     delattr()
    #     getattr()
    #     hasattr()
    # __str__ 和__repr__  **  所有双下方法,知道有这么个方法就行,主要是很多人用不太好这些双下方法
    # __del__
    # item系列
    #     __getitem__
    #     __setitem__
    #     __delitem__

    5,isinstance 检查一个obj是否是一个类的对象

    class Foo():pass
    class Foo1():pass
    obj = Foo()
    print(isinstance(obj,Foo))
    print(isinstance(obj,Foo1))

    6,issubclass(sub,super) 检查sub类是否是super类的派生类

    class A():pass
    class B(A):pass
    print(issubclass(B,A))

    7,反射,非常非常重要的知识点,反射是用字符串类型的名字去操作变量,和eval有点类似

    8,反射对象的属性

    name = 1
    eval('print(name)')
    # eval会有很大的安全隐患,因为你不知道你执行的代码是什么来自哪里,除非写死了,不然有很大的安全隐患
    # 但是反射就不会有安全问题,他不是真的拿到了一段python代码,他是操作内存中已经存在的变量
    
    # 第一种:反射对象中的属性和方法
    class A:
        def func(self):
            print('in func')
    
    a = A()
    a.name = 'Alex'
    
    # 反射对象的属性
    ret = getattr(a,'name')  # 通过变量名的字符串形式取到值
    print(ret)
    print(a.__dict__)
    
    变量名 = input(">>>")
    print(getattr(a,变量名))
    print(a.__dict__[变量名]) # 相当于这样,但是我们一般不这么用

    9,反射对象的方法

    class A:
        def func(self):
            print('in func')
    
    ret = getattr(a,'func')
    ret()

    10,反射类的属性,方法和静态方法

    class A:
        price = 20
        def __init__(self,name):
            self.name = name
        def func(self):
            print('in func')
    
        @classmethod
        def func2(cls):
            print('classmethod')
    
        @staticmethod
        def func3():
            print('staticmethod')
    
    a = A('lisa')
    # 反射对象的属性
    if hasattr(a,'name'):
        ret = getattr(a,'name')
        print(ret)
    # 反射对象的方法
    if hasattr(a,'func'):
        ret = getattr(a,'func')
        ret()
    
    # 反射类的属性
    if hasattr(A,'price'):
        ret = getattr(A,'price')
        print(ret)
    
    # 反射类的方法
    if hasattr(A,'func2'):
        ret = getattr(A,'func2')
        ret()
    
    # 反射静态的方法
    if hasattr(A,'func3'):
        ret = getattr(A,'func3')
        ret()

    11,反射模块的属性和方法

    # 模块my的代码
    day = "monday"
    def func():print('func in module my.py')
    import my
    # 反射模块的属性和方法
    
    print(getattr(my,'day'))
    print(getattr(my,'func'))

    12,反射自己模块中的变量,另外自己模块的函数也是可以的

    import sys
    year = 2019
    print(sys.modules['__main__'].year)
    print(sys.modules['my'])
    
    def qqxing():print('qqxing')
    
    # 反射自己模块中的变量
    ret = getattr(sys.modules['__main__'],'qqxing') # 这样写其实是有坑的,因为如果我不是在这个模块开始运行的,他就不叫__main__了
    ret()
    print(getattr(sys.modules[__name__],变量名)) # 这样就可以了

    13,应用time模块的一个小实例,要反射的函数有参数如何处理?下面的例子给出了解答

    import time
    print(time.strftime('%Y-%m-%d %H:%M:%S'))
    print(getattr(time,'strftime')('%Y-%m-%d %H:%M:%S'))

    14,一个模块中的类能不能反射得到

    import my
    print(getattr(my,"C")) # 拿到类
    print(getattr(my,"C")()) # 实例化

    15,总结:什么.什么的形式都可以用反射来得到,目前我们没有用到太多应用他的场景,但是后面用到他的地方非常多

    16,getattr和hasattr 是一对儿,夫妻档要一起用

    17,setattr,delattr几乎不会用到的,不占用星,用的非常少

    class A:
        pass
    
    a = A()
    setattr(A,'name','nezha')
    setattr(a,'name','alex')
    
    print(A.name)
    print(a.name)
    
    delattr(a,'name') # 删掉对象的会用类的name
    
    print(A.name)
    print(a.name) 

    18,类里面内置的双下方法,__str__ 和__repr__  以前有讲过str()和repr()

    class A(object):pass
        # def __str__(self):  # 只要是str方法,一定要返回一个字符串
        #     return 'str方法'
    
    a = A()
    print(str(a))
    如果类里面的str方法没有实现,那么会去调用object类里面的str方法,返回类的字符串
    object里面有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
    运行结果:
    <__main__.A object at 0x1072d6320>
    class A(object):
        def __str__(self):  # 只要是str方法,一定要返回一个字符串
            return 'str方法'
    # 自己实现了str方法会用自己的
    a = A()
    print(str(a))  # 会自动调用类里面的双下str方法
    运行结果:
    str方法

    19,str print str %s

    class A(object):
        def __str__(self):  # 自己写会定义一个比较人性化的结果
            return "A's object"
    
    a = A()
    print(str(a))
    print(a)  # 默认打印一个对象,就是打印出这个对象的地址,调用a.__str__
    # 这个不涉及原理或者什么,只是python的一种规定
    l = [1,2,3,4,5] # 实例化了一个列表类的对象
    print(l) # 为何打印l就会显示出里面的每一个元素,这就是他做了处理
    # [1, 2, 3, 4, 5]
    class A(object):
        def __str__(self):  # 自己写会定义一个比较人性化的结果
            return "A's object"
    
    a = A()
    print('%s:%s'%(A,a)) %s实际上走的也是双下str方法
    运行结果:
    <class '__main__.A'>:A's object

    20,__repr__,调用repr和%r方法会自动调用类里面的双下repr方法

    class Teacher(object):
        def __init__(self,name,salary):
            self.name = name
            self.salary = salary
    
        def __str__(self):  # 自己写会定义一个比较人性化的结果, 如果不返回str会报错的
            return "A's object"
    
    
        def __repr__(self):
            return str(self.__dict__)
    
    lisa = Teacher('lisa',100)
    print(lisa)
    print(repr(lisa))
    
    运行结果:
    A's object
    {'name': 'lisa', 'salary': 100}

    21,总结一下

    # 自己没有定制双下repr方法,那么会调用父类的repr方法,输出对象的内存地址,
    # repr方法是str方法的备胎,自己没有定制str方法,那么会找repr方法,如果也没有repr方法,那么会调用父类的str方法。

    22,repr是 str的备胎,str不能做repr的备胎

    23,双下len方法,这些双下方法又称为魔法方法,是调用其他的自动来触发的

    class A:
        def __len__(self):
            return 100  # 返回值必须是整数,小数也不行
    
    a = A()
    print(len(a))

    23,__len__,这个方法必须实现了,才可以在下面调用,object类并没有定义所有的双下__len__方法,不一定所有的内置方法都被object收录了,比方说数字。有一些模块,比如说时间,不具备len,也没有意义,所以只能是所有的类都有的,会被object收录。定制对象的长度

    class Classes:
        def __init__(self,name):
            self.name = name
            self.student = []
    
        def __len__(self):
            return len(self.student)
    
    s9 = Classes('python')
    s9.student.append('lisa')
    s9.student.append('lucy')
    print(len(s9))  # 2

    24,__del__双下del方法,析构方法,del 既执行了方法,又删除了变量,析构函数,在删除一个对象之前,在做一些收尾工作

    class A:pass
        # def __del__(self):
        #     print('执行我啦!')
    
    a = A()
    del a   # 会自动调用双下del方法
    print(a) # 提示出错,NameError: name 'a' is not defined
    # 需要注意的是a 双下del 即使我们不定制,那么调用的时候也会自动去调用父类的双下del删除

    25,del 被删除的情况,引用计数,达到零了会被删除,这是第一种情况,第二种情况,

    26,双下__call__方法

    class A:
        def __init__(self,name,age):
            self.name = name
            self.age = age
        # def __call__(self):
        #     print('执行我啦lala')
    
        def __call__(self, *args, **kwargs):
            for k in self.__dict__:
                print(k,end=' ')
    
    a = A('lisa',22)
    a()  # TypeError: 'A' object is not callable ,不实现call方法会报出这个错误
    A('lisa',22)() # 见到这样的不要不认识,实际上就是调用双下call方法
  • 相关阅读:
    mysql数据库常用指令
    解决windows的mysql无法启动 服务没有报告任何错误的经验。
    “Can't open file for writing”或“operation not permitted”的解决办法
    启动Apache出现错误Port 80 in use by "Unable to open process" with PID 4!
    如何打开windows的服务services.msc
    常见的HTTP状态码 404 500 301 200
    linux系统常用的重启、关机指令
    (wifi)wifi移植之命令行调试driver和supplicant
    linux(debian)安装USB无线网卡(tp-link TL-WN725N rtl8188eu )
    alloc_chrdev_region申请一个动态主设备号,并申请一系列次设备号
  • 原文地址:https://www.cnblogs.com/lisa-blog/p/10274464.html
Copyright © 2011-2022 走看看