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

    1 isinstance(obj,cls)和issubclass(sub,super)

    isinstance(obj,cls) obj是否是cls的对象或cls子类的对象
    issubclass(sub,super) sub是否是super的子类
    cls.__bases__ 获取cls的父类

    class A:
        pass
    
    class B(A):
        pass
    
    print(issubclass(B,A))  #True
    print(B.__bases__)
    
    b=B()
    print(isinstance(b,B))  #True
    

    2 反射

    反射也叫自省,主要设置程序可以访问、检测和修改它本身状态或行为的一种能力。

    2.1 python中面向对象的反射

    Python中是通过字符串的形式来操作对象相关的属性。python 中一切皆对象(都可以使用反射)
    具体的做法是:将字符串映射成命令

    四个实现自省的函数

    2.1.1 hasattr

    hasattr(object,name)

    判断object是否有名字是name的属性。
    等价于 name in object.__dict__

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    class Foo:
        camp="foo"
        def __init__(self,name):
            self.name=name
    
        def test1(self):
            print("test1")
    
    f=Foo("zzz")
    
    #不用反射来,访问属性
    # print(f.name)
    # f.name="yyy"
    # print(f.name)
    
    #使用反射
    #hasattr
    print(f.__dict__)
    print(hasattr(f,"name"))  #判断f对象的名称空间里,有么有"name"这个属性,等价于"name" in f.__dict__
    print("name" in f.__dict__)   #True
    print("camp" in Foo.__dict__)     #True
    

    2.1.2 getattr

    getattr(object, name, default=None)

    获取object名称空间里的"name"属性的值,如果存在,就返回该值;不存在,就返回default。
    等价于:object.name (object.__dict__["name"])

    #getattr
    print(f.name)
    print(getattr(f,"name"))   #获取f对象名称空间里"name"属性的值,等价于 f.name  <======> f.__dict__["name"]
    print(getattr(f,"age",-1))   #获取f对象名称空间里"age"属性的值,如果不存在,就返回-1
    #print(f.age)   #AttributeError: 'Foo' object has no attribute 'age'
    print(Foo.camp)       #foo
    print(Foo.__dict__["camp"])   #foo
    

    ### 2.1.3 setattr

    setattr(object, name, value)

    修改对象object的name属性值为value。
    等价于:object.name=value

    #setattr
    setattr(f,"name","yyy")    #等价于f.name="yyy"   <=====>f.__dict__["name"]="yyy"
    print(getattr(f,"name"))
    setattr(Foo,"camp","fooo")
    Foo.camp="fooo"
    #Foo.__dict__["camp"]="fooo"    #TypeError: 'mappingproxy' object does not support item assignment
    print(getattr(Foo,"camp"))
    

    2.1.4 delattr

    delattr(object,name)

    删除object对象的名称空间下的名叫name的属性
    等价于:del object.name

    #delattr
    delattr(f,"name")   #等价于del f.name   <=====>f.__dict__.pop("name")
    #print(f.name)
    
    

    2.2 反射的两种形式

    2.2.1 基于类和对象的反射

    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'))
    

    结果:

    old boy
    <function Foo.func at 0x000001EDF525BB70>
    <function Foo.bar at 0x000001EDF525BBF8>
    

    2.2.2 基于模块的反射

    在python中,每一个.py文件都是一个模块,而模块都是一个个对象。

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    import sys
    
    class Foo:
        def __init__(self,name):
            self.name = name
    
        def get_name(self):
            return self.name
    
    
    #获取模块的名称
    #print(__name__)
    this_module=sys.modules[__name__]
    print(this_module)  #获取本文件的模块对象,通过该对象可以调用本文件下的变量、函数、类等
    #print(sys.modules)
    
    print(hasattr(this_module,"Foo"))
    
    print(getattr(this_module,"Foo"))
    
    

    结果:

    __main__
    <module '__main__' from 'D:/devtools/workspace/python/PycharmProjects/py_fulstack_s4/day32 面向对象的进阶/基于模块的反射.py'>
    True
    <class '__main__.Foo'>
    

    2.3 反射的用途(好处)

    2.3.1 实现可插拔机制

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

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    
    class FtpClient:
        def __init__(self, addr):
            print("正在连接服务器[%s]" % addr)
            self.addr = addr
    
        #def get():
    
    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    
    from developer_one import FtpClient
    f1=FtpClient("192.168.1.1")
    if hasattr(f1,"get"):
        func_get=getattr(f1,"get")
        func_get()
    else:
        print("不存在此方法")
        print("处理其他的逻辑")
    
    
    #即使调用的developer_one中FtpClient模块的功能“get”有没有完成,都不影响程序的正常执行。这就叫可插拔机制。
    

    2.3.2 用字符串导入模块

    m=input(">>").strip()   #官方不推荐
    m1=__import__(m)
    print(m1.time())
    
    
    import importlib   #官方推荐方案
    t=importlib.import_module("time")
    

    2.4 日常中的“反射”

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    
    def delete():
        print("delete")
    
    def add():
        print("add")
    
    def search():
        print("search")
    
    def modify():
        print("modify")
    
    file_dict={                #相当于对象的名称空间
        "delete":delete,
        "add":add,
        "search":search,
        "modify":modify,
    }
    
    while True:
        choice=input(">>:").strip()
        if not choice:continue
        if choice in file_dict:     #相当于hasattr(file_dict,choice)
            func=file_dict[choice]   #getattr(file_dict,choice)
            func()
    

    3 __setattr__,__delattr__,__getattr__

    3.1 __setattr__

    __setattr__ #在对象进行赋值(包括类的初始化)操作时,会自动调用

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    class Foo:
        def __init__(self,name):
            self.name=name
    
    
        def __setattr__(self, key, value):   #对对象的属性进行赋值(包括类的初始化)操作时,会自动调用
            print("key : %s , value : %s "%(key,value))  #key : name , value : zhang
            print("key type:",type(key))    #key type: <class 'str'>
                                            #为什么key的类型是str? 我们说了什么时候会自动调用这个函数。是在对象进行赋值的时候,其中有赋值操作的是,初始化f时。f=Foo("zhang"),在内存里面真正执行的是:f.__dict__["name"]="zhang"。所以说key是一个str类型。
            print("value type:",type(value))    #value type: <class 'str'>
            #print(self.key)      #AttributeError: 'Foo' object has no attribute 'key'
    
            #self.key=value     #RecursionError: maximum recursion depth exceeded
            #setattr(self,key,value)    #RecursionError: maximum recursion depth exceeded
            self.__dict__[key]=value
    
    f=Foo("zhang")
    

    结果:

    key : name , value : zhang 
    key type: <class 'str'>
    value type: <class 'str'>
    __getattr__ age
    
    

    3.2 __delattr__

    __delattr__是在执行删除del object.name时,自动调用

    class Foo:
        def __init__(self,name):
            self.name=name
    
        def __delattr__(self,item):    #在执行对象属性的删除操作时,会调用
            #del self.item  #RecursionError: maximum recursion depth exceeded while calling a Python object
            #del self.__dict__[item]
            self.__dict__.pop(item)
    
    f=Foo("zhang")
    del f.name
    #print(f.name)
    

    3.3 __getattr__

    __getattr__ 查找的对象属性不存在,才会触发__getattr__;查找的对象属性存在,不会触发

    class Foo:
        def __init__(self,name):
            self.name=name
    
        def __getattr__(self,item):      #查找的对象属性不存在,才会触发__getattr__;查找的对象属性存在,不会触发
            print("__getattr__",item)
    
    f=Foo("zhang")
    f.name    #未执行__getattr__
    f.age     #__getattr__ age
    #print(f.name)
    

    结果:

    __getattr__ age
    

    3.4 用途

    1 二次加工标准类型

    关键在于继承。

    class List(list):
        def append(self, obj):
            if not isinstance(obj,int):
                raise TypeError("must be int!")
            super().append(obj)
    
        def insert(self, index, obj):
            if not isinstance(obj,int):
                raise TypeError("must be int!")
            super().insert(index,obj)
    
    
    li=List((1,2,3))
    #li.insert(2,"-1")
    li.insert(2,-1)
    print(li)
    

    2 以授权的方式实现定制数据类型

    #!/user/bin/env python
    # -*- coding:utf-8 -*-
    
    class List:
        def __init__(self,li):
            self.x=list(li)
    
        def append(self,s):
            if isinstance(s,str):
                self.x.append(s)
            else:
                raise TypeError("传入列表的必须是字符串!")
    
        @property
        def mid(self):
            print("列表的中间值:",self.x[int(len(self.x)/2)])
    
        def __getattr__(self,item):
            if hasattr(self.x,item):
                return getattr(self.x,item)
            else:
                raise NameError("属性名错误!")
    
        def __str__(self):   #通过__str__来隐藏.x
            return str(self.x)
    
    li=List((1,2,3,4))
    li.append("s")
    print(li)
    li.mid
    li.pop(3)
    print(li)
    

    结果:

    [1, 2, 3, 4, 's']
    列表的中间值: 3
    [1, 2, 3, 's']
    
  • 相关阅读:
    对于服务器AdminServer, 与计算机Machine-0相关联的节点管理器无法访问
    C语言面试题目之指针和数组
    Go数据类型之基本数据类型
    【转载】虚拟地址与虚拟内存的理解
    const变量可以修改么?
    【转载】内联函数 —— C 中关键字 inline 用法解析
    【转载】抓包工具tcpdump用法说明
    【转载】网络编程面试题
    [leetcode]颠倒整数
    [leetcode]反转字符串
  • 原文地址:https://www.cnblogs.com/yangzhenwei123/p/6759317.html
Copyright © 2011-2022 走看看