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方法
  • 相关阅读:
    HDU 6106 Classes【水题】
    HDU 6106 Classes【水题】
    ACM常用解题技巧方法
    ACM常用解题技巧方法
    程序员语录
    数据库设计的三大范式
    IDEA中Java代码存入DB中为乱码
    IDEA中如何添加jar包
    Java的Protected
    Hibernate JPA 如何使用SQL文直接查询
  • 原文地址:https://www.cnblogs.com/lisa-blog/p/10274464.html
Copyright © 2011-2022 走看看