python设计模式总结

学习资料:
https://github.com/cundi/Mastering.Python.Design.Patterns

  • 深入描述符

1、深入描述符

以下函数实现了两个功能,一是懒初始化,类的属性不是创建实例时产生,而是当使用时创建。二是实现了一次初始化。

class LazyProperty:
    def __init__(self, method):
        self.method = method
        self.method_name = method.__name__
        # print('function overriden: {}'.format(self.fget))
        # print("function's name: {}".format(self.func_name))

    def __get__(self, obj, cls):
        if not obj:
            return None

        value = self.method(obj)
        # print('value {}'.format(value))
        setattr(obj, self.method_name, value)
        return value

class Test:
    def __init__(self):
        self.x = 'foo'
        self.y = 'bar'
        self._resource = None

    @LazyProperty
    def resource(self):
        print('initializing self._resource which is: {}'.format(self._resource))

        self._resource = tuple(range(5))  # 假设这一行的计算成本比较大
        return self._resource

def main():
    t = Test()
    print(t.x)
    print(t.y)

    print(t.resource)
    print(t.resource)
main()

主要分析下上面的程序所完成的功能。
resource函数被LazyProperty修饰,即可以写成
resource = LazyProperty(resource)
类LazyProperty中定义了__get__方法,说明该类实际上就是一个描述符。描述符用来修饰另一个类中的属性,在知识点总结二中有介绍。当Test类访问resource时,涉及到访问优先顺序问题,详细可以参考python描述器的理解,总结来说就是若实现了资料描述符(同时定义了__get__和__set__),同名属性优先使用资料描述符,若非资料描述符,优先使用该类字典中的属性。
所以上面实现主要思想是:首先使用描述符定义一个属性(resource),该属性不会再初始化中创建,可以通过print t.__dic__查看。然后,调用t.resource由于是非资料描述符,因此查看类本身有没有同名属性,第一次调用时没有,因此直接调用__get__方法。注意该方法执行了语句setattr(obj, self.method_name, value),即在obj的类中创建了self.method_name(初始化后为resource)。而obj是调用该描述符的对象(t),因此后面出现了同名属性,实现了只初始化一次。

2、责任链模式

#! /usr/bin/env python
#--*--coding:utf8--*--


class Event:
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return self.name


class Widget:
    def __init__(self, parent=None):
        self.parent = parent

    def handle(self, event):
        handler = 'handle_{}'.format(event)
        if hasattr(self, handler):
            method = getattr(self, handler)
            method(event)
        elif self.parent:
            self.parent.handle(event)
        elif hasattr(self, 'handle_default'):
            self.handle_default(event)


class MainWindow(Widget):

    def handle_close(self, event):
        print('MainWindow: {}'.format(event))

    def handle_default(self, event):
        print('MainWindow Default: {}'.format(event))


class SendDialog(Widget):
    def handle_paint(self, event):

        print('SendDialog: {}'.format(event))


class MsgText(Widget):
    def handle_down(self, event):

        print('MsgText: {}'.format(event))


def main():
    mw = MainWindow()

    sd = SendDialog(mw)
    msg = MsgText(sd)
    for e in ('down', 'paint', 'unhandled', 'close'):
        evt = Event(e)
        print('\nSending event -{}- to MainWindow'.format(evt))
        mw.handle(evt)
        print('Sending event -{}- to SendDialog'.format(evt))
        sd.handle(evt)
        print('Sending event -{}- to MsgText'.format(evt))
        msg.handle(evt)
if __name__ == '__main__':
    main()

输出为:

Sending event -down- to MainWindow
MainWindow Default: down
Sending event -down- to SendDialog
MainWindow Default: down
Sending event -down- to MsgText
MsgText: down

Sending event -paint- to MainWindow
MainWindow Default: paint
Sending event -paint- to SendDialog
SendDialog: paint
Sending event -paint- to MsgText
SendDialog: paint

Sending event -unhandled- to MainWindow
MainWindow Default: unhandled
Sending event -unhandled- to SendDialog
MainWindow Default: unhandled
Sending event -unhandled- to MsgText
MainWindow Default: unhandled

Sending event -close- to MainWindow
MainWindow: close
Sending event -close- to SendDialog
MainWindow: close
Sending event -close- to MsgText
MainWindow: close
首先看以下代码片段:
class Handle_Future:
    def __init__(self):
        pass
    def main_process(self):
        if hasattr(self,'handle'):
            method = getattr(self,'handle')
            method()
        else:
            print('not has a handle method')

    def __str__(self):
        return 'my name is Yuan'

class Handle(Handle_Future):
    def handle(self):
        print('process in handle call')


han = Handle()
han.main_process()
print(han)

输出为:
process in handle call
my name is Yuan

子类继承了父类,而父类中却能调用未来的代码(很高境界),个人理解为:

Handle类实例化后,因为继承了父类Handle_Future,该实例包含了父类的所有属性和方法,代码实际上会合并(粗略理解),整个对象为 self,也就是说虽然父类的self中没有子类的函数,但是子类继承父类后,该self所代表的就是整个对象了。

class Handle():
     def main_process(self):
        if hasattr(self,'handle'):
            method = getattr(self,'handle')
            method()
        else:
            print('not has a handle method')

    def __str__(self):
        return 'my name is Yuan'
    def handle(self):
        print('process in handle call')

上面也简单回顾了了__str__魔法方法,直接引用类名(带括号,否则为地址)会调用。
再来简单理解下整个程序的设计含义,阐述责任链设计模式,在责任链模式中,发送方可直接访问链中的首个节点。若首个节点不能处理请求,则转发给下一个节点,如此直到请求被某个节点处理或者整个链遍历结束。

发送一个down事件给MainWindow,最终被MainWindow默认处理函数处理。另一个不错的用例是,虽然close事件不能被SendDialog和MsgText直接处理,但所有close事件最终都能被MainWindow正确处理。这正是使用父子关系作为一种回退机制的优美之处。

3、单例模式

单例模式的主要目的是确保某一个类只有一个实例存在。当你希望在整个系统中,某个类只能出现一个实例时,单例对象就能派上用场。主要可以很好地避免资源浪费。
单例模式主要有四种方法

  • 单独使用模块
  • __new__
  • 使用装饰器
  • 使用元类
1、使用模块

Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。因此,我们只需把相关的函数和数据定义在一个模块中,就可以获得一个单例对象了。

2、使用 __new__
class Singleton(object):
    _instance = None
    def __new__(cls, *args, **kw):
        if not cls._instance:
            cls._instance = super(Singleton, cls).__new__(cls, *args, **kw)  
        return cls._instance  
 
class MyClass(Singleton):  
    a = 1

关于 __new__方法还需要进一步理解。

3、使用装饰器
from functools import wraps
 
def singleton(cls):
    instances = {}
    @wraps(cls)
    def getinstance(*args, **kw):
        if cls not in instances:
            instances[cls] = cls(*args, **kw)
        return instances[cls]
    return getinstance
 
@singleton
class MyClass(object):
    a = 1
4、使用元类
class Singleton(type):
    _instances = {}
    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]
 
# Python2
class MyClass(object):
    __metaclass__ = Singleton
 
# Python3
# class MyClass(metaclass=Singleton):
#    pass

元类还需要更多理解。

你可能感兴趣的:(python设计模式总结)