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

    1、isinstance和issubclass
    1)、isinstance(obj,cls)检查是否obj是否是类 cls 的对象
    print(obj.__dict__) #由于报错无法执行
    
    class Foo(object):
         pass
      
    obj = Foo()
      
    print(isinstance(obj, Foo)) #True

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

    class Foo(object):
        pass
     
    class Bar(Foo):
        pass
     
    print(issubclass(Bar, Foo)) #True

     一、反射

    1、什么是反射

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

    2、面向对象中的反射的定义

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

     3、实现反射的4个内置函数

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

    #内置函数:hasattr/getattr/setattr/delattr
    
    class Foo:
        f = '类的静态变量'
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def say_hi(self):
            print('hi,%s'%self.name)
    
    obj=Foo('egon',73)
    
    #1、hasattr 检测是否含有某属性
    print(hasattr(obj,'name'))      #True
    print(hasattr(obj,'say_hi'))    #True
    
    #2、getattr 获取属性
    n=getattr(obj,'name')
    print(n)                        #egon
    func=getattr(obj,'say_hi')
    func()                          #hi,egon
    
    print(getattr(obj,'aaaaaaaa','不存在啊')) #不存在啊
    
    #3、setattr 设置属性
    setattr(obj,'sb',True)
    setattr(obj,'show_name',lambda self:self.name+'sb')
    print(obj.__dict__)             
    #{'name': 'egon', 'age': 73, 'sb': True, 'show_name': <function <lambda> at 0x0000026061C8AAE8>}
    print(obj.show_name(obj))
    #egonsb
    
    #4、delattr 删除属性
    delattr(obj,'age')
    delattr(obj,'show_name')
    delattr(obj,'show_name111')#不存在,则报错
    #报错信息:delattr(obj,'show_name111')#不存在,则报错
    4个方法的使用示例
    class Foo(object):
         
        staticField = "old boy"
     
        def __init__(self):
            self.name = 'wupeiqi'
     
        def func(self):
            return 'func'
        
        @staticmethod
        def bar():
            return 'bar'
     
    print(getattr(Foo, 'staticField'))  #old boy
    print(getattr(Foo, 'func'))     #<function Foo.func at 0x00000250E23EAC80>
    print(getattr(Foo, 'bar'))      #<function Foo.bar at 0x00000250E23EAD08>
    类也是对象
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import sys
    
    def s1():
        print('s1')
    
    def s2():
        print('s2')
    
    #获取当前模块的名字
    this_module = sys.modules[__name__]
    
    print(hasattr(this_module, 's1'))   #True
    print(getattr(this_module, 's2'))   #<function s2 at 0x0000023BABB4AB70>
    反射当前模块成员

     导入其他模块,利用反射查找该模块是否存在某个方法

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    def test():
        print('from the test')
    module_test.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
     
    """
    程序目录:
        module_test.py
        index.py
     
    当前文件:
        index.py
    """
    
    import module_test as obj
    
    #obj.test()
    
    # 判断test是否属于obj的属性或方法
    print(hasattr(obj,'test'))  #True
    getattr(obj,'test')()       #直接执行test()方法
    #结果:from the test
    index.py

     反射总结

    # hasattr  判断某一个 变量 是否能够.调用一个名字,返回True或者False
    # getattr  直接获取一个变量中的名字的值
    # setattr  为一个变量增加或者修改一个属性
    # delattr  删除一个变量中的属性或者方法
    
    # 反射类中的名字
    # getattr(类名,'静态属性')
    # getattr(类名,'类方法')()
    # getattr(类名,'静态方法')()
    
    # 反射对象中的名字
    # getattr(对象名,'对象属性')
    # getattr(对象名,'方法名')()
    
    # 反射模块中的名字
    # import 模块名
    # getattr(模块名,'模块中的变量')
    # getattr(模块名,'模块中的函数')()
    # getattr(模块名,'模块中的类名')
    
    # 反射当前模块中的名字
    # import sys
    # getattr(sys.modules[__name__],'变量')
    # getattr(sys.modules[__name__],'函数')()
    # getattr(sys.modules[__name__],'类名')
    反射总结公式

     二、特殊的内置方法函数

    1、__str__和__repr__

    改变对象的字符串显示__str__,__repr__

    自定制格式化字符串__format__

    #_*_coding:utf-8_*_
    
    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 __repr__(self):
            return 'School(%s,%s)' %(self.name,self.addr)
        def __str__(self):
            return '(%s,%s)' %(self.name,self.addr)
    
        def __format__(self, format_spec):
            # if format_spec
            if not format_spec or format_spec not in format_dict:
                format_spec='nat'
            fmt=format_dict[format_spec]
            return fmt.format(obj=self)
    
    s1=School('oldboy1','北京','私立')
    print('from repr: ',repr(s1))       #from repr:  School(oldboy1,北京)
    print('from str: ',str(s1))         #from str:  (oldboy1,北京)
    print(s1)                           #(oldboy1,北京)
    
    '''
    str函数或者print函数--->obj.__str__()
    repr或者交互式解释器--->obj.__repr__()
    如果__str__没有被定义,那么就会使用__repr__来代替输出
    注意:这俩方法的返回值必须是字符串,否则抛出异常
    '''
    print(format(s1,'nat'))         #oldboy1-北京-私立
    print(format(s1,'tna'))         #私立:oldboy1:北京
    print(format(s1,'tan'))         #私立/北京/oldboy1
    print(format(s1,'asfdasdffd'))  #oldboy1-北京-私立
    View Code
    class B:
        def __str__(self):
            return 'str : class B'
    
        def __repr__(self):
            return 'repr : class B'
    
    b=B()
    print('%s'%b)   #str : class B
    print('%r'%b)   #repr : class B
    %s与%r

     2、__del__

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

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

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

    3、item系列

    __getitem__/__setitem__/__delitem__
    #__xxxitem__:使用 [''] 的方式操作属性时被调用
    
    class Foo:
        #初始化方法
        def __init__(self,name):
            self.name=name
    
        #当访问不存在的属性时会调用该方法
        def __getitem__(self, item):
            print(self.__dict__[item])
    
        #:每当属性被赋值的时候都会调用该方法,因此不能再该方法内赋值 self.name = value 会死循环
        def __setitem__(self, key, value):
            self.__dict__[key]=value
    
        #当删除属性时调用该方法    
        def __delitem__(self, key):
            print('del obj[key]时,我执行')
            self.__dict__.pop(key)
    
        #删除指定对象的指定名称的属性
        def __delattr__(self, item):
            print('del obj.key时,我执行')
            self.__dict__.pop(item)
    
    #实例化对象
    f1=Foo('sb')
    f1['age']=18
    f1['age1']=19
    print(f1.__dict__)  #{'name': 'sb', 'age': 18, 'age1': 19}
    del f1.age1         #del obj.key时,我执行
    del f1['age']       #del obj[key]时,我执行
    f1['name']='alex'
    print(f1.__dict__)  #{'name': 'alex'}
    View Code

    4、__new__

    构造方法,当实例化对象时,会优先自动执行该方法

    # new一个对象
    # object.__new__()
    class A:
        def __init__(self):
            print('执行init方法')
        def __new__(cls):
            print('执行new方法')
            #创造对象 将对象返回
            return object.__new__(cls)
    
    a = A()
    #输出结果:
    # 执行new方法
    # 执行init方法
    print(type(a))  #<class '__main__.A'>
    print(type(A))  #<class 'type'>
    
    # 先执行__new__方法 创造出一个对象
    # 然后把创造出来的对象传递给__init__方法
    # 会把self自动的返回,被a接收
    
    
    # 元类
    # 有一个元类 在创建类
    # type()  所有直接用class创建出来的类的元类都是type
    
    # class 类名(B,classMeta = 元类名)
    # class 类名(B,classMeta = type)  # 默认
    
    # 元类 创造 类     所以所有的类的type都是它的元类,默认是type
    # 类   创造 对象   具体创造对象的方法 __new__方法,所有的对象的type都是它对应的类
    
    # python中 一切皆对象
    # 变量 都有它属于的数据类型
    View Code
    #单例模式
    class Singleton:
        def __new__(cls, *args, **kw):
            if not hasattr(cls, '_instance'):
                cls._instance = object.__new__(cls, *args, **kw)
            return cls._instance
    
    #实例化对象
    one = Singleton()
    two = Singleton()
    
    two.a = 3
    print(one.a)    # 3
    # one和two完全相同,可以用id(), ==, is检测
    print(id(one))  # 2363725443368
    print(id(two))  # 2363725443368
    print(one == two)   # True
    print(one is two)   # True
    单例模式一
    # 设计模式
    # 单例模式
    # 一个类 可以被多次实例化 但是同一时间在python的内存中,只能有一个实例
    class A:
        _instance = None    #静态变量
        #初始化方法
        def __init__(self, name):
            '''给娃娃穿衣服'''
            self.name = name
        #构造方法    
        def __new__(cls, *args, **kwargs):
            '''生娃的过程'''
            if not 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
    
    
    #第二种方法
    class B:
        #初始化方法
        def __init__(self,name):
            '''给娃穿衣服'''
            self.name = name
        #构造方法
        def __new__(cls, *args, **kwargs):
            '''生娃的过程'''
            if not hasattr(B, '_instance'):
                B._instance = object.__new__(cls)
            return B._instance
    
    a1 = B('alex')  # 第一次实例化的时候创造一个实例
    print(a1.name)      #alex
    a2 = B('egon')
    print(a1.name,a2.name)  #egon egon
    单例模式二

     5、__call__

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

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

    class Foo:
        #初始化方法
        def __init__(self):
            print('执行__init__')
        #构造方法
        def __call__(self, *args, **kwargs):
            print('执行__call__')
        #常规方法
        def call(self):
            print('执行call')
    
    obj = Foo() # 执行__init__
    obj()       # 执行__call__
    obj.call()  # 执行call
    View Code

    6、__len__

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
        
        def __len__(self):
            return len(self.__dict__)
    
    a = A()
    print(len(a))   #2
    View Code

    7、__hash__

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __hash__(self):
            return hash(str(self.a)+str(self.b))
    
    a = A()
    print(hash(a))  #-8485950673113911502
    View Code

    8、__eq__

    class A:
        def __init__(self):
            self.a = 1
            self.b = 2
        #是==的内置方法
        def __eq__(self,obj):
            if  self.a == obj.a and self.b == obj.b:
                return True
    
    a = A()
    b = A()
    print(a == b)   #True
    View Code
    from collections import namedtuple
    Card = namedtuple('Card',['rank','suit'])
    
    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):
            return len(self._cards)
    
        #返回纸牌列表的某张纸牌
        def __getitem__(self, item):
            return self._cards[item]
    
    #纸牌实例化
    deck = FranchDeck()
    print(deck[0])      #Card(rank='2', suit='红心')
    
    #随机抽牌
    from random import choice
    print(choice(deck))     #Card(rank='A', suit='红心')
    print(choice(deck))     #Card(rank='K', suit='方板')
    纸牌游戏
    #可命名元组
    from collections import namedtuple
    Card = namedtuple('Card',['rank','suit'])
    
    #纸牌类
    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):
            return len(self._cards)
    
        #返回纸牌列表的某张纸牌
        def __getitem__(self, item):
            return self._cards[item]
    
        #增加或修改纸牌
        def __setitem__(self, key, value):
            self._cards[key] = value
    
    #实例化纸牌对象
    deck = FranchDeck()
    print(deck[0])      #Card(rank='2', suit='红心')
    
    #随机抽牌
    from random import choice
    print(choice(deck))     #Card(rank='7', suit='梅花')
    print(choice(deck))     #Card(rank='Q', suit='梅花')
    
    #随机洗牌
    from random import shuffle
    shuffle(deck)           
    print(deck[:5])         
    #输出结果
    #[Card(rank='2', suit='红心'), Card(rank='8', suit='梅花'), Card(rank='6', suit='黑桃'), 
    # Card(rank='5', suit='方板'), Card(rank='5', suit='梅花')]
    纸牌游戏2
  • 相关阅读:
    Java 接口
    Java 数据结构
    Java 包(package)
    一步步学习SPD2010--第四章节--创建和修改网页(9)--附上母版页
    一步步学习SPD2010--第四章节--创建和修改网页(8)--插入Web部件区域
    一步步学习SPD2010--第四章节--创建和修改网页(7)--创建ASP.NET页面
    一步步学习SPD2010--第四章节--创建和修改网页(6)--创建和修改列表表单页面
    一步步学习SPD2010--第四章节--创建和修改网页(5)--创建列表视图页面
    一步步学习SPD2010--第四章节--创建和修改网页(4)--修改列表视图页面
    一步步学习SPD2010--第四章节--创建和修改网页(3)--改变网站的首页
  • 原文地址:https://www.cnblogs.com/lioushell/p/8549702.html
Copyright © 2011-2022 走看看