zoukankan      html  css  js  c++  java
  • 面向对象高级(下)

    1 item方法

      想对比__getattr__(), __setattr__() 和 __deltattr__()这三个通过属性的方式的三个方法

      还有__getitem__(), __setitem__() 和 __delitem__()这三个函数, 是通过字典形式来处理属性

      字典形式使用中括号的方式获取值

      在实现__setitem__()的时候仍然需要使用__dict__来实现增值的设置

      具体的用法如下所示

    class People:
        def __init__(self,name):
            self.name=name
    
        def __getitem__(self, item):
            print("==>get")
            print(self.__dict__[item])
    
        def __setitem__(self, key, value):
            print("==>set")
            self.__dict__[key]=value
    
        def __delitem__(self, key):
            print("==>del")
            self.__dict__.pop(key)
    
    whc = People('whc')
    
    whc['age'] = 18
    whc['age']
    del whc['age']
    

    2 __str__

      __str__() 和 __repr__()两个方法是用于输出信息的方法  

      和__iter__()方法一样, 对象调用的时候可以直接用 str(对象) 或者 repr(对象) 来对应的调用__str__()和__repr__()

      当使用 str函数 或者是print的时候, 调用__str__()

      当使用 repr函数 或者直接在交互式环境的时候, 调用__repr__()

      如果没有__str__就会使用__repr__代替

      由于一般这俩效果相同, 因而一般先定义__str__, 然后写上__repr__ = __str__

      这俩的返回值必须是字符串

      和他俩相关的是__format__(), 当调用 format() 方法的时候会调用

      具体操作代码如下

    class Space:
        def __init__(self,name,addr,type):
            self.name=name
            self.addr=addr
            self.type=type
    
        def __repr__(self):
            return 'Space(%s,%s)' %(self.name,self.addr)
    
        def __str__(self):
            return '(%s,%s)' %(self.name,self.addr)
    
        def __format__(self, format_spec):
            return 'Space({},{},{})'.format(self.name, self.addr, self.type)
    
    space = Space('兴业家园', '北京', '公寓')
    print( repr(space) )
    print( str(space) )
    print( space )
    print(format(space))
    

    3 __slots__

      python中对对象可以任意绑定属性, 但是如果需要限制属性的绑定的时候就可以在类中定义一个__slots__

      它的值一般赋值成一个元组, 里面的写上可以绑定的属性的名字

      当绑定别的名字的时候就会报错

      __slots__的实现细节是将对象的__dict__取消了, 而分别对每个对象指定一个__slots__

      具体使用代码如下

    class People:
        __slots__=['name','age']
    
    whc = People()
    whc.name = 'whc'
    print(whc.__slots__)
    
    fizz = People()
    fizz.name = 'fizz'
    print(fizz.__slots__)
    

    4 __iter__

      可迭代对象是有方法__iter__()

      迭代器是有方法__next__()

      因而可以自己构建一个类, 使得它的对象, 既是一个可迭代对象, 也是一个迭代器  

      具体仿造range方法实现的代码如下

    class MyRange:
        def __init__(self, *args):
            if len(args) == 1:
                self.start = 0
                self.end = args[0]
            else:
                self.start = args[0]
                self.end = args[1]
            if len(args) == 3:
                self.len = args[2]
            else:
                self.len = 1
    
        def __iter__(self):
            return self
    
        def __next__(self):
            if self.start >= self.end:
                raise StopIteration
            n = self.start
            self.start += self.len
            return n
    
    for i in  MyRange(11):
        print(i)
    
    for i in  MyRange(2, 11):
        print(i)
    
    for i in  MyRange(2, 11, 3):
        print(i)
    

    5 __doc__

      在类中最开始定义的光秃秃的字符串是类的文档信息

      查看该文档信息可以使用__doc__来获取

      在函数中的第一个光秃秃的字符串也是, 通过函数名来调用__doc__即可获得

      另外__doc__无法被继承

      具体代码如下

    class Foo:
        '我是Foo的描述信息'
        def foo(self):
            '我是foo()的描述信息'
            pass
    
    print(Foo.__doc__)
    print(Foo().__doc__)
    
    print( Foo.foo.__doc__ )
    print(Foo().foo.__doc__ )
    

    6 __module__

      __module__和__class__是两个特殊属性

      可以通过对象点的方式获取

      __module__是获取对象所在模块的名字. __class__是获取对象所在的类

      具体代码如下

    import time
    print(time.time.__module__)
    print(time.time.__class__)
    # time
    # <class 'builtin_function_or_method'>
    

    7 __del__

      这是一个特殊地函数--析构函数

      调用内置方法del的时候可能会调用到类中__del__()方法

      是否执行析构函数的判定是, del后面的变量指引的内容的指引数是否大于0, 如果不大于0则就会调用

      在程序结束之后, 如果有没有清除的变量, 对应的__del__()也会执行

      具体实例如下

    class Foo:
        def __init__(self, name):
            self.name = name
    
        def __del__(self):
            print('{} 执行我啦'.format(self.name))
    
    f0 = Foo('f0')
    del f0 #执行__del__
    
    f1 = Foo('f1')
    f2 = f1
    del f1 #由于还有f2这个指向, 所以不执行__del__
    
    f3 = Foo('f3') #由于此处再新建了一个, 结束了之后这个也要__del__
    # f0 执行我啦
    # f1 执行我啦
    # f3 执行我啦
    

    8 __enter__

      在文件操作中, 有个with操作, 语句块结束后可以自动关闭文件  

      具体可以模拟文件操作来实现open()的功能

      with语句的流程如下

      with后的操作会生成一个对象, 此时后调用__init__()方法

      通过as需要返回给一个对象给as后的变量, 此时是执行__enter__()方法, 返回值给该变量

      在执行完毕with内部的代码块后, 会再执行__exit__()方法

      __exit__自带三个额外的参数, 分别是异常类型, 异常值, 异常的堆栈信息

      __exit__可以有返回值, 但是会判定成布尔值, 为Ture之后, with代码块出现异常的语句之后的语句不再执行, 但是with之后的语句会继续执行

       具体顺序的验证如下

    class Foo:
        def __enter__(self):
            pass
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("====>",exc_type, exc_val, exc_tb, "<=====")
            return True
    
    with Foo() as f:
        raise TypeError("出现错误")
        print("***************")
    
    print("==> ######## <==")
    # ====> <class 'TypeError'> 出现错误 <traceback object at 0x0000000000D4F1C8> <=====
    # ==> ######## <==
    

      完成自定义的open()操作的类的实现代码如下

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    
    __author__ = 'weihuchao'
    
    
    import time
    class LogFile:
        def __init__(self,filename,mode='r',encoding='utf-8'):
            self.file=open(filename,mode,encoding=encoding)
    
        def write(self,line):
            t=time.strftime('%Y-%m-%d %T')
            self.file.write('%s %s' %(t,line))
    
        def __enter__(self):
            return self
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.close()
    
        def __getattr__(self, item):
            return getattr(self.file,item)
    
    with LogFile('log', 'w+') as f:
        f.write("aaa")
        f.seek(0)
        print(f.read())
    

    9 __call__

      在类中还可以定义一个特殊函数__call__()来实现对象的可调用属性

      具体实现是

    class Foo:
        def __call__(self, *args, **kwargs):
            print('__call__')
            
    obj = Foo()
    obj()
    

    10 元类

      对象是由类产生的, 类是由type产生的, type继续由type产生

      type()手动创建类需要三个元素,

        一个是字符串类型, 表示类名

        一个是元组类型, 表示父类的集合

        一个是字典类型, 表示绑定的属性和方法

      具体实现如下

    def run(self):
        print("running..")
    
    PeopleClass = type("People",(object,), {"country":"China",'run':run})
    whc = PeopleClass()
    print(PeopleClass)
    print(whc)
    # <class '__main__.People'>
    # <__main__.People object at 0x0000000000B27CC0>
    

    10.1 利用元类新增功能

      可以写一个元类Mateclass, 它需要继承自type类

      原来的类需要关联该元类, 也就是在继承中有 metaclass=元类名字

      此时执行元类就可以生成一个对象, 也就是创建的这个类

      基于此, 就是元类中的__init__()方法创建的 类对象, 所以新加的功能只需在__init__()方法中就行

      元类的__init__()有额外三个参数, 分别是类名, 类基类, 类属性字典

      实现检查__doc__的代码如下

    class MyMetaclass(type):
        def __init__(self, class_name, class_bases, class_dic):
            for key, value in class_dic.items():
                if callable(value) and not value.__doc__:
                    raise Exception("{}方法内必须写入注释..".format(key))
    
    class Foo(metaclass=MyMetaclass):
        x = 1
        def __init__(self, name):
            self.name = name
        def run(self):
            'run function'
            print('running')
        def go(self):
            print('going')
    

    10.2 新建对象的过程

      首先, 类要生成对象, 类本身需要可调用

      针对于基类, 类是基类的对象, 也就是说在基类中, 需要有一个__call__()函数, 而这个函数, 是在类的__init__之前执行的

      在基类的__call__()方法中, 需要使用self.__new__(self)来创建一个空对象, 这个对象就是类

      有了类之后就可以调用原有的方法__init__(), 这时在其中就是熟悉的生成对象了

      最后再返回这个类就行了

      完成整个过程的代码如下

    class MyMetaclass(type):
        def __call__(self, *args, **kwargs):
            obj = self.__new__(self)
            self.__init__(obj, *args, **kwargs)  # obj.name='egon'
            return obj
    
    class People(metaclass=MyMetaclass):
        def __init__(self, name):
            self.name = name
    
    whc = People('whc')
    print(whc.name)
    

      

    人若有恒 无所不成
  • 相关阅读:
    Sharepoint2013商务智能学习笔记之Excel Service展示Sql Server数据Demo(五)
    Sharepoint2013商务智能学习笔记之Excel Service服务配置(四)
    Sharepoint2013商务智能学习笔记之部署AdventureWorksDW2012数据库(三)
    Sharepoint2013商务智能学习笔记之Secure Store Service服务配置(二)
    Sharepoint2013商务智能学习笔记之简单概述(一)
    SQL Server date 设置默认值
    C# 发Domino邮件 报错误 Password or other security violation for database 的解决方案
    Excel顺序生成序号,不能有数字4出现
    IBM Domino 9 出现 Domino Designer 您正在试图升级多用户安装。请获取正确的安装包以完成升级。 解决方案
    IBM Domino 9 出现 Server Controller 未在主机上运行或未在端口2050监听 解决方案
  • 原文地址:https://www.cnblogs.com/weihuchao/p/6762521.html
Copyright © 2011-2022 走看看