zoukankan      html  css  js  c++  java
  • 面向对象进阶、反射

      isinstance和issubclass

    • 反射
      •   setattr
      •   delattr
      •   getattr
      •   hasattr
    • __str__和__repr__
    • __del__
    • item系列
      •   __getitem__
      •   __setitem__
      •   __delitem__
    • __new__
    • __call__
    • __len__
    • __hash__
    • __eq__

    isinstance和issubclass

     isinstance(obj,cls)检查是否obj是否是类 cls 的对象

    #对象与类之间的关系

    #对象与类之间的关系
        #判断第一个参数是否是第二个参数的实例
    #身份运算
    2 == 3   # 值是否相等
    2 is 3   # 内存地址是否相等
    class A:pass#创建一个类
    class B(A):pass#B继承A类
    class C(B):pass#C继承B类
    c = C()#实例化一个C
    print(isinstance(c,A))   # True包含继承关系的判断
    print(type(c) is C)      # type只关心创建这个对象的类

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

    #类与类之间的关系
    #类与类之间的关系
    #issubclass()
    class A:pass创建一个A类
    class B(A):pass#B类继承A类
    print(issubclass(A,B))#False不是包含关系
    print(issubclass(B,A))#True是包含关系
    #第一个参数是疑似子类,第二个参数是疑似父类.
    #最终结果如果真的是父子类关系,则返回True

     反 射

    1 什么是反射

    反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。这一概念的提出很快引发了计算机科学领域关于应用反射性的研究。它首先被程序语言的设计领域所采用,并在Lisp和面向对象方面取得了成绩。

     

    2 python面向对象中的反射:通过字符串的形式操作对象相关的属性。python中的一切事物都是对象(都可以使用反射)

    四个可以实现自省的函数

    下列方法适用于类和对象(一切皆对象,类本身也是一个对象)


    hasattr、getattr、setattr、delattr
    class Foo:#定义一个类
        f = '类的静态变量'
        def __init__(self,name,age):#定义一个动态属性
            self.name=name
            self.age=age
        def say_hi(self):#定义一个say_hi方法
            print('hi,%s'%self.name)#打印hi,对象
    obj=Foo('egon',73)
    #检测是否含有某属性
    print(hasattr(obj,'name'))#检测是否含name属性True
    print(hasattr(obj,'say_hi'))#检测是否含有say_hi属性True
    
    #获取属性
    n=getattr(obj,'name')#获取对象的name属性的值
    print(n)
    # 类.静态属性   getattr(类,'静态属性')
    # 对象.方法
    #   getattr(对象,'方法')()   直接反射得到一个方法之后调用
    # 对象.对象属性
    # 应用场景 : 网络编程 从文件中读取信息反映到编程中
    func=getattr(obj,'say_hi')#获取对象的方法ip地址
    func()#执行函数
    
    print(getattr(obj,'aaaaaaaa','不存在啊')) #找不到就报错
    
    #设置属性
    setattr(obj,'sb',True)#  为一个变量增加或者修改一个属性
    setattr(obj,'show_name',lambda self:self.name+'sb')
    print(obj.__dict__)#打印obj内的字典
    print(obj.show_name(obj))#打印更改后的属性
    
    #删除属性
    delattr(obj,'age')#删除一个变量中的属性或者方法
    delattr(obj,'show_name')
    delattr(obj,'show_name111')#不存在,则报错
    
    print(obj.__dict__)#打印obj的字典
    
    # hasattr  判断某一个 变量 是否能够.调用一个名字,返回True或者False
    # getattr  直接获取一个变量中的名字的值
    # setattr  为一个变量增加或者修改一个属性
    # delattr  删除一个变量中的属性或者方法
    d = {'k':'v'}  #d.keys()
    print(getattr(d,'keys')())
    f = open() # f文件操作对象
    f.read() # 文件对象.read方法

    a.b
    模块名.函数名
    import my_moudle#引入一个模块
    print(my_moudle.money)#打印my_money类的_money属性
    print(getattr(my_moudle,'money'))#得到my_moudle的money属性
    getattr(my_moudle,'qqxing')()#得到并运行qqxing函数

    import 包名 ---> 包内的__init__文件
    反射类中的名字
    # getattr(类名,'静态属性')
    # getattr(类名,'类方法')()
    # getattr(类名,'静态方法')()
    
    反射对象中的名字
    # getattr(对象名,'对象属性')
    # getattr(对象名,'方法名')()
    
    反射模块中的名字
    # import 模块名
    # getattr(模块名,'模块中的变量')
    # getattr(模块名,'模块中的函数')()
    # getattr(模块名,'模块中的类名')
    
    反射当前模块中的名字
    # import sys
    # getattr(sys.modules[__name__],'变量')
    # getattr(sys.modules[__name__],'函数')()
    # getattr(sys.modules[__name__],'类名')
    import sys#引入sys模块
    sys.modules[__name__]
    print(sys.modules[__name__])#<module '__main__' from '/Users/guoyuanjie/Desktop/day27/day27/3.反射.py'>  # 所有导入过的模块
    # {'字符串数据类型的模块名':模块的内存地址}
    # {'__main__':当前模块的内存地址}
    类中的内置方法 __方法名__
    魔术方法 双下方法
    内置方法 : 是直接和python的语法隐形相关

    len()内置函数 __len__()
    hash()哈希函数 __hash__()
    str() __str__()

    l = [1,2,3,4]
    len(l)
    class A:#定义一个属性
        def __init__(self,name,cls,age,sex):#初始化
            self.name = name#name属性
            self.cls = cls#cls属性
            self.age = age#age属性
            self.sex = sex#sex属性
        def __eq__(self, other):
            if self.__dict__ == other.__dict__:return True
            return True
        def __len__(self):#__len__方法属性
            return len(self.__dict__)#返回一个len(对象的字典的个数)
    
    
    hei = A('小黑','py10期',18,'')#实例化小黑
    hei2 = A('小2黑','py11期',17,'')#实例化小黑二
    def len(obj):#定义一个函数,传入对象
        return obj.__len__()#返回一个对象属性
    print(len(hei))#打印hei的个数4
    print(hei.__dict__)#{'name': '小黑', 'cls': 'py10期', 'age': 18, 'sex': '无'}打印对象hei的字典方法
    print(hei2.__dict__)#{'name': '小2黑', 'cls': 'py11期', 'age': 17, 'sex': '无'}打印对象hei2的字典方法
    print(hei == hei2)  # #True 两个对象就算值是完全相等的,但是仍然内存地址不同
                        # == 时间上是比较内存地址的
    # == 实际上是调用了__eq__方法
    format_dict={
        'nat':'{obj.name}-{obj.addr}-{obj.type}',#学校名-学校地址-学校类型
        'tna':'{obj.type}:{obj.name}:{obj.addr}',#学校类型:学校名:学校地址
        'tan':'{obj.type}/{obj.addr}/{obj.name}',#学校类型/学校地址/学校名
    }
    class School:
        def __init__(self,name,addr,type):#初始化对象
            self.name=name
            self.addr=addr
            self.type=type
    
        def __format__(self, format_spec):#定义一个__format__方法
            return format_spec.format(obj=self)#返回一个
    
    s1=School('oldboy1','北京','私立')#实例化一个北京的学校
    print(format(s1,format_dict['tna']))#私立:oldboy1:北京
    print(format(s1,format_dict['nat']))# oldboy1-北京-私立
    print(format(s1,format_dict['tan']))# 私立/北京/oldboy1
    print(format(s1,'tna'))# tna
    print(format(s1,'tan'))# tan
    class School:
        def __init__(self,name,addr,type):
            self.name=name
            self.addr=addr
            self.type=type
        def __str__(self):
            return str(self.__dict__)
        def __repr__(self):  # repr是str的备胎
            return 'repr : school的repr对象'
    s1=School('oldboy1','北京','私立')
    print(str(s1))#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
    print('%s'%s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
    print(s1)#{'name': 'oldboy1', 'addr': '北京', 'type': '私立'}
    
    print(repr(s1))#repr : school的repr对象
    print('%r'%s1)#repr : school的repr对象
    
    print('%s'%s1)   # str   __str__
    # %s str 直接打印 内部都是调用了__str__

     object __eq__,__str__,__repr__

    del__

    析构方法,当对象在内存中被释放时,自动触发执行。

    注:此方法一般无须定义,因为Python是一门高级语言,程序员在使用时无需关心内存的分配和释放,因为此工作都是交给Python解释器来执行,所以,析构函数的调用是由解释器在进行垃圾回收时自动触发执行的。

    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    del f1
    print('------->')
    
    #输出结果
    执行我啦
    ------->
    # 构造方法 创建一个对象的
    # 初始化方法 __init__ 给已经创建出来的对象添加属性
    # 析构方法 删除一个对象的时候调用的方法
    import time
    class A:
        def __init__(self):
            self.f = open('userinfo','a')
        def consume(self):
            pass
        def __del__(self):
            '''在删除一个对象之前做一些收尾工作'''
            self.f.close()
            print('删除一个对象的时候调用我')
    
    a = A()
    time.sleep(1)
    del a
    # 删除一个对象的时候,如果内部存在__del__方法,
    # 那么在删除一个对象之前先执行__del__方法中的代码
    print(a)

    __new__构造方法

    # new一个对象
    # object.__new__()
    class A:
        def __init__(self):#初始化init方法
            print('执行init方法了')
        def __new__(cls):#函数中先执行new方法
            print('执行new方法了')
            return object.__new__(cls)   # 创造对象,将对象返回
    
    a = A()#
    print(type(a))
    print(type(A))
    # 先执行__new__方法 创造出一个对象
    # 然后把创造出来的对象传递给__init__方法
    # 会把self自动的返回,被a接收
    元类
    有一个元类 在创建类
    type() 所有直接用class创建出来的类的元类都是type

       class 类名(B,classMeta = 元类名)

    class 类名(B,classMeta = type)  # 默认

    元类 创造 类 所以所有的类的type都是它的元类,默认是type
    类 创造 对象 具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类

    python中 一切皆对象
    变量 都有它属于的数据类型

    设计模式
    单例模式
    一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
    class A:
        _instance = None#定义一个静态变量
        def __init__(self,name):#初始化方法
            '''给娃穿衣服'''
            self.name = name#定义一个动态属性
        def __new__(cls, *args, **kwargs):#定义一个new方法
            '''生娃的过程'''
            if not A._instance:#如果没有A._instance
                A._instance = object.__new__(cls)#类属性等于对象的属性
            return A._instance#返回一个类属性
    a1 = A('alex')  # 第一次实例化的时候创造一个实例
    print(a1.name)#alex
    a2 = A('egon')
    print(a1.name,a2.name,a1 is a2)  # egon egon True

     

    class A:
        def __init__(self,name):
            '''给娃穿衣服'''
            self.name = name
        def __new__(cls, *args, **kwargs):
            '''生娃的过程'''
            if not hasattr(A,'_instance'):#如果没有
                A._instance = object.__new__(cls)
            return A._instance
    a1 = A('alex')  # 第一次实例化的时候创造一个实例
    print(a1.name)#alex
    a2 = A('egon')
    print(a1.name,a2.name)  #egon egon

    item系列

    __getitem__\__setitem__\__delitem__

    class A:
        def __init__(self,name):#初始化方法
            self.name = name#定义一个静态属性
            self.age = 81
        def __getitem__(self, item):#查看一个对象的的方法
            return self.__dict__[item]
        def __setitem__(self, key, value):#增加和修改一个动态属性
            self.__dict__[key] = value
        def __delitem__(self, key):#删除一个动态属性
            del self.__dict__[key]
    a = A('alex')#实例化
    print(a['name'])  #alex 对应了类中一个方法的语法#a.name==a['name']
    print(a['age'])  #81 对应了类中一个方法的语法#a.age==a['age']
    # 增加 和 修改一个属性
    a['sex'] = '不详'# a.sex = '不详'#增加一个a.sex='不祥'
    print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '不详'}
    # print(a.sex)
    # print(a['sex'])
    a['sex'] = ''#修改一个对象的动态属性
    print(a.__dict__)#{'name': 'alex', 'age': 81, 'sex': '女'}
    del a['sex']#删除一个a['sex']的属性
    print(a.__dict__)#{'name': 'alex', 'age': 81}

    __call__

    对象后面加括号,触发执行。

    注:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

     

    class Foo:
    
        def __init__(self):
            pass
        
        def __call__(self, *args, **kwargs):
    
            print('__call__')
    
    
    obj = Foo() # 执行 __init__
    obj()       # 执行 __call__
    class A:
        def __call__(self,a):
            print('执行我了',a)
        def call(self,b):
            print('执行我了',b)
    a = A()
    a('aaa')   # __call__
    a.call('bbb')
    hash
    不可变的数据类型都可以被hash

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):#定义一个魔术方法
            print(hash(str(12)))#同一时间字符串12的哈希值#7130726887503445041
            return hash(str(self.a)+str(self.b))#同一时间返回一个哈希值'12'#7130726887503445041
    a = A()
    print(hash(a))#返回对象的哈希值
     
    class A:pass
        # def __hash__(self):
        #     return 1
    a = A()
    b = A()
    print(hash(a))   # object.__hash__()#同一时间同一个对象的hash值不管调用几次都相同
    print(hash(a))   # object.__hash__()
    print(hash(a))   # object.__hash__()
    print(hash(a))   # object.__hash__()
    print(hash(a))   # object.__hash__()
    print(hash(a))   # object.__hash__()
    print(hash(a))   # object.__hash__()
    print(hash(b))   # object.__hash__()
    
    # dict的key   set的元素
    # dic  key --> value
    # dic[key] = value
    
    # hash(obj)函数,obj对象对应的类必然内部实现了__hash__方法
    # hash的结果就是__hash__方法的返回值
    # 且在一次成的执行过程中是不会发生变化的
    # 且要想作为字典的key或者作为集合的元素,这个对象对应的类必须实现__hash__方法
    数据结构与算法 python   数据结构
    python核心编程第二三版 基础
    流畅的python 进阶

    扑克牌例子
    from collections import namedtuple#引用一个collections模块namedtuple可命名元祖
    Card = namedtuple('Card',['rank','suit'])#创建一个可命名元祖
    # card1 = Card(1,'红桃')
    
    class FranchDeck:#创建一个类
        ranks = [str(n) for n in range(2,11)] + list('JQKA')#设定大小静态属性
        suits = ['红心','方板','梅花','黑桃']#设置花色静态属性
    
        def __init__(self):#初始化一个元祖属性
            self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
                                            for suit in FranchDeck.suits]
    
        def __len__(self):#定义一个len方法
            return len(self._cards)# 返回对象的_cards属性的个数
    
        def __getitem__(self, item):#查询方法
            return self._cards[item]#返回一个对象属性的所有内容
    
        def __setitem__(self, key, value):
            self._cards[key] = value
    deck = FranchDeck()
    print('**',deck[:])
    from random import choice#引入选择模块
    print(choice(deck))   # deck对象对应的类中的getitem方法和len方法
    from random import shuffle#打乱顺序
    shuffle(deck)#打印顺序
    print('**',deck[:])
    # 金融公司面试题
    # 有一个类,对应这个类产生了100个对象
    # 每个对象有三个属性 : 姓名 年龄 性别
    # 请对这一百个对象进行去重,如果姓名和性别相同,即便年龄不同也是相同的对象
    # 问最简便的方法?
    class Person:#定义一个类
        def __init__(self,name,age,sex):#初始化属性
            self.name = name#对象的name属性
            self.age = age#对象的age属性
            self.sex = sex#对象的sex属性
        def __hash__(self):#定义哈希方法
            return hash('%s%s'%(self.name,self.sex))#返回hash'self.name,self.sex'的值
        def __eq__(self, other):#定义一个eq方法
            if self.name == other.name and  
                self.sex == other.sex:#如果对象属性等于
                return True
    p_lst = []#定义个空列表
    for i in range(100):#打印0到99
        p_lst.append(Person('egon',i,'male'))#p_lst列表添加Person('egon',i,'male')
    p_lst.append(Person('alex',i,'male'))#p_lst列表添加Person('alex',i,'male')
    p_lst.append(Person('yuan',i,'male'))#p_lst列表添加Person('yuan',i,'male')
    print(p_lst)
    print(set(p_lst)) # 报错不可hash 完成了__hash__
    # hash是否相等   __hash__
    # 值是否相等     __eq__
    
    # 收获1
    # 对于一些python当中已经存在的内置函数 内置数据类型 内置模块中的方法
    # 都有可能依赖于类中的内置方法
    # 收获2
    # set方法依赖集合中元素对象的__hash__ __eq__
  • 相关阅读:
    微信小程序里使用 Redux 状态管理
    ES6基础
    微信小程序入门
    Redis 安装
    ServiceStack.Redis 使用
    改善C#程序,提高程序运行效率的50种方法
    Jquery Ajax调用aspx页面方法
    WebAPI创建
    Find the Difference -- LeetCode
    Encode and Decode Strings -- LeetCode
  • 原文地址:https://www.cnblogs.com/chongdongxiaoyu/p/8549315.html
Copyright © 2011-2022 走看看