python cookbook第三版学习笔记十七:委托属性

我们想在访问实例的属性时能够将其委托到一个内部持有的对象上,这经常用到代理机制上

class A:
    def spam(self,x):
        print("class_A:"+str(x))
    def foo(self):
        pass

class B:
    def __init__(self):
        self._a=A()
    def bar(self):
        pass
    def __getattr__(self, item):
        return getattr(self._a,item)

b=B()

b.bar()

b.spam(42)

运行结果:

class_A:42

在这里,当调用b.spam的时候,由于查找不到这个属性,因此调用__getattr__来查找所有的属性。在上面的代码中,在访问B中未定义的方法时就把这个操作委托给A。

对这种方法进行扩展一下,我们可以实现带有状态的对象或状态机。代码如下:

class connection():

    def __init__(self):

        self.new_state(ClosedConnection)

    def new_state(self,newstate):

        self.__class__=newstate

    def read(self):

        raise NotImplementedError()

    def write(self):

        raise NotImplementedError()

    def open(self):

        raise NotImplementedError

    def close(self):

        raise NotImplementedError

class ClosedConnection(connection):

    def read(self):

        raise RuntimeError('not open')

    def write(self,data):

        raise RuntimeError('not open')

    def open(self):

        self.new_state(OpenConnection)

    def close(self):

        raise RuntimeError('Already closed')

class OpenConnection(connection):

    def read(self):

        print('reading')

    def write(self,data):

        print('writing')

    def open(self):

        raise RuntimeError('Already open')

    def close(self):

        self.new_state(ClosedConnection)

c=connection()

print(c)

c.read()

执行结果如下,初始状态为ClosedConnection, 调用read的时候提示not open

<__main__.ClosedConnection object at 0x00000250CD984DD8>

Traceback (most recent call last):

  File "D:/py_prj/test2/cookbook.py", line 152, in <module>

    c.read()

  File "D:/py_prj/test2/cookbook.py", line 130, in read

    raise RuntimeError('not open')

RuntimeError: not open

c=connection()

print(c)

c.open()

print(c)

c.read()

c.write('abc')

c.close()

print(c)

调用c.open后状态转移到OpenConnection。此时调用read和write方法则可以正常调用。调用close方法后状态转移到ClosedConnection

<__main__.ClosedConnection object at 0x000001C495E94DA0>

<__main__.OpenConnection object at 0x000001C495E94DA0>

reading

writing

<__main__.ClosedConnection object at 0x000001C495E94DA0>

通过这种方法减少了在代码分支中大量使用ifelse的调用。

原文地址:https://www.cnblogs.com/zhanghongfeng/p/9501473.html