• Python基础:21包装


            “包装”在Python 编程中经常会被提到的一个术语。意思是对一个已存在的对象进行包装,可以是对一个已存在的对象,增加,删除,或者修改功能。

            可以包装任何类型(type)作为一个类(class)的核心成员,以使新对象的行为模仿你想要的数据类型中已存在的行为,并且去掉你不希望存在的行为。

     

            授权是包装的一个特性,实现授权的关键点就是覆盖__getattr__()方法,在其中包含一个对getattr()内建函数的调用。

            特殊方法__getattr__()的工作方式是,当搜索一个属性时,任何局部对象首先被找到(定制的对象)。如果搜索失败了,则__getattr__()会被调用。

            换言之,当引用一个属性时,Python 解释器将试着在局部名称空间中查找那个名字,如果没有在局部字典中找到,则搜索类名称空间,最后,如果两类搜索都失败了,搜索则对原对象开始授权请求,此时,__getattr__()会被调用。

     

            包装的一个简单例子:

    class  WrapMe(object):
            def  __init__(self, obj):
                    self.__data = obj
            def  get(self):
                    return  self.__data
            def  __repr__(self):
                    return  ‘self.__datadef  __str__(self):
                    return  str(self.__data)
            def  __getattr__(self, attr):
                    return  getattr(self.__data, attr)

            这里将用到复数,因为所有Python数值类型,只有复数拥有属性:

    >>> wrapcomplex =WrapMe(3.5+4.2j)
    >>> wrapcomplex                   
    (3.5+4.2j)
    
    >>> wrapcomplex.real
    3.5
    
    >>> wrapcomplex.imag
    4.2
    
    >>>wrapcomplex.conjugate()
    (3.5-4.2j)
    
    >>> wrapcomplex.get()
    (3.5+4.2j)

            访问复数的三种属性,我们的自定义类中一种都没有定义,对这些属性的访问,是通过getattr()方法,授权给对象。调用get()方法没有授权,因为它是为我们的对象定义的。

             下一个使用包装类的例子用到一个列表。我们将会创建对象,然后执行多种操作,每次授权给列表方法。

    >>> wraplist =WrapMe([123, 'foo', 45.67])
    >>>wraplist.append('bar')
    >>>wraplist.append(123)
    
    >>> wraplist
    [123, 'foo', 45.67, 'bar',123]
    
    >>>wraplist.index(45.67)
    2
    
    >>>wraplist.count(123)
    2
    
    >>> wraplist.pop()
    123
    
    >>> wraplist
    [123, 'foo', 45.67, 'bar']

            注意,只有已存在的属性是在此代码中授权的。特殊行为没有在类型的方法列表中,不能被访问,因为它们不是属性。一个例子是,对列表的切片操作,它是内建于类型中的,而不是像append()方法那样作为属性存在的。也就是说,切片操作符是序列类型的一部分,并不是通过__getitem__()特殊方法来实现的。

    >>> wraplist[2]
    Traceback (most recent calllast):
      File "<stdin>", line 1, in<module>
    TypeError: 'WrapMe' objectdoes not support indexing

            然而,还有一种"作弊"的方法,访问实际对象[通过get()方法]和它的切片能力.

    >>> reallist =wraplist.get()
    >>> reallist[3]
    'bar'

            这就是为什么需要实现get()方法了----仅仅是为了我们需要取得对原对象进行访问这种情况。

     

            另外一个例子,描述了一个包装文件对象的类。我们的类与一般的文件对象行为完全一样, 除了在写模式中,字符串只有全部为大写时,才写入文件。下面提供一个文件类对象,定制write()方法,同时,给文件对象授权其它的功能:

    class  CapOpen(object):
           def  __init__(self, fn,mode='r', buf=-1):
                  self.file = open(fn, mode, buf)
    
           def  __str__(self):
                  return  str(self.file)
    
           def  __repr__(self):
                  return  `self.file`
    
           def  write(self,  line):
                  self.file.write(line.upper())
    
           def  __getattr__(self, attr):
                  return getattr(self.file, attr)
    
    
    >>> f = CapOpen('/tmp/xxx','w')
    >>>f.write('delegation  example
    ')
    >>>f.write('faye  is  good
    ')
    >>>f.write('at  delegating
    ')
    >>> f.close()
    >>> f
    <closed file '/tmp/xxx',mode 'w' at 12c230>

            可以看到,唯一不同的是第一次对CapOpen()的调用,而不是open()。除了write(),所有属性都已授权给文件对象:

    >>> f =CapOpen('/tmp/xxx', 'r')
    >>> for  eachLine  in  f:
    ...          print eachLine,
    ...
    
    DELEGATION  EXAMPLE
    FAYE  IS  GOOD
    AT  DELEGATING

     

  • 相关阅读:
    最长公共子序列(LCS)
    数组分割问题
    Trie树
    BitMap(比特位)
    KMP算法——字符串匹配
    排序算法
    概率问题
    【设计模式】——访问者模式
    【设计模式】——解释器模式
    【设计模式】——享元模式
  • 原文地址:https://www.cnblogs.com/gqtcgq/p/7247189.html
Copyright © 2020-2023  润新知