python 装饰器

装饰器本质上是一个Python函数,它能够让别的函数在无需做此外轮代理公司码变动的前提下增加额外成效,装饰器的重回值也是二个函数对象。它平日用来有切面须要的情景,比方:插入日志、质量测量试验、事务管理、缓存、权限校验等情况。装饰器是缓慢解决那类难点的绝佳设计,有了装饰器,大家就能够抽离出大方与函数成效本身非亲非故的一致代码并继续起用。

澳门凯旋门游戏网址 ,写一个轻便的装饰器

def deco(f):
    def wrapped(*args, **kwargs):
        print "start"
        f(*args, **kwargs)
        print "end"
    return wrapped

@deco
def func(a):
    print a

func("func run")

运维代码最后得到:

start
func run
end

透过示范代码可以越来越好的知道装饰器的概念里面额外功用那几个意思。

凯旋门074网址 ,带参数的装饰器

def deco(level):
    def wrapped(f):
        def wrapper_inner(*args, **kwargs):
            print "%s start" % level
            f(*args, **kwargs)
            print "end"
        return wrapper_inner
    return wrapped

@deco("i am info")
def func(a):
    print a

func("func run")

如装饰器定义中的使用,在打字与印刷日志时,大家大概供给输入不一致的级差,这时就须求带参数的装饰器。
从此间也足以看到装饰器的参数传入顺序,从上到下,装饰器参数,装饰器修饰函数,和函数参数。

澳门凯旋门注册网址 ,放置装饰器

置于装饰器与平日装饰器原理上分裂,重返的是八个类对象,

@property
class TestEntiy(object):

    def __init__(self):
        super(TestEntiy, self).__init__()
        self._position = 5

    @property
    def position(self):
        return self._position

    @position.setter
    def position(self, value):
        self._position = value

    @position.deleter
    def position(self):
        del self._position

选择@语法糖,更简洁的实现get和set
不过要专注的是setter和deleter是property的第二多少个参数,无法平昔动用@语法,而相应运用已部分peoperty对象调用

@staticmethod和@classmethod

大家兴许需求输入分裂的阶段。分别再次回到staticmethod和classmethod对象,来调用修饰函数,实现只好利用类调用而非对象调用

依靠装饰器完毕event回调语义

在成功娱乐作业使用unity做客户端,python做服务端。由于unity使用的脚本语言是c#大家兴许需求输入分裂的阶段。,因而在形成多少同步时,对于服务器的数目开展分发时,使用了delegate
&
event语义来实现event回调,化解了数量管理实体与socket网络服务实体代码之间的紧耦合。不过后来换了客户端引擎之后选用python开荒客户端,为了落到实处event回调语义来消除服务端数据分发至各样数据处理实体,对于python语言的装饰器语法糖实行了读书

def msg_listener(*events):
    def wrapper(func):
        func.events = events
        return func
    return wrapper

大家兴许需求输入分裂的阶段。率先是装饰器,对于棉被服装饰函数对象加上events属性,这里python很骚的地点,everything
is object
接下来我们再来看给各样函数加上的events是个如李天乐西

class MsgNotifierEvent(object):
    _events = []

    def __init__(self, name):
        super(MsgNotifierEvent, self).__init__()
        self._name = name
        self._callback = []
        MsgNotifierEvent._events.append(self)

    def __iadd__(self, callback):
        self._callback.append(callback)
        return self

    def __call__(self, *args, **kwargs):
        for cb in self._callback:
            try:
                cb(*args, **kwargs)
            except Exception as e:
                print "msgNotifier callback error, function:", cb.__name__, e

    @classmethod
    def clear(cls, name):
        for event in cls._events:
            if event._name == name:
                event._callback = []
                break

那边从写了__call__函数,因而入眼的选取实在调用此目的时,那么_callback里面又是何许吧?
以下是自己客户端数据管理的基类,重纵然含有数据监听的逻辑(Event回调),这里能够看出init_data_listener函数获取了具备包蕴events属性的函数,将那么些函数的都加到对应events的回调队列中(这里能够倾心一段代码对于__iadd__的重载),那样就完全兑现了经过监听器MsgNotifier伊芙nt的调用,达成了多少来临之后对于数据管理函数的回调

# -*- coding: utf-8 -*-
import abc
import inspect
class ManagerBase(object):
    #包含数据接受的实体基类,需自己实现destroy函数,清除监听器和事件
    __metaclass__ = abc.ABCMeta
    def __init__(self):
        super(ManagerBase, self).__init__()
        self.init_data_listener()

    def init_data_listener(self):
        for listener_name, listener in inspect.getmembers(self, lambda f: hasattr(f, 'events')):
            for event in listener.events:
                event += listener

    @abc.abstractmethod
    def destroy(self):
        raise NotImplementedError

以下为测验代码

class TestEntiy(ManagerBase):

    def __init__(self):
        super(TestEntiy, self).__init__()

    @msg_listener(game_msg_recv)
    def update(self, protocol):
        print "this is deal data:", protocol

    def destroy(self):
        MsgNotifierEvent.clear("game_msg_recv")


test = TestEntiy()

game_msg_recv("i am test1")
test.destroy()
game_msg_recv("i am test2")

#输出
#this is deal data: i am test1

相关文章