• 7.29 多态和类的内置方法


    一。多态

      在现实生活中,多态也会体现。如对于水这种物质,有固态:冰,液态:常态,气态:水蒸气,

      在程序中,其官方定义是:多个不同对象可以相应同一方法,产生不同的结果。

      而在python中,多态不是一个特殊的语法,而是一种关系,一种特性,举例:

    class A:
        def work(self):
            print('I am working in A')
    
        def name(self):
            print('i am A')
    
    class B:
        def work(self):
            print('I am working in B')
    
        def name(self):
            print('i am B')
    
    class C:
        def work(self):
            print('I am working in C')
    
        def name(self):
            print('i am C')
    
    a=A()
    b=B()
    c=C()
    def toge(obj):
        obj.work()
    
    toge(a)
    toge(b)
    toge(c)
    #I am working in A
    #I am working in B
    #I am working in C

      上述代码中分别制造了ABC三个类,这三个类都有不同 的特征,也有相同的特征work,可以通过多态,统一管理其中的work使之工作而保留其他的特性。

      这种方法在接口中有所体现是,所以除了上述的鸭子类型以外也可以使用接口和抽象类来使用多态。

      如果不是这种特性,需要分别对ab三个对象编写其对应的方法。

    二。相关内置对象

      1.isinstance

      作用:判断某个对象是否是某个类的实例:isinstance(对象,类)

      这种方法也可以判断某个数据是否是某个类型isinstance(数据,类型)

    class Person:
        def work(self):
            print('i am working ')
    
    class book:
        def write(self):
            print('i can write')
    
    def working(oop):
        if isinstance(oop,Person):
            oop.work()
        else:
            print('you are not Person')
    
    ab=Person()
    ac=book()
    working(ab)
    working(ac)
    #i am working 
    #you are not Person

      当一个对象不具有某个特点时,可以使用isinstance来判断是否可以执行该函数,使程序不会报错,因为可以不执行不存在的方法。

      除此之外,isinstance还可以判断某个数据是不是某个数据类型:

    def add(a,b):
        if isinstance(a,int) and isinstance(b,int):
            return a+b
        else:
            return '不是整型'
    
    print(add(2,44))
    print(add('asd',2))
    #46
    #不是整型

      2.issubclass(子类,父类)

      作用,判断一个子类是不是某个父类的子类。

    class Father:
        def name(self):
            print('i am father')
    
    class Son(Father):
        def name(self):
            print('i am son')
    
    class Wang:
        def name(self):
            print('i am wang ')
    
    def test1(oop):
        if issubclass(type(oop),Father):
            oop.name()
        else:
            print('you are not my son')
    
    s1=Son()
    w1=Wang()
    test1(s1)
    test1(w1)
    #i am son
    #you are not my son

    三。魔法函数

      这类方法一般都放在类中使用。

      1.__str__

      该方法是在对象被转化为字符串时触发,而对象本来是一种对象形式:

    <__main__.Person object at 0x00000288BDA380B8>

      而这种方法显然是没有什么意义的,但是对于print的原理就是先将任何数据转化成字符串形式打印出来,所以,如果定义了该方法之后就可以直接打印该对象。

      在__str__方法中可以传入对象参数,规定打印格式,如:

    class Person:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def __str__(self):
            return '名字是%s,年龄是%s'%(self.name,self.age)
    
    p1=Person('lzx',18)
    print(p1)
    #名字是lzx,年龄是18

      2.__del__

      该方法是在对象被删除时,执行该方法:

    class Person2:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def __del__(self):
            print('i am del')
    
    a=Person2('lzx',123)
    del a
    print('over')
    #i am del
    #over

      当执行del a与据说是,会打印iam del

      但是如果不执行del a 语句,程序会自动结束,垃圾回收机制会自动将不用的对象进行回收删除,所以即使不写这句话,在最后也会执行语句。

      简易文件处理:

    class File1:
        def __init__(self,file):
            self.file=open(file,'r',encoding='utf-8')
    
        def read(self):
            return self.file.read()
    
        def __del__(self):
            self.file.close()
            print('over')
    
    ab=File1('test.py')
    print(ab.read())

      在对象结束时自动关闭对文件的操作。

      3.__call__

      当对象被调用时,执行该函数,调用就是对象名+()

    class Test2:
        def __call__(self, *args, **kwargs):
            print('666')
    
    ba=Test2()
    ba()
    #666

      4.__slots__

      该属性是一个类属性,在类中使用,用于内存优化,当一个类定义了__slots__后,会使得类中的名称空间不被创建,类中只能创建slots中所用有的名称属性,不能多也不能少,这样就能减少内存开销的效果。

      __slots__=['','']

    class Person:
    
        __slots__ = ["name"]
        def __init__(self,name):
            self.name = name
    
    p =  Person("jck")
    
    # 查看内存占用
    # print(sys.getsizeof(p))
    # p.age = 20 # 无法添加
    
    # dict 没有了
    print(p.__dict__)

      注意,这时候的Person中的__dict__已经不存在了。

      5.getattr setattr delattr

      getattr 用点访问属性的时如果属性不存在时执行

      setattr 用点设置属性时

      delattr 用del 对象.属性 删除属性时 执行

    class Test3:
        def __getattr__(self, item):
            print('__getattr__')
            return 1
    
        def __setattr__(self, key, value):
            print('__setattr__')
            self.__dict__[key]=value
    
        def __delattr__(self, item):
            print('__delattr__')
            self.__dict__.pop(item)
    
    abc=Test3()
    print(abc.name)
    abc.name='123'
    print(abc.name)
    del abc.name
    print(abc.name)
    #__getattr__
    #1
    #__setattr__
    #123
    #__delattr__
    #__getattr__
    #1

      首先,除了使用super继承父类的方法运行程序实现功能之外,对于setattr的基本原理就是将键值添加至名称空间的字典__dict__里,在设置属性时调用。而删除也是将名称空间字典中的键值弹出,顺便执行该函数语句。

      而getattr,当可以通过点获取该值时,就返回该值,当没有找到该值时就返回return中的值

      getattribute

      当类中有getattribute方法时,获取值前会优先执行该函数,如果获取到了属性,就会返回其值,如果没有找到,就会调用getattr方法。

    class Test3:
        def __getattr__(self, item):
            print('__getattr__')
            return 1
    
        def __getattribute__(self, item):
            print('__getattribute__')
            return super().__getattribute__(item)
    
    
    abc1=Test3()
    # abc1.name=123
    print(abc1.name)
    #__getattribute__
    #__getattr__
    #1

      6.getitem,setitem,delitem

      当类中有上述发方法,使用[]获取其值时,会触发该函数。

    class Test4:
        def __getitem__(self, item):
            print('__getitem__')
            return self.__dict__[item]
    
        def __setitem__(self, key, value):
            print('__setitem__')
            self.__dict__[key]=value
    
        def __delitem__(self, key):
            print('__delitem__')
            del self.__dict__[key]
    
    abc4=Test4()
    abc4['name']=22
    print(abc4['name'])
    del abc4['name']
    print(abc4['name'])
    #__setitem__
    #__getitem__
    #22
    #__delitem__

      了解即可。

      例:让一个对象既支持点取值,又支持[]取值:

    class MyDict(dict):
    
         def __getattr__(self, key):
             return self.get(key)
        
         def __setattr__(self, key, value):
             self[key] = value
        
         def __delattr__(self, item):
             del self[item]

      在该类中,首先继承了dict类的方法,使得对象可以用于字典的属性,再对其点操作进行返回值。

      7.运算符重载(__gt__,__lt__,__eq__)

      gt是在对象之间进行比较大时,运行该函数

      lt是在对象之间进行比较小时,运行该函数

      eq是在对象之间进行比较等于时,运行该函数

      本来对象之间是不支持运算符比较 的(等于可以比较)

    class Test6:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
    a=Test6('lzx',6)
    b=Test6('zzp',3)
    print(a>b)
    #报错

      进行等于比较时也是比较两个对象是否相同。

      而使用gt或者lt就可以实现对象之间的属性值的比较:

    class Test6:
        def __init__(self,name,age):
            self.name=name
            self.age=age
    
        def __gt__(self, other):
            if self.age>other.age:
                return True
            return False
    
        def __lt__(self, other):
            if self.age<other.age:
                return False
            return True
    
        def __eq__(self, other):
            if self.age==other.age:
                return 123
            return 321
    
    a=Test6('lzx',6)
    b=Test6('zzp',3)
    print(a<b)
    print(a==b)
    #True
    #321

      当然,在gt和lt之间只需要使用一个就够了。符号如果不同 解释器会自动交换两个对象的位置。

    四。迭代器

      要使一个类或对象,成为一个迭代器,需要在其定义两个方法:__item__和__next__。

    class Dd:
        def __init__(self,max):
            self.max=max
            self.count=0
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.count<self.max:
                self.count+=1
                return self.count
            else:
                raise StopIteration
    
    for i in Dd(10):
        print(i)

      Dd就使一个迭代器,Dd的作用就是输入1-10的数,当调用该类时,执行next中的语句,使用StopItIreration进行异常抛出,停止程序,防止死循环的出现。

      利用这个可以模仿range函数:

    class Myrange:
        def __init__(self,min1,max1,step=1):
            self.min1=min1-1
            self.max1=max1-1
            self.step=step
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.min1<self.max1:
                self.min1+=self.step
                return self.min1
            else:
                raise StopIteration
    
    for i in Myrange(0,10,2):
        print(i)

      如上,range满足左开右闭原则,而步长step默认为1,即使不传也没关系,不同点在于必须要传入起始数字。

      所以,可以把具有__iter__,__next__两个方法的类看作一个迭代器。

    五。上下文操作

      上下文操作其实早有应用,像文件的打开与写入就是上下文操作,在使用with操作文件时会获取一个文件句柄,对句柄进行操作,即使后来忘记关闭对文件的链接,最后程序也会自动帮你关闭,其原理 就是在open类中的exit函数帮你关闭文件。

      当执行with语句时,会先执行enter语句,如果运行正常,则运行exit语句,当enter运行过程中出现异常,则会立即运行exit语句,并传入异常信息。

    class Text7:
        def __init__(self,file):
            self.file=file
    
        def __enter__(self):
            print('enter===')
            self.f=open(self.file)
            return self.f
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print('exit===')
            print(exc_type, exc_val, exc_tb)
            self.f.close()
    
    with Text7('test.py') as m:
        print(m.read())

      Text7就是一个低配的open操作,其中:

      enter将文件句柄作为返回值给类。

      在exit中exc_type, exc_val, exc_tb,三个参数就是返回其异常信息(包含错误的类型.错误的信息.错误的追踪信息)。

      小知识:exit也有返回值,返回的是一个布尔值(True,False),当程序正常运行结束时,没有太大影响,

          当程序出现异常时,如果返回值是true时,异常会被处理,如果返回的时False。异常会被保留。

  • 相关阅读:
    mysql中表名是order的CRUD的错误
    BAT-增加JAVA环境变量(WIN764位)
    D7 D2007 XE10.1 都支持的字符分隔函数
    问题-百度云同步盘登陆时提示155010错误
    BAT-批量改文件后缀名
    delphi判断线程是否正在运行
    JAVA-JSP动作元素之param
    JAVA-JSP动作元素之forward
    JAVA-JSP动作元素之include
    JAVA-JSP之taglib指令
  • 原文地址:https://www.cnblogs.com/LZXlzmmddtm/p/11266139.html
Copyright © 2020-2023  润新知