面向对象高级编程

1.使用__slots__:主要是节省内存,其次可以限制定义
    我们可以给一个实例绑定一个属性:
    直接写:实例名.属性名 = 数据 ,给实例绑定的属性只能在该实例中使用
    我们也可以给实例添加一个方法:
    例:
    >>> class Student():
            """定义一个学生的类"""
            def __init__(self,name,age):
                self.name = name
                self.age = age

                
        >>> from types import MethodType # 导入模块
        >>> s = Student('Bob',18)
        >>> s.name
        'Bob'
        >>> s.age
        18
        >>> # 定义一个函数作为实例方法
        >>> def score_show(self,score):
                self.score = str(score)
                print('%s' % self.score)

            
        >>> s.score_show = MethodType(score_show,s)
        >>> s.score_show(98)
        98
        但要注意的是给实例绑定的方法,只能用在该实例中
        要想在所有实例中都能使用,需要绑定在类上
        Student.score_show = MethodType(score_show,Student)
        如果我们要限制绑定的实例,只允许绑定特定的实例可以使用__slots__:
        >>> # 限制绑定的属性
        >>> class Std():
            """定义一个学生的类"""
            __slots__ = ('name','age')
            def __init__(self,name,age):
                self.name = name
                self.age = age

                
        >>> s = Std('bob',19)
        >>> s.score = 98 # 当想要绑定我们定义之外的属性时就会报错
        Traceback (most recent call last):
          File "<pyshell#29>", line 1, in <module>
            s.score = 98
        AttributeError: 'Std' object has no attribute 'score'
        >>> class Std1():
            def __init__(self,name,age):
                self.name = name
                self.age = age
            
        >>> st2 = Std1('Bob',19)
        NameError: name 'std2' is not defined
        >>> st2.score = 98
        >>> st2.score
        98
        但需要注意,定义的限制属性只在当前类中起作用,在继承它的子类中不起作用
        除非在子类中也定义了__slots__,那么子类将包含父类中的限制和本身定义的


3.__module__:查看这个类来自哪个模块
    from m1 import t
    c = t.C()
    print(c.__module__)  #m1.t
4.__del__:析构方法,高级语言不需要考虑内存的使用与释放,当内存被释放时,会触发该方法
5.__del__:内存被释放时会触发
    class User:
        def __init__(self,name):
            self.name = name
        def __del__(self):
            print("我执行啦")

    s1 = User("alxe")
    # del s1.name             # --------->
    # print("--------->")     #我执行啦

    del s1                    #我执行啦        # 只有删除实例时才会触发,
                                               # 上面也触发是因为程序结束了,内存也被回收了
    print("------------->")  #------------->
6.数据描述符:本质上是一个类,用来在其他类的类属性中调用,来描述类属性,之后类属性的操作都有这个描述符来管理
    注意事项:
        1.描述符本身应定义成新式类,被代理的类也应该是新式类
        2.必须把描述符定义成这个类的类属性,不能定义到构造函数中
        3.必须严格遵循优先级
            # 描述符的优先级
            """
            类属性>数据描述符(至少有__get__和__set__)>实例属性>非数据描述符(只有__get__方法)>__getattr__
            """
        class Foo:
            """这就是定义了一个描述符"""
            def __get__(self, instance, owner):
                print("====>__get__")
            def __set__(self, instance, value):
                print("====>__set__")
            def __delete__(self, instance):
                print("====>__delete__")

        class Date:
            x = Foo()      # 描述符必须定义在另一个类里面,被描述的属性调用、设置、删除都只会触发描述符中的定义的方法

        b = Date()
        b.x             # ====>__get__
        b.x = 1         # ====>__set__
        del b.x         #====>__delete__

7.__enter__和__exit__:上下文管理协议
    with open("文件名") as f:
        "代码块"
    这个操作会将文件加载到内存,并自动回收,就是用上下文管理协议实现的
        举例:
            class Open:
                def __init__(self,name):
                    self.name = name
                def __enter__(self):
                    print("====>enter")
                def __exit__(self, exc_type, exc_val, exc_tb):
                    print("====>exit")
                    print(exc_type)   #<class 'NameError'>
                    print(exc_val)    #name 'skdvuhsod' is not defined
                    print(exc_tb)     #<traceback object at 0x00000273E0BAED48>
                    return True

            # with Open("a.txt") as f:
            #     print("........")
            """
            ====>enter
            ........
            ====>exit
            """

            # 当文件操作中出现异常
            with Open("a.txt") as f:
                print("------------")
                print(skdvuhsod)
                """
                一个异常就由这三部分组成,异常类、异常值和追踪信息
                <class 'NameError'>
                name 'skdvuhsod' is not defined
                <traceback object at 0x00000273E0BAED48>
                """
                print("-----------")   # 当出现异常后,会直接触发__exit__,之后的语句都不会执行
                print("34134141")
            print("aadsdas")           # 文件操作代码块出现异常时,当__exit__返回True时,异常会被吞掉,程序会继续执行,
            """
            ====>enter
            ------------
            ====>exit
            <class 'NameError'>
            name 'skdvuhsod' is not defined
            <traceback object at 0x000002311AA6ED48>
            aadsdas        # __exit__返回True,回收文件,程序继续执行
            """
8.元类:既然类是一个对象,那么就也有产生类的类,就是元类(type)

        # metaclass:元类就是类的类
        # class Foo:
        #     pass
        # s = Foo()
        # print(type(s))    #<class '__main__.Foo'>
        # print(type(Foo))  #<class 'type'>   type就是元类,我们定义的类都是由它生成的
        # 那么我们就可以用type生成一个类
        # def __init__(self,name,age):
        #     self.name = name
        #     self.age = age
        # Foo = type("Foo",(object,),{"__init__":__init__}) # 三个参数,类名、继承的类,属性
        # f1 = Foo('alxe',10)
        # print(f1.__dict__)   #{'name': 'alxe', 'age': 10}

        # 下面我们来自定制一个元类
        class Mytype(type):
             def __init__(self,a,b,c):
                 pass
                #self:【<class '__main__.Foo'>】a:【Foo】,b:【()】c:【{'__module__': '__main__', '__qualname__': 'Foo', '__init__': <function Foo.__init__ at 0x000002C42459DBF8>}】
             def __call__(self, *args, **kwargs):
                 #print(args,kwargs)   #('alxe',) {}
                 obj = object.__new__(self)   # self就是Foo,这里使用Foo创建一个对象
                 self.__init__(obj,*args,**kwargs)  # 调用Foo的__init__,为生成的对象添加数据属性
                 return obj

        class Foo(metaclass=Mytype):    #"metclass=":声明元类
            def __init__(self,name):
                self.name = name

        f = Foo('alxe') #执行类名()就会触发元类的__call__
        f1 = Foo("python")
        print(f.name)
        print(f.__dict__)
        print("=============")
        print(f1.name)
        print(f1.__dict__)

 

posted @ 2020-06-13 17:47  pywhy  阅读(102)  评论(0编辑  收藏  举报