• python面向对象进阶(上)


    一 、isinstance(obj,cls)和issubclass(sub,super)

    (1)isinstance(obj,cls)检查对象obj是否是类 cls 的对象,返回True和Flase

    示例:

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    p=People("xuyaunyuan")
    print(p.name)
    print(isinstance(p,People))#判断对象P是不是类People的对象
    

    执行结果是:

    xuyaunyuan
    True
    

     

    (2)issubclass(sub, super)检查sub类是否是 super 类的派生类,返回True和Flase

    示例:

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    class Student(People):
        def __init__(self,name,id):
            self.name=name
            self.id=id
    print(issubclass(Student,People))#检查Student类是否是 super 类(people类)的派生类
    

    执行结果是:

    True
    

      

     

    二 、反射

    (1)反射的概念:主要是指程序可以访问、检测和修改它本身状态或行为的一种能力(自省)。

    (2)四个可以实现自省的函数(下列方法适用于类和对象,一切皆对象,类本身也是一个对象)

    a、hasattr(object,name)——判断object中有没有一个name字符串对应的方法或属性

    b、getattr(object,name)——获取属性

    c、setattr(x, y, v)——设置属性

    d、delattr(x, y)——  删除属性

    分别示例:

    a、hasattr(object,name)——判断object中有没有一个name字符串对应的方法或属性

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    p=People("xuyaunyuan")
    #hasattr有没有
    print(hasattr(p,"name"))#判断对象P有没有name属性
    print("name" in p.__dict__)#等同于上面
    

    执行结果是:

    True
    True
    

     

    b、getattr(object, name, default=None)——获取属性

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    p=People("xuyaunyuan")
    #getattr#获取
    print(getattr(p,"country"))#获取数据属性country
    print(getattr(p,"name"))
    

    执行结果是:

    china
    xuyaunyuan
    

      

    c、setattr(x, y, v)——设置属性

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    p=People("xuyaunyuan")
    #setattr设置setatttr(x指对象,y指属性,v指value值)
    setattr(p,"age",18)
    setattr(p,"sex","woman")
    print(p.__dict__)#查看是否设置成功
    

    执行结果是:

    {'name': 'xuyaunyuan', 'age': 18, 'sex': 'woman'}
    

      

    d、delattr(x, y)——  删除属性

    class People:
        country="china"
        def __init__(self,name):
            self.name=name
        def test(self):
            print("test")
    p=People("xuyaunyuan")
    #delattr#删除
    delattr (p,"name")
    print(p.__dict__)#查看是否删除成功
    

    执行结果是:

    {}
    

      

    总结:

    hasattr(obj,'属性') #obj.属性 是否存在
    getattr(obj,'属性') #获取obj.属性 不存在则报错
    getattr(obj,'属性','默认值') #获取obj.属性 不存在不会报错,返回那个默认值
    setattr(obj,'属性','属性的值') #obj.属性=属性的值
    delattr(obj,'属性') #del obj.属性

     

    (3)反射当前模块的属性

    关于文件的2种运行方式:把文件当脚本运行和把文件当做模块导入

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

    示例:

    新建2个文件,分别取名为test.py和test1.py

    import sys
    ##在test.py文件下定义一些名字
    x=11#定义变量名x
    class People:#定义类名People
        def __init__(self):
            pass
    def s1():#定义函数名s1
        print("s1")
    def s2():#定义函数名s2
        print("s2")
    
    import test#在test1.py的文件下导入test模块
    
    #在test1.py的文件下导入test模块
    print(test)#打印导入的test模块
    print(test.People)#打印类
    test.s1()#运行函数s1
    test.s2()#运行函数s2
    print(test.x)#打印变量x
    

    执行结果是:

    <module 'test' from 'C:\Users\Administrator\PycharmProjects\py_fullstack_s4\day32-面向对象进阶\模块导入\test.py'>
    <class 'test.People'>
    s1
    s2
    11
    

      

    b、在自己的文件内部查看自己的模块

    this_module = sys.modules[__name__]#在自己的文件内查看自己的模块和绝对路径
    print(this_module)
    示例:
    import sys
    class Foo:
        pass
    def s1():
        print('s1')
    
    def s2():
        print('s2')
    this_module = sys.modules[__name__]#在自己的文件内查看自己的模块和绝对路径
    print(this_module)
    
    print(hasattr(this_module, 's1'))#也可进行判断在this_module里面有没有s1
    print(getattr(this_module, 's2'))#也可获取this_module里面的s2
    this_module.s2()#运行s2函数
    this_module.s1()#运行s1函数
    

      

    执行结果是:

    <module '__main__' from 'E:/飞秋/徐圆圆课程视频/Python fullstack s4 基础篇-day31/day31/test.py'>
    True
    <function s2 at 0x000000000282A8C8>
    s2
    s1

      

    (4)反射的好处(为什么要用反射)

    好处一:实现可插拔机制

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

     示例:

    新建2个文件,分别为客户端和服务端

    在客户端定义如下:

    class FtpClient:
        'ftp客户端,但是还有没有实现具体的功能'
        def __init__(self,addr):
            print('正在连接服务器[%s]' %addr)
            self.addr=addr
        def test(self):
            print('test')
    

    在服务端调用:

    import ftpclient
    print(ftpclient)
    f1=ftpclient.FtpClient('192.168.1.1')
    if hasattr(f1,'get'):#客户端并没有定义get函数,如果定义了的话,即可运行
        func=getattr(f1,'get')#客户端并没有定义get函数
        func()
    else:
        print('其他逻辑')
    

    执行结果是:

    <module 'ftpclient' from 'E:\飞秋\徐圆圆课程视频\Python fullstack s4 基础篇-day31\day31\反射实现可插拔机制\ftpclient.py'>
    正在连接服务器[192.168.1.1]
    其他逻辑
    

     

    好处二:动态导入模块

    示例:方法一 (利用内置函数)

    #不推荐用法
    m=input("请输入你要导入的模块:")
    m1=__import__(m)#内置函数
    print(m1)
    print(m1.time())
    

    执行结果是:

    请输入你要导入的模块:time
    <module 'time' (built-in)>
    1493024366.8544436
    

    示例:方法二(推荐用法)

    #推荐使用方法
    import importlib#调用模块
    t=importlib.import_module('time')
    print(t.time())
    

    执行结果是:

    1493024403.4785383

     

    三、__setattr__,__delattr__,__getattr__

    三个参数,给对象添加属性

    __setattr__   添加/修改属性会触发它的执行

    __delattr__   删除属性的时候会触发

    __getattr__   只有在使用点调用属性且属性不存在的时候才会触发

     作用:系统内置函数属性(你定义了就用你定义的函数属性,不定义就用系统默认的函数属性)

     整体使用情况示例:

    class Foo:
        def __init__(self,name):
            self.name=name
        def __setattr__(self, key, value):
            print("——setattr——key:%s value:%s"%(key,value))
            print(type(key))
            print(type(value))
            # self.key = value  # 这就无限递归了,不能用
            self.__dict__[key]=value#将值加入字典内
    
        def __delattr__(self, item):
            print("——delattr——item:%s"%item)
            print(type(item))
            # del self.item #无限递归了,不能用
            self.__dict__.pop(item)#删除
    
        def __getattr__(self, item):
            print('----> from getattr:你找的属性不存在')
    
    #__setattr__添加/修改属性会触发它的执行
    f=Foo("xuyuanyuan")
    print(f.__dict__)# 因为你重写了__setattr__,凡是赋值操作都会触发它的运行,你啥都没写,就是根本没赋值,除非你直接操作属性字典,否则永远无法赋值
    f.age="18"#增加age属性
    print(f.__dict__)
    
    #__delattr__删除属性的时候会触发
    f.__dict__['age']=18#我们可以直接修改属性字典,来完成添加/修改属性的操作
    del f.age
    print(f.__dict__)
    
    #__getattr__只有在使用点调用属性且属性不存在的时候才会触发
    f.aaa
    

    执行结果:

    ——setattr——key:name value:xuyuanyuan
    <class 'str'>
    <class 'str'>
    {'name': 'xuyuanyuan'}
    ——setattr——key:age value:18
    <class 'str'>
    <class 'str'>
    {'name': 'xuyuanyuan', 'age': '18'}
    ——delattr——item:age
    <class 'str'>
    {'name': 'xuyuanyuan'}
    ----> from getattr:你找的属性不存在

    总结:

    obj点的方式去操作属性时触发的方法

    __getattr__:obj.属性 不存在时触发
    __setattr__:obj.属性=属性的值 时触发
    __delattr__:del obj.属性 时触发

     

     四 、二次加工标准类型(包装)

    示例,如果是用继承的方法实现二次加工

    # #基于继承的原理,来定制自己的数据类型(继承标准类型)
    # 定制自己的append:只能向列表加入字符串类型的值
    class List(list):
        def append(self,p_obiect):
            if not isinstance(p_obiect,str):#判断加入的是否是字符串的,如果不是字符串的话,则会报错
                raise TypeError("must be str")#报错,提示必须是字符串
            else:
                super().append(p_obiect)#将加入的字符串加入到超父类list内
    
    l=List([1,2,3,4])
    l.append("hello")
    print(l)
    

    执行结果是:

    [1, 2, 3, 4, 'hello']
    

    授权:授权是包装的一个特性, 包装一个类型通常是对已存在的类型的一些定制,这种做法可以新建,修改或删除原有产品的功能。其它的则保持原样。授权的过程,即是所有更新的功能都是由新类的某部分来处理,但已存在的功能就授权给对象的默认属性。

    1、通过触发__getattr__方法

    示例:

    	# 定制显示列表中间那个值的属性
    class List:
        def __init__(self,list=[1,2,3,4]):
            self.list=list
        def append(self, p_obiect):
            if not isinstance(p_obiect, int):  # 判断加入的是否是字符串的,如果不是字符串的话,则会报错
                raise TypeError("must be int")  # 报错,提示必须是字符串
            else:
                self.list.append(p_obiect)  # 将加入的字符串加入到超父类list内
        @property#装饰器功能,search=property(search)相当于调用了property函数
        def search(self):
           print(self.list[len(self.list)//2],type(self.list[len(self.list)//2]))
        def __getattr__(self, item):#属性不存在时则会触发运行
            print("你找的属性不存在")
    
    l=List()
    print(l.list)
    l.append(5)
    print(l.list)
    # 没加@property的话,则需要c.search()调用
    # 加了@property装饰器的话,可直接当做属性调用c.search
    l.search#可直接当做属性调用
    # print(f.read())
    l.pop#当调用没有的属性时,则会触发__getattr__的运行
    

    执行结果是:

    [1, 2, 3, 4]
    [1, 2, 3, 4, 5]
    3 <class 'int'>
    你找的属性不存在
    

      

     

  • 相关阅读:
    由自身经历谈“不谋全局者,不足以谋一域”
    MySQL 常用SQL语句
    举例说明android中ListPreference的使用方法
    cookie机制和session机制的区别
    thinkphp浏览历史功能实现方法
    利用PHP获取访客IP、地区位置、浏览器及来源页面等信息
    PHP+Ajax点击加载更多内容 -这个效果好,速度快,只能点击更多加载,不能滚动自动加载...
    php用正则表达式匹配URL的简单方法(亲测可行)
    PHP实现记录浏览历史页面
    [译] 流言终结者 —— “SQL Server 是Sybase的产品而不是微软的”
  • 原文地址:https://www.cnblogs.com/xuyuanyuan123/p/6758018.html
Copyright © 2020-2023  润新知