• python面向对象 : 反射和内置方法


    一. 反射

    1. isinstance()和issubclass()

      isinstance( 对象名, 类名) : 判断对象所属关系,包括父类  (注:type(对象名) is 类名 : 判断对象所属关系,只包括当前的类.)

      issubclass(类名, 类名) : 判断类与类之间的继承关系

    class A:
        pass
    
    
    class B(A):
        pass
    
    
    b = B()
    print(isinstance(b, B))  # True  判断对象b是否属于B类
    print(isinstance(b, A))  # True  判断对象b是否属于A类
    print(type(b) is B)  # True   判断对象b是否属于B类
    print(type(b) is A)  # False  判断对象b是否属于A类
    
    print(issubclass(A, B))  # False  判断A是不是B的子类
    print(issubclass(B, A))  # True   判断B是不是A的子类

    2. 反射

      反射 : 用字符串数据类型的变量名来访问这个变量的值. python中的一切事物都是对象(都可以使用反射)

      反射的方法 : getattr , hasattr,  setattr,  delattr

    (1) getattr

      getattr 接收2个参数,前面的是一个对象或者模块,后面的是一个字符串.

      语法 : 命名空间.XXX == getattr(命名空间,'XXX')

    #从类的角度看:
    
    class A:
        name = 'jack'
        @classmethod
        def func(cls):
            print(666)
        @staticmethod
        def func1():
            print(777)
    
    # 反射查看静态属性
    print(A.name)  # jack
    print(getattr(A, 'name'))  # jack
    # 反射调用方法
    A.func()  # 666
    print(getattr(A, 'func'))  # <bound method A.func of <class '__main__.A'>> 内存地址
    getattr(A, 'func')()  # 666   类方法
    
    A.func1()  # 777
    print(getattr(A, 'func1'))  # <function A.func1 at 0x000002436F709620>  内存地址
    getattr(A, 'func1')()  # 777  静态方法
    # 从对象的角度来看
    
    class A:
        NAME = 'STEVE'  # 全局变量和类中的静态属性最好全大写
    
        @classmethod
        def func(cls):
            print(666)
    
        @staticmethod
        def func1():
            print(777)
    
    
    a = A()
    # 反射查看静态属性
    print(getattr(a, 'NAME'))  # STEVE
    # 反射调用方法
     # 类方法
    getattr(a, 'func')()  # 666
     # 静态方法
    getattr(a, 'func1')()  # 777
    # 从模块的的角度
    
      # 导入系统模块
    import os # 导入os模块 os模块是别人写好的python代码的结合 os.rename('12', 'hello') # 把文件为'12'的文件名改为'hello' getattr(os, 'rename')('hello', '12') # 把文件为'hello'的文件名改为'12' ==>> os.rename # 导入自己的模块 def func1(): print(666) def func2(): print(777) import sys # 是一个模块,这个模块里的所有的方法都是和python解释器相关的 print(sys.modules) # 这个方法 表示所有在当前这个python程序中导入的模块 # 可以找到本文件的模块地址(字典类型): '__main__' from 'D:/pycharm/练习/week05/new21.py'> print(sys.modules['__main__']) # <module '__main__' from 'D:/pycharm/练习/week05/new21.py'> file = sys.modules['__main__'] file.func1() # 666 file.func2() # 777 getattr(file, 'func1')() # 666 getattr(file, 'func2')() # 777

     (2) hasattr

    class A:
        name = 'tom'
        def __init__(self):
            self.age = 18
    a = A()
    
    print(hasattr(A, 'name'))  # True  判断A类是否含有name属性
    print(hasattr(a, 'age'))   # True  判断对象a是否含有age属性
    print(hasattr(a,'sex'))   # False

    (3) setattr , delattr

    class A:
        def __init__(self,name):
            self.name = name
    
    a = A('tom')
    setattr(a,'name', 'jack')  # 把对象a的属性name的值改成'jack'
    print(a.name)  # jack
    print(a.__dict__)  # {'name': 'jack'}
    
    
    delattr(a,'name')  # 删除对象a的name属性
    print(a.__dict__)  # {}

    二. 内置方法

           格式 :   __名字__              称呼 : 类中的特殊方法内置方法 双下方法 魔术方法 (magic_method)

      类中的每一个双下方法都有它自己的特殊意义 , 所有的双下方法没有需要你在外部直接调用的, 而是总有一些其他的内置函数特殊的语法来自动触发这些双下方法

    1. __call__

      功能 : 对象后面加括号,触发执行。即:对象() 或者 类()()

    class A:
        DAY = 'MONDAY'
        def __call__(self):
            print('666')
    
    a = A()
    a()  # 666   自动执行__call__方法
    A()()  # 666

    2. __len__

    class A:
        def __init__(self):
            self.lst = [1, 2, 3, 4, 5, 6, 7]
        def __len__(self):
            print(666)
            return len(self.lst)
    
    a = A()  # 实例化对象
    print(len(a))  # 7  len()自动执行__len__方法

    3. __str__

    class A:
        def __str__(self):
            return '%s %s %s %s %s' %(self.name, self.age, self.sex, self.height, self.weight)
        def __init__(self, name, age, sex, height, weight):
            self.name = name
            self.age = age
            self.sex = sex
            self.height = height
            self.weight = weight
    
    a = A('jack', 18, '', 55, 1.85)
    print(a)  # print一个对象相当于调用一个对象的__str__方法
    # jack 18 男 55 1.85
    print(str(a))  # 内置的数据类型,内置的类,相当于执行__str__
    # jack 18 男 55 1.85
    print('1号: %s' %a)  # 1号: jack 18 男 55 1.85

    4. __new__

      __new__ : 构造方法

      在实例化之后,__init__之前先执行new来创建一块空间

    class A:
        def __new__(cls, *args, **kwargs):
            obj = object.__new__(cls)  # A类没有__new__,只能去找object里找
            print('第一步')
            return obj
        def __init__(self):
            print('第二步')
    a = A()  # 先执行__new__方法,再执行__init__方法
    # 第一步
    # 第二步

      单例类

    # 单粒类 : 只能实现一个实例化对象空间的类
    class A:
        __INSTANCE = None
        def __new__(cls):
            if not cls.__INSTANCE :
                cls.__INSTANCE = object.__new__(cls)
                return cls.__INSTANCE
        def __init__(self):pass
    
    a1 = A()
    a2 = A()
    a3 = A()
    print(a1)  # <__main__.A object at 0x000002096E378B38>
    print(a2)  # None
    print(a3)  # None

     5. __repr__

    class A:
        def __init__(self, name):
            self.name = name
        def __repr__(self):
            return self.name
    a = A('jack')
    print(a)  # jack  自动执行了__repr__方法

      print()也会执行__str__方法,再把__str__加进程序看看

    class A:
        def __init__(self, name):
            self.name = name
        def __str__(self):
            return '执行str方法%s ' % self.name
        def __repr__(self):
            return '执行repr方法%s ' % self.name
    a = A('jack')
    print(a)  # 执行str方法jack
    print(str(a)+'	' + repr(a))  # 执行str方法jack     执行repr方法jack
    print('%s*****%r' % (a, a))  # 执行str方法jack *****执行repr方法jack

      __repr__ 和 __str__ 的区别与联系 :

        __str__ : str(obj),要求必须实现了__str__,要求这个方法的返回值必须是字符串str类型
        print , %s, str直接执行__str__

    __repr__: 是__str__的备胎.如果有__str__方法,那么print %s str都先去执行__str__方法,并且使用__str__的返回值. 如果没有__str__, 那么 print %s str都会执行repr
       repr(obj),%r直接执行__repr__
    # 子类没有__str__但是有__repr__,父类有__str__时
    class A:
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def __str__(self):
            return self.age
    class B(A):
        def __init__(self, name, age):
            self.name = name
            self.age = age
        def __repr__(self):
            return self.name
    
    b = B('jack','18')
    print(b)  # 18  先找本类的__str__ ,子类没有再找父类的__str__,父类没有再找子类的__repr__
      在子类中使用__str__, 先找子类的__str__, 没有的话要向上找,只要父类不是object, 就执行父类的__str__, 但是如果出了object之外的父类都没有__str__方法,就执行
    子类的__repr__方法,如果子类也没有,还要向上继续找父类中的__repr__方法. 一直找不到 再执行object类中的__str__方法.
    6. __del__ : 析构方法
    class A:
        def __init__(self, name):
            self.name = name
        def __del__(self):
            print(666)
    a = A('jack')
    print(a.name)  # jack
    del a.name  # 666  删除对象a的name属性, 自动触发__del__方法,然后进行删除操作
    # print(a.name)  # 报错,对象a已经没有name属性

    7. item系列

    类的实例属性是字典的时候,使用以下三个方法:

    __getitem__() :返回当前的实例属性的字典值
    __setitem__():属性中的key和value重新赋值
    __delitem__():删除实例属性中的某个字典key和value值
    class A:
        def __init__(self, name):
            self.name = name
        def __getitem__(self, item):
            return getattr(self, item)
        def __setitem__(self, key, value):
            setattr(self, key, value)
        def __delitem__(self, key):
            delattr(self, key)
    
    a = A('jack')
    a['k'] = 'v'  # 触发 __setitem__
    print(a['k'])  # 触发 __getitem__
    del a['k']  # 触发 __delitem__
    
    
    class A:
        def __init__(self, lst):
            self.lst = lst
        def __getitem__(self, item):
            print(self.lst[item])
        def __setitem__(self, key, value):
            self.lst[key] = value
        def __delitem__(self, key):
            self.lst.pop(key)
    a = A([0, 1, 2, 3, 4, 5])
    a[3]  # 3
    a[1] = 'j'
    print(a.lst)  # [0, 'j', 2, 3, 4, 5]
    del a[4]
    print(a.lst)  # [0, 'j', 2, 3, 5]

    8. __eq__  定义等于操作符(==)的行为。

    class A:
        def __init__(self, name):
            self.name = name
        def __eq__(self, other):
            if self.name == other.name:
                return True
            else:
                return False
    a1 = A('jack')
    a2= A('tom')
    a3 = A('jack')
    
    print(a1 == a2)  # False   == 自动触发__eq__
    print(a1 == a3)  # True

     9. __hash__

    # 对同一个值在多次执行python代码的时候hash值是不同
    # 但是对同一个值 在同一次执行python代码的时候hash值永远不变
    
    print(hash('abc'))
    print(hash('abc'))
    print(hash('abc'))
    print(hash('abc'))
    # 第一次运行
    # 6909065435967799450
    # 6909065435967799450
    # 6909065435967799450
    # 6909065435967799450
    # 第二次运行
    # 4813272381834820912
    # 4813272381834820912
    # 4813272381834820912
    # 4813272381834820912

      字典的寻址和集合的去重都是通过hash算法完成的.

      字典 : 通过哈希算法,把key值进行一次计算,算出哈希值,若是出现哈希值相同的key,则比较key值是否相同,若相同则覆盖value值,不同就二次寻址.

       集合: 通过哈希算法,把元素的值进行一次计算,若是出现哈希值相同的元素,则比较元素值是否相同,若相同后面的则覆盖前面元素的值,不同就二次寻址.

    # 一个类
    # 对象的属性 : 姓名 性别 年龄 部门
    # 员工管理系统
    # 内部转岗 python开发 - go开发
    # 姓名 性别 年龄 新的部门
    
    # 5个员工
    # 如果几个员工对象的姓名和性别相同,这是一个人
    # 请对这5个员工做去重
    class Staff:
        def __init__(self, name, sex, age, partment):
            self.name = name
            self.sex = sex
            self.age = age
            self.partment = partment
    
        def __hash__(self):
            return hash(self.name + self.sex)
                # hash('%s%s'%(self.name,self.sex))
                # hash(self.name, self.sex)  # 报错,因为给了两个值
    
        def __eq__(self, other):
            if self.name == other.name and self.sex == other.sex:
                return True
            else:
                return False
    
    
    s1 = Staff('jack', '', 18, 'sales_department')
    s2 = Staff('tom', '', 22, 'finace_departmrnt')
    s3 = Staff('vicky', '', 20, 'marketing_department')
    s4 = Staff('jack', '', 25, 'personnel_department')
    s5 = Staff('vicky', '', 22, 'production_department')
    lst = [s1, s2, s3, s4, s5]
    print(lst)
    staff_set = set(lst)  # 去重操作
    print(staff_set)
    for person in staff_set:
        print(person.__dict__)
    # {'name': 'vicky', 'sex': '女', 'age': 20, 'partment': 'marketing_department'}
    # {'name': 'tom', 'sex': '男', 'age': 22, 'partment': 'finace_departmrnt'}
    # {'name': 'jack', 'sex': '男', 'age': 18, 'partment': 'sales_department'}
     
    无限的我,现在才开始绽放,从东边的第一缕阳光到西边的尽头
  • 相关阅读:
    Go笔记-接口(interface)
    Go学习笔记-结构体中的方法
    Go学习笔记-数组和切片
    处理器的工作流程
    MySQL重温笔记-索引
    Mysql中为什么应该尽量避免使列默认值为NULL
    which、whereis、find的区别
    linux下查找大文件和大目录
    【转】Linux设置定时任务方法
    [转]python中np.multiply()、np.dot()和星号(*)三种乘法运算的区别
  • 原文地址:https://www.cnblogs.com/huangqihui/p/9393030.html
Copyright © 2020-2023  润新知