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

    参考

    参考2

    一、反射(******)

    1 什么是反射

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

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

    四个可以实现自省的函数

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

    def hasattr(*args, **kwargs): # real signature unknown
        """
        Return whether the object has an attribute with the given name.
        
        This is done by calling getattr(obj, name) and catching AttributeError.
        """
        pass
    hasattr(object,name)
    def getattr(object, name, default=None): # known special case of getattr
        """
        getattr(object, name[, default]) -> value
    
        Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
        When a default argument is given, it is returned when the attribute doesn't
        exist; without it, an exception is raised in that case.
        """
        pass
    getattr(object, name, default=None)
    getattr(object, name, default=None)
    def setattr(x, y, v): # real signature unknown; restored from __doc__
        """
        Sets the named attribute on the given object to the specified value.
    
        setattr(x, 'y', v) is equivalent to ``x.y = v''
        """
        pass
    
    setattr(x, y, v)
    setattr(x, y, v)
    def delattr(x, y): # real signature unknown; restored from __doc__
        """
        Deletes the named attribute from the given object.
    
        delattr(x, 'y') is equivalent to ``del x.y''
        """
        pass
    
    delattr(x, y)
    delattr(x, y)
    class BlackMedium:
        feature='Ugly'
        def __init__(self,name,addr):
            self.name=name
            self.addr=addr
    
        def sell_house(self):
            print('%s 黑中介卖房子啦,傻逼才买呢,但是谁能证明自己不傻逼' %self.name)
        def rent_house(self):
            print('%s 黑中介租房子啦,傻逼才租呢' %self.name)
    
    b1=BlackMedium('万成置地','回龙观天露园')
    
    #检测是否含有某属性
    print(hasattr(b1,'name'))
    print(hasattr(b1,'sell_house'))
    
    #获取属性
    n=getattr(b1,'name')
    print(n)
    func=getattr(b1,'rent_house')
    func()
    
    # getattr(b1,'aaaaaaaa') #报错
    print(getattr(b1,'aaaaaaaa','不存在啊'))
    
    #设置属性
    setattr(b1,'sb',True)
    setattr(b1,'show_name',lambda self:self.name+'sb')
    print(b1.__dict__)
    print(b1.show_name(b1))
    
    #删除属性
    delattr(b1,'addr')
    delattr(b1,'show_name')
    delattr(b1,'show_name111')#不存在,则报错
    
    print(b1.__dict__)
    
    四个方法的使用演示
    四个方法的使用演示
    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')
    print getattr(Foo, 'func')
    print getattr(Foo, 'bar')
    
    类也是对象
    类也是对象
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    import sys
    
    
    def s1():
        print 's1'
    
    
    def s2():
        print 's2'
    
    
    this_module = sys.modules[__name__]
    
    hasattr(this_module, 's1')
    getattr(this_module, 's2')
    
    反射当前模块成员
    反射当前模块成员

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

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    def test():
        print('from the test')
    View Code
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    
    """
    程序目录:
        module_test.py
        index.py
    
    当前文件:
        index.py
    """
    
    import module_test as obj
    
    #obj.test()
    
    print(hasattr(obj,'test'))
    
    getattr(obj,'test')()
    View Code

    3 为什么用反射之反射的好处

    好处一:实现可插拔机制

    有俩程序员,一个lili,一个是egon,lili在写程序的时候需要用到egon所写的类,但是egon去跟女朋友度蜜月去了,还没有完成他写的类,lili想到了反射,使用了反射机制lili可以继续完成自己的代码,等egon度蜜月回来后再继续完成类的定义并且去实现lili想要的功能。

    总之反射的好处就是,可以事先定义好接口,接口只有在被完成后才会真正执行,这实现了即插即用,这其实是一种‘后期绑定’,什么意思?即你可以事先把主要的逻辑写好(只定义接口),然后后期再去实现接口的功能

    class FtpClient:
        'ftp客户端,但是还么有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
    egon还没有实现全部功能
    #from module import FtpClient
    f1=FtpClient('192.168.1.1')
    if hasattr(f1,'get'):
        func_get=getattr(f1,'get')
        func_get()
    else:
        print('---->不存在此方法')
        print('处理其他的逻辑')
    
    不影响lili的代码编写
    不影响lili代码编写

    好处二:动态导入模块(基于反射当前模块成员)

    #(1) 反射对象   # hasattr getattr setattr delattr
    class A:
        def func(self):
            print('in func')
    
    a = A()
    a.name = 'alex'
    a.age = 63
    # 反射对象的属性
    ret = getattr(a,'name')  # 通过变量名的字符串形式取到的值
    print(ret)   #alex
    # print(a.__dict__)        #{'name': 'alex', 'age': 63}
    var = input('>>>')     # age
    # print(a.__dict__[变量名]) #63
    print(getattr(a,var))  #63
    
    
    # 反射对象的方法
    # a.func()   #in func
    ret = getattr(a,'func')
    ret()      #in func
    
    #(2) 反射类
    class A:
        price = 20
        @classmethod
        def func(cls):
            print('in func')
    
    # 反射类的属性
    # print(A.price)  #20
    print(getattr(A,'price')) #20
    #
    # 反射类的方法 :classmethod staticmethod
    print(A.func())  #in func
    if hasattr(A,'func'):
        getattr(A,'func')()  #in func
    
    #(3) 反射模块
    import my
    '''
    my.py
            day = 'Monday'  # 周一
            def wahaha():
                print('wahahaha')
    
            class C: pass
    '''
    # 反射模块的属性
    # print(my.day)  # Monday
    print(getattr(my,'day'))  # Monday
    
    # 反射模块的方法
    getattr(my,'wahaha')()  #wahahaha
    
    
    #(4) 反射内置模块
    import time
    print(getattr(time,'time')())     #1590662183.0512092
    print(getattr(time,'asctime')())  #Thu May 28 18:36:23 2020
    
    #(5) 反射自己模块
    def qqxing():
        print('qqxing')
    year = 2018
    import sys
    # sys.modules['__main__']  #找到当前模块
    print(sys.modules['__main__'])
    print(sys.modules['__main__'].year)   #2018
    # 反射自己模块中的变量
    print(getattr(sys.modules['__main__'],'year'))  #2018# 反射自己模块中的函数
    getattr(sys.modules['__main__'],'qqxing')()  # #qqxing    #main最好写成一个变量name
    blm = input('>>>')  #year
    print(getattr(sys.modules[__name__],blm))  #2018
    # 正常运行的时候name变量等于模块的名字,防止本被其它模块导入造成反射不成功的影响
    
    
    #(6) 反射模块中的类
    import my
    print(getattr(my,'C')())   #实例化模块my中的类C,得到一个对象  <my.C object at 0x000000000221ADA0>
    if hasattr(my,'name'):
        getattr(my,'name')  #没有这个变量name,什么都不打印
        
    
    #(7)settar和delatter 重要程度半颗星
    # setattr  设置修改变量
    class A:
        pass
    a = A()
    setattr(a,'name','nezha')    #这个name存在对象a的内存空间中
    setattr(A,'name','alex')     #这个name存在类A的内存空间中
    print(A.name)  #alex
    print(a.name)  #nezha
    
    # delattr 删除一个变量
    delattr(a,'name')
    print(a.name)     #alex   把对象a的name删除了,会从当前类A中寻找name:'alex'
    delattr(A,'name')  
    print(a.name)     #把类中的name也删除了,报错

    反射小示例:

    class Teacher:
        dic = {'查看学生信息':'show_student','查看讲师信息':'show_teacher'}
        def show_student(self):
            print('show_student')
    
        def show_teacher(self):
            print('show_teacher')
    
        @classmethod
        def func(cls):
            print('hahaha')
    alex = Teacher()
    for k in Teacher.dic:
        print(k)
    key = input('输入需求 :')
    if hasattr(alex,Teacher.dic[key]):
        func = getattr(alex,Teacher.dic[key])
        func()

     

    反射应用场景:flask配置文件以及Django中间件都用到了反射

    二、 isinstance(obj,cls)和issubclass(sub,super)(***)

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

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

    class A:pass
    class B(A):pass
    a = A()
    print(isinstance(a,A))    #True
    print(issubclass(B,A))    #True
    print(issubclass(A,B))    #False

     三、几个类的内置方法(**)

    1、__str____repr__

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

    自定制格式化字符串__format__

    # 内置的类方法 和 内置的函数之间有着千丝万缕的联系
    
    class A:pass
    a=A()
    print(a) #<__main__.A object at 0x0000000001E1A860>
    #先去a里面找__str__方法,没有找到的话就去父类object里面找__str__方法
    # object  里有一个__str__,一旦被调用,就返回调用这个方法的对象的内存地址
    
    class Teacher:
        def __init__(self,name,salary):
            self.name = name
            self.salary = salary
        def __str__(self):   #自己实现__str__方法
            return "Teacher's object :%s"%self.name
        def __repr__(self):
            return str(self.__dict__)
        def func(self):
            return 'wahaha'
    nezha = Teacher('哪吒',250)
    print(nezha)  # 打印一个对象的时候,就是调用nazha.__str__   #Teacher's object :哪吒
    print(repr(nezha))  #{'name': '哪吒', 'salary': 250}
    print('>>> %r'%nezha) #>>> {'name': '哪吒', 'salary': 250}
    
    l = [1,2,3,4,5]   # 实例化 实例化了一个列表类的对象
    print(l) #之所以打印出了[1, 2, 3, 4, 5]是因为重定制了它了str方法
    # %s str()  直接打印 实际上都是调用的_str__方法
    # %r repr()  实际上都是调用__repr__方法
    # repr 是str的备胎:如果当前类中没有str方法但有repr方法,打印str的时候会走当前类的repr方法,但str不能做repr的备胎
    
    # print(obj) / '%s'%obj / str(obj)的时候,实际上是内部调用了obj.__str__方法,如果str方法有,那么他返回的必定是一个字符串
    # 如果没有__str__方法,会先找本类中的__repr__方法,再没有再找父类中的__str__。
    # repr(),只会找__repr__,如果没有找父类的
    
    # 内置的方法有很多
    # 不一定全都在object中
    class Classes:
        def __init__(self,name):
            self.name = name
            self.student = []
        def __len__(self):
            return len(self.student)
        def __str__(self):
            return 'classes'
    py_s9= Classes('python全栈9期')
    py_s9.student.append('二哥')
    py_s9.student.append('泰哥')
    print(len(py_s9))  #2
    print(py_s9)  #classes

    2、__del__

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

    注:如果产生的对象仅仅只是python程序级别的(用户级),那么无需定义__del__,如果产生的对象的同时还会向操作系统发起系统调用,即一个对象有用户级与内核级两种资源,比如(打开一个文件,创建一个数据库链接),则必须在清除对象的同时回收系统资源,这就用到了__del__

    class A:
        def __del__(self):   # 析构函数: 在删除一个对象之前进行一些收尾工作
            print("执行到我啦!")
    a = A()
    del a   #执行到我啦!      del 既执行了这个方法,又删除了变量  
    class Foo:
    
        def __del__(self):
            print('执行我啦')
    
    f1=Foo()
    # del f1
    print('------->')
    
    #输出结果
    ------->
    执行我啦
    
    
    
    #为何啊???
    挖坑埋了你 

    3、 __call__

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

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

    class A:
        def __init__(self,name):
            self.name = name
        def __call__(self):
            '''
            打印这个对象中的所有属性
            :return:
            '''
            for k in self.__dict__:
                print(k,self.__dict__[k])
    a = A('alex')()  #name alex

     4、item系列

    __getitem____setitem____delitem__

    class Foo:
        def __init__(self,name,age,sex):
            self.name = name
            self.age = age
            self.sex = sex
    
        def __getitem__(self, item):
            if hasattr(self,item):
                return self.__dict__[item]
    
        def __setitem__(self, key, value):
            self.__dict__[key] = value
    
        def __delitem__(self, key):
            del self.__dict__[key]
    
    f = Foo('egon',38,'')
    print(f['name']) #egon   会触发类中的getitem方法,并把'name'传给itme
    f['hobby'] = ''  #会触发类中的setitemi方法,并把'hobby'传给key,'女'传给value
    print(f.__dict__)  #{'name': 'egon', 'age': 38, 'sex': '男', 'hobby': '女'}
    print(f.hobby,f['hobby'])  #女 女
    # del f.hobby      # object 原生支持  __delattr__
    del f['hobby']     # 通过自己实现的  会触发类中的delitem方法,并把'hobby'传给key
    print(f.__dict__)  #{'name': 'egon', 'age': 38, 'sex': '男'}
    示例

    5、__new__(MS)

    __init__ 初始化方法
    __new__ 构造方法 : 创建一个对象
    我们都知道在__init__之前就已经有一个self了,这个self就是__new__造出来的
    class A:
        def __init__(self):
            self.x = 1
            print('in init function')
        def __new__(cls, *args, **kwargs):#为什么不传self呢,因为new方法之后才有self
            print('in new function')
            return object.__new__(A, *args, **kwargs) #创建一个对象self,返回到上面了
    
    a1 = A()
    '''
        in new function
        in init function
    '''
    a2 = A()
    '''
        in new function
        in init function
    '''
    print(a1)  #<__main__.A object at 0x00000000021BA8D0>
    print(a2)  #<__main__.A object at 0x0000000001E7A8D0>

    单例模式:
     一个类 始终 只有 一个 实例
     当你第一次实例化这个类的时候 就创建一个实例化的对象
     当你之后再来实例化的时候 就用之前创建的对象

    class A:
        __instance = False
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def __new__(cls, *args, **kwargs):
            if cls.__instance: #如果之前创建过对象就不在创建了,返回之前创建的对象
                return cls.__instance
            cls.__instance = object.__new__(cls) #如果之前没有创建过对象,创建对象
            return cls.__instance
    
    egon = A('egg',38)
    egon.cloth = '小花袄'
    nezha = A('nazha',25)
    print(nezha) #<__main__.A object at 0x0000000001EAA9B0>
    print(egon)  #<__main__.A object at 0x0000000001EAA9B0>  和上面内存地址一样,说明是同一个对象
    print(nezha.name)  #nazha
    print(egon.name)   #nazha
    print(nezha.cloth) #小花袄
    
    #第一实例化的时候可以比喻女娲造出了一个小人,给小人起了一个名字,赋予了年龄,
    #第二次实例化的时候拿到的还是之前造出的那个小人,如果小人没有名字和年龄就给它名字和年龄
    # 如果有名字年龄就把它们删了重新赋予名字和年龄,也就是它们操作的都是同一个对象
    单立模式

    6、__eq__

    判断两个对象是否相等,正常情况下比较内存地址,如果重新对它进行定制它对根据定制的条件来判断两个对象是否相等

    class A:
        def __init__(self,name):
            self.name = name
    
        def __eq__(self, other):
            if self.__dict__ == other.__dict__:
                return True
            else:
                return False
    
    ob1 = A('egon')
    ob2 = A('egg')
    print(ob1 == ob2)  #False     此时==会触发eq方法
    eq示例

    7、__hash__

    只要是可hash的,内部一定实现了一个__hash__方法,默认根据对象的内存地址进行hash,也可以自定制规则

    class A:
        def __init__(self,name):
            self.name = name
    
    m=A('hui')
    n=A('hui')  
    print(hash(m))  #2005673  #默认根据对象的内存地址进行hash
    print(hash(n))  #-9223372036852770132
    
    
    class B:
        def __init__(self,name,sex):
            self.name = name
            self.sex = sex
        def __hash__(self):  #自定制hash
            return hash(self.name+self.sex)
    
    a = B('egon','')
    b = B('egon','')
    print(hash(a))    #-4411851472115669131
    print(hash(b))    #-4411851472115669131
    
    c = B('egon0','')
    d = B('egon0','')
    print(hash(c))     #247660479663688395
    print(hash(d))     #5874602778707716777
    hash示例

    示例:

    import json
    from collections import namedtuple
    Card = namedtuple('Card',['rank','suit'])   # rank 牌面的大小 suit牌面的花色
    class FranchDeck:
        ranks = [str(n) for n in range(2,11)] + list('JQKA')   # 2-A
        suits = ['红心','方板','梅花','黑桃']
    
        def __init__(self):
            self._cards = [Card(rank,suit) for rank in FranchDeck.ranks
                                            for suit in FranchDeck.suits]
            # for suit in FranchDeck.suits:
            #     for rank in FranchDeck.ranks:
            #         Card(suit,rank)
    
        def __len__(self):
            return len(self._cards)
    
        def __getitem__(self, item):
            return self._cards[item]
    
        def __setitem__(self, key, value):
            self._cards[key] = value
    
        def __str__(self):
            return json.dumps(self._cards,ensure_ascii=False)  #
    
    deck = FranchDeck()
    print(deck[10])                               #取牌      #Card(rank='4', suit='梅花')
    from random import choice
    print(choice(deck))  #choice依赖内置的len方法   #抽牌      #Card(rank='4', suit='红心')
    
    from random import shuffle
    shuffle(deck)       #shuffle依赖内置的setitem  #洗牌
    print(deck[10])                                           #Card(rank='8', suit='红心')
    print(deck)      #[["A", "红心"], ["5", "方板"], ["6", "方板"],["2", "方板"], ["3", "方板"],…… ["2", "黑桃"], ["A", "方板"]]
    print(deck[:5])   #[Card(rank='A', suit='红心'), Card(rank='5', suit='方板'), Card(rank='6', suit='方板'),
                      # Card(rank='2', suit='方板'), Card(rank='3', suit='方板')]
    
    # 内置函数 内置的模块 内置的基础类型 < --- >类的内置方法
    纸牌游戏
    # 100个人,name/sex/age
    #每年录入他们的信息,特点 名字 和 性别相同, 年龄不同
    #录入的信息怎么和之前录入的信息进行去重
    # set
    class A:
        def __init__(self,name,sex,age):
            self.name = name
            self.sex = sex
            self.age = age
    
        def __eq__(self, other):
            if self.name == other.name and self.sex == other.sex:
                return True
            return False
    
        def __hash__(self):
            return hash(self.name + self.sex)
    
    a = A('egg','',38)
    b = A('egg','',37)
    print(set((a,b)))   # unhashable   #{<__main__.A object at 0x00000000021DA7F0>}
    
    # set 依赖对象的 hash eq
    MS
  • 相关阅读:
    debian 安装deb软件
    Linux的发行版之间的联系和区别
    Linux软件包安装(rpm、yum、apt-get)
    在deepin中安装docker
    使用BeanUitls提高对象拷贝效率
    Nginx下载和安装与启动
    Spring Boot 的项目打包成的 JAR 包,制作成 docker 镜像并运行
    Java并发编程实战(使用synchronized实现同步方法)
    Java7并发编程实战(一) 守护线程的创建和运行
    Java7并发编程实战(一) 线程的等待
  • 原文地址:https://www.cnblogs.com/zh-xiaoyuan/p/12983373.html
Copyright © 2011-2022 走看看