• [高清组图]环广西赛:参赛车队赛前适应训练 2018-08-31
  • [高清组图]特谢拉复出吴曦失单刀 苏宁0-0平斯威 2018-08-31
  • [高清组图]潜水偶遇座头鲸 亲密互动玩起“水中击掌” 2018-08-31
  • [高清组图]法拉利拍定妆照 维特尔KIMI准备好了 2018-08-31
  • [高清组图]毛剑卿伤退莫雷诺捅射 申花1-0一方 2018-08-31
  • [高清组图]比埃拉双响巴坎布建功 国安5-1富力 2018-08-31
  • [高清组图]武磊世界波胡尔克点射 上港2-0胜申花 2018-08-31
  • [高清组图]武磊2球吕文君建功 上港3-1富力 2018-08-31
  • [高清组图]欧超杯-科斯塔2球 皇马加时赛2-4马竞 2018-08-31
  • [高清组图]格里芬赤膊骑行 休赛期享受二人世界 2018-08-31
  • [视频]【深化改革 重在实效】精准扶贫 四川彝区要拔掉“穷根” 2018-08-31
  • [视频]【深化改革 重在实效】破藩篱促合力 体制创新粘合“两张皮” 2018-08-31
  • [视频]【深化改革 重在实效】激发活力 实现市场准入全程便利化 2018-08-31
  • [视频]【深化改革 重在实效】打通简政放权的“最后一公里” 2018-08-31
  • [视频]【深化改革 重在实效】广东:户籍改革为外来工打开一扇门 2018-08-31
  • 手机版
    你好,游客 登录 注册 搜索
    背景:
    阅读新闻

    Python装饰器入门笔记

    [日期:2018-08-11] 来源:Linux社区  作者:Linux [字体: ]

    奥门新萄京官方正版 www.arianalance.com 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

    通过示例代码可以更好的理解装饰器的定义。

    带参数的装饰器
    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__的重载),这样就完整实现了通过监听器MsgNotifierEvent的调用,实现了数据到来之后对于数据处理函数的回调
    # -*- 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

    Linux公社的RSS地址:http://www.arianalance.com/rssFeed.aspx

    本文永久更新链接地址http://www.arianalance.com/Linux/2018-08/153465.htm

    linux
    相关资讯       Python装饰器 
    本文评论   查看全部评论 (0)
    表情: 表情 姓名: 字数

           

    评论声明
    • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
    • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
    • 本站管理人员有权保留或删除其管辖留言中的任意内容
    • 本站有权在网站内转载或引用您的评论
    • 参与本评论即表明您已经阅读并接受上述条款