美文网首页
【学习记录】Python3版本(7:面向对象高级编程)(meta

【学习记录】Python3版本(7:面向对象高级编程)(meta

作者: 天有三光 | 来源:发表于2020-03-01 18:38 被阅读0次

    动态过程为类或者实例绑上一个方法

    ​>>> def set_age(std,age):
    
    std.age=age
    
    #idle界面中敲出函数
    
    >>> Student.set_age=MethodType(set_age,Student)
    
    Traceback (most recent call last):File "<pyshell#41>", line 1, in <module>Student.set_age=MethodType(set_age,Student)
    
    NameError: name 'MethodType' is not defined
    
    #直接使用MethodType语句,发现不对
    
    >>> from types import MethodType
    
    >>> Student.set_age=MethodType(set_age,Student)
    
    >>> bart=Student('bart',61,'male')
    
    >>> bart.set_age(99)
    
    >>> bart.age
    
    99
    
    #大功告成
    
    image
    Student.set_score = set_score并不是给类绑定了方法只是调用,而Student.set_score=MethodType(set_score,Student)才是给类绑定方法
    1
    Student.set_score=set_scor
    print(Student.set_score,set_score)
    

    2

    Student.set_score=MethodType(set_score,Student)
    print(Student.set_score,set_score)
    分别运行上面两段代码就能体会到区别
    

    限制类里的属性__slots__

    class Animals(object):
    
        __slots__=('name','age')
    
    class Cat(Animals):
    
        pass
    
    ====
    
    >>> Dogs=Animals()
    
    >>> Dogs.name='doge'
    
    >>> Dogs.age=7
    
    >>> Dogs.number='A'
    
    Traceback (most recent call last):File "<pyshell#52>", line 1, in <module>Dogs.number='A'
    
    AttributeError: 'Animals' object has no attribute 'number'
    
    #使用__slots__之后,Animal类的Dogs无法传入number属性
    
    >>> Cats=Cat()
    
    >>> Cats.number='A'
    
    >>> Cats.number
    
    'A'
    
    #Animal的子类Cat却可以传入number属性
    

    @property

    为了解决调用函数代码复杂,直接暴露参数无法检查参数输入的矛盾,该语句应运而生。

    class Student(object):
        
        def __init__(self,name,score,gender):
            self.__name=name
            self.__score=score
            self.__gender=gender
    
        @property
        #相当于调用时,使用变量名.函数名。即s.gender=,且表示该函数是只读的,不会修改
        def gender(self):
            return self.__gender
    
        @gender.setter
        #表示这是修改gender变量的函数
        def set_gender(std, gender):
            if gender=='male':
                std.__gender=gender
            elif gender=='female':
                std.__gender=gender
            else:
                print('Type error')
    
    

    在idle界面中

    >>> bart=Student('bart',60,'male')
    >>> bart.gender
    'male'
    >>> bart.set_gender='female'
    >>> bart.gender
    'female'
    

    廖老师布置的作业:

    # -*- coding: utf-8 -*-
    class Screen(object):
    
        def __init__(self,width=0,height=0):
            self.__width=width
            self.__height=height
    
        @property
        def width(self):
            return self.__width
    
        @property
        def height(self):
            return self.__height
    
        @property
        def resolution(self):
            return self.__width*self.__height
    
        @width.setter
        def width(self,value):
            if value>0:
                self.__width=value
            else:
                print('Type Error')
    
        @height.setter
        def height(self,value):
            if value>0:
                self.__height=value
            else:
                print('Type Error')
    
    

    多重继承

    人类面临分类的时候经常会发现的问题:它既是一种分类方法的A类,又是另一种分类方法的B类。
    此时,为了使得类可以完成它的使命,我们需要让他能够继承到他需要的属性,这就涉及了多重继承的问题。

    class Animals(object):
    
        __slots__=('name','age')
    
    class Flyable(object):
        pass
    
    class Bat(Animals,Flyable):
        pass
    

    相当于tag标签一样的分类。

    MixIn

    摸不太着头脑,是说上面的那个Bat类还可以写成

    class Bat(Animal,FlyableMixIn):
        pass
    

    吗?


    定制类

    __xxx__类有特殊用途
    注意,这些都是要自己写函数的,而不是可以直接在idle窗口调用的。它们写好后,可以让类的访问变得像是一个list型(或者其他类型)。

    1 __str____repr__

    >>> a=Screen()
    >>> a
    <__main__.Screen object at 0x000001FA828B48D0>
    

    此处返回的就是调用__repr__()的,返回的是开发者看到的字符串,是为调试服务的。
    可以这么写:

    class Student(object):
        
        def __init__(self,name,score,gender):
            self.__name=name
            self.__score=score
            self.__gender=gender
        def __str__(self):
            return 'Student object (name=%s)' % self.__name
        __repr__=__str__
    

    idle界面:

    >>> bart=Student('bart',60,'male')
    >>> bart
    Student object (name=bart)
    

    2 __iter__返回迭代

    使用此语句返回一个迭代对象,使得在idle界面可以使用for循环访问。

    3 __getitem__返回一个可用下标访问的迭代对象

    比如之前__iter__返回的可迭代对象,用__getitem__可以在idle界面使用下标如数列一样的访问。
    但是要注意的是,在编写此函数时,要同时包含切片对象的处理方式。
    同类还有,__setitem____delitem__等等

    4 __getattr__

    当用户访问一个不存在的属性时,python会调用__getattr__函数。
    因此,可以写:

        #当访问一个不存在的属性时
        def __getattr__(self,attr):
            if attr=='age':
                return 'unknown'
            raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)
    

    idle中:

    >>> bart=Student('bart',60,'male')
    >>> bart.age
    'unknown'
    >>> bart.number
    Traceback (most recent call last):
      File "<pyshell#32>", line 1, in <module>
        bart.number
      File "D:\ZQC\2020寒假学习计划\python\Sy_13_WhereisDuiXiang.py", line 17, in __getattr__
        raise AttributeError('\'Student\' object has no attribute\'%s\''%attr)
    AttributeError: 'Student' object has no attribute'number'
    #这个到底对不对啊,我好懵啊orz
    

    5 __call__

    可以将类的实例对象当成函数一样:

        #类的实例当函数调用
        def __call__(self):
            print('I\'m class \'Student\'.')
    

    idle中:

    >>> bart=Student('bart',60,'male')
    >>> bart()
    I'm class 'Student'.
    

    通过callable可以判断一个对象是否可以调用。


    使用枚举类

    枚举类是一种定义常数的方法。
    一般常量都是用全大写表示,如:PI=3.1415。当然,这种定义方式太简单了,而且它本身是int型的变量。因此,就引出了,枚举类。

    >>> from enum import Enum
    >>> Week=Enum('week',('Mon','Tue','Wed','Thu','Fri','Sat','Sun'))
    >>> for name,member in Week.__members__.items():
        print(name,'-->',member.value)#列举所有枚举量
    
    Mon --> 1
    Tue --> 2
    Wed --> 3
    Thu --> 4
    Fri --> 5
    Sat --> 6
    Sun --> 7
    

    另外,还可以从Enum派生出自定义类:

    >>> from enum import Enum
    >>> class Weekday(Enum):
        Sun=0
        Mon=1
        Tue=2
        Wed=3
        Thu=4
        Fri=5
        Sat=6
    
    >>> day1=Weekday.Mon
    >>> print(day1,Weekday.Tue,Weekday.Tue.value,day1==Weekday.Wed,Weekday(4))
    Weekday.Mon Weekday.Tue 2 False Weekday.Thu
    

    这里的访问两种方式都可以用。
    成员值允许相同,第二个成员的名称被视作第一个成员的别名


    使用元类

    1 type()

    >>> print(type(Weekday))#type()可以查看类型
    <class 'enum.EnumMeta'>
    >>> def fn(self,name='world'):#先定义函数
        print('hello,%s'%name)
    
    >>> Hello=type('Hello',(object,),dict(hello=fn))
    #依次传入三个参数:class名,tuple表示的继承父类,class方法名绑定函数
    >>> h=Hello()
    >>> h.hello()
    hello,world
    >>> h.hello('Bob')
    hello,Bob
    

    2 metaclass

    个人觉得,这玩意吧,会降低的代码可读性,因此放弃加载本节。

    相关文章

      网友评论

          本文标题:【学习记录】Python3版本(7:面向对象高级编程)(meta

          本文链接:https://www.haomeiwen.com/subject/hnnkhhtx.html