范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

面试官你相信吗,我只用两个函数实现事务!(设计模式)

  主题  设计模式    Python
  大家好,今天给大家介绍一个新的设计模式,叫做memento模式。
  memento在英文当中是纪念品的意思,在这里,指的是对象的深度拷贝。通过对对象深度拷贝的方法来 实现事务的功能 。有了解过数据库的小伙伴们应该都知道,在数据库当中有些操作是绑定的, 要么一起执行成功,要么一起不执行,绝对不运行某些操作执行了,某些操作没有执行的情况发生 。这一点就被称为事务。
  深度拷贝
  我们先来简单回顾一下Python当中的拷贝。
  拷贝在很多语言当中都有对应的函数,在Python当中也不例外。Python中的拷贝函数有两个,一个是copy,另外一个是deepcopy。也就是常说的深拷贝和浅拷贝,这两者的区别也非常简单,简而言之就是 浅拷贝只会拷贝父类对象,不会拷贝父类对象当中的子对象 。
  我们来看一个例子,在下图当中b是a的浅拷贝,我们可以看到当a[2]当中插入了5之后,b当中同样也多了一个5。因为它们下标2存储的是同一个引用,所以当a当中插入的时候,b当中也发生了同样的改变。我们也可以看到,当我们改变了a[0]的时候,b当中则没有发生对应的改变。因为a[0]是一个数字,数字是基础类型直接存储的值而不是引用。
  与浅拷贝对应的就是深拷贝,我们可以看到,当a[2]当中插入元素的时候,深度拷贝出来的b并不会发生对应的变化。
  memento
  利用拷贝,我们可以实现memento函数,它的作用是 给对象做备份 。在Python当中,对于一个对象obj来说,它所有的成员以及函数等信息全是储存在 obj.__dict__  这个dict当中的。也就是说如果我们将一个对象的 __dict__  拷贝一份的话,其实就相当于我们把对象拷贝了一份。
  通过使用拷贝,我们可以很容易实现memento函数,我们先来看代码吧。from copy import copy, deepcopy  def memento(obj, deep=False):     state = deepcopy(obj.__dict__) if deep else copy(obj.__dict__)      def restore():         obj.__dict__.clear()         obj.__dict__.update(state)          return restore
  memento是一个高阶函数, 它返回的结果是执行函数,而不是具体的执行结果 。如果对高阶函数不太熟悉的同学,可以去回顾一下Python当中高阶函数的相关内容。
  这里面的逻辑不难理解,传入的参数是一个obj的对象和一个bool型的flag。flag表示使用深拷贝或浅拷贝,obj就是我们需要做对应快照或者是存档的对象。我们希望在对象框架不变的基础上恢复其中的内容,所以我们拷贝的范围很明确,就是 obj.__dict__  ,这当中存储了对象的所有关键信息。
  我们看下restore这个函数,当中的内容其实很简单,只有两行。第一行是清空obj目前 __dict__  当中的内容,第二步是用之前保存的state来还原。其实restore执行的是一个 回滚obj的功能,我们捋一下整个过程。我们运行memento函数会得到restore这个函数,当我们执行这个函数的时候,obj当中的内容会回滚到上次执行memento时的状态。
  理解了memento当中的逻辑之后,距离我们实现事务就不远了。关于事务我们有两种实现方法,一种是通过对象,一种是通过装饰器,我们一个一个来说吧。
  Transaction对象
  面向对象实现的方式比较简单,它和我们平时使用事务的过程也比较近似。Transaction对象当中应该提供两个函数,一个是commit一个是rollback。也就是说 当我们执行成功之后我们执行commit,对执行的结果进行快照。如果执行失败则rollback,将对象的结果回滚到上一次commit时的状态 。
  我们理解了memento函数之后,会发现commit和rollback刚好对应执行memento函数以及执行restore函数。这样我们不难写出代码:class Transaction:      deep = False     states = []      def __init__(self, deep, *targets):         self.deep = deep         self.targets = targets         self.commit()      def commit(self):         self.states = [memento(target, self.deep) for target in self.targets]      def rollback(self):         for a_state in self.states:             a_state()
  由于我们需要事务的对象可能不止一个,所以这里的targets设计成了数组的形式。Transaction装饰器
  我们也可以把事务实现成装饰器,这样我们可以通过注解的方式来使用。
  这里的代码原理也是一样的,只不过实现逻辑基于装饰器而已。如果对装饰器熟悉的同学,其实也不难理解。这里的args[0]其实就是某一个类的实例,也就是我们需要保证事务的主体。from functools import wraps  def transactional(func):     @wraps(func)     def wrapper(*args, **kwargs):         # args[0] is obj         state = memento(args[0])         try:             func(*args, **kwargs)         except Exception as e:             state()             raise e     return wrapper
  这是常规装饰器的写法,当然我们也可以用类来实现装饰器,其实原理差不多,只是有一些细节不太一样。class Transactional:      def __init__(self, method):         self.method = method      def __get__(self, obj, cls):         def transaction(*args, **kwargs):             state = memento(obj)             try:                 return self.method(*args, **kwargs)             except Exception as e:                 state()                 raise e         return transaction
  当我们将这个注解加在某一个类方法上,当我们执行obj.xxx的时候,就会执行Transactional这个类当中的 __get__  方法,而不是获得Transactional这个类。并且把obj以及obj对应的类型作为参数传入,也就是这里的obj和cls的含义。这个是用类来实现装饰器的常规做法,我们贴一下常规的代码,来比较学习一下。class Wrapper:     def __init__(self, func):         wraps(func)(self)      def __call__(self, *args, **kwargs):         return self.__wrapped__(*args, **kwargs)      def __get__(self, instance, cls):         if instance is None:             return self         else:             return types.MethodType(self, instance)
  这是一个用类来实现装饰器的case,我们可以看到在 __get__  这个函数当中返回的是self,也就是返回了Wrapper这个类。类通常是不能直接执行的,为了让它能够执行,这里给它实现了一个 __call__  函数。如果还是看不明白也没有关系,可以忽略这部分。用类实现装饰器也不常见,我们熟悉高阶函数的方法就可以了。实战
  最后我们来看一个实际应用的例子,我们实现了一个NumObj的类,兼容了上面两种事务的使用,可以对比一下看看区别。class NumObj:     def __init__(self, value):         self.value = value      def __repr__(self):         return "<%s, %r>" % (self.__class__.__name__, self.value)      def increment(self):         self.value += 1      @transactional     def do_stuff(self):         self.value += "111"         self.increment()                   if __name__ == "__main__":     num_obj = NumObj(-1)      a_transaction = Transaction(True, num_obj)  # 使用Transaction     try:         for i in range(3):             num_obj.increment()             print(num_obj)          a_transaction.commit()         print("----committed")         for i in range(3):             num_obj.increment()             print(num_obj)         num_obj.value += "x"         print(num_obj)     except Exception:         a_transaction.rollback()         print("----rollback")      print(num_obj)  # 使用Transactional     print("-- now doing stuff")     num_obj.increment()      try:         num_obj.do_stuff()     except Exception:         print("-> doing stuff failed")         import sys         import traceback         traceback.print_exc(file=sys.stdout)      print(num_obj)
  从代码当中,我们不难发现对于Transaction也就是面向对象实现的,我们 需要额外创建一个Transaction的实例来在try catch当中控制是否执行回滚 。而使用注解的方式更加灵活,它 执行失败会自动执行回滚 ,不需要太多的额外操作。
  一般来说我们更加喜欢使用注解的方式,因为这样的方式更加简洁干净,更加pythonic,能够体现出Python的强大。而第一种方法显得有些中规中矩,不过好处是可读性强一些,代码实现难度也低一些。大家如果在实际工作当中有需要用到,可以根据自己的实际情况去进行选择,两种都是不错的方法。
  今天的文章就到这里,衷心祝愿大家每天都有所收获。如果还喜欢今天的内容的话,请来一个三连支持 吧~( 点赞、关注、转发 )
  原文  http://www.cnblogs.com/techflow/p/14297395.html

腾讯员工碎片时间开发的Mac看图软件,没有产品经理却是目前最佳大多数的macOS用户估计跟我的感觉都差不多,也跟做这款软件的腾讯同学一样,macOS上实在是难以找到一个满意好用的看图软件,macOS自带的Preview自然是功能强大,但是用户269元入手Nokia1安卓机,后盖可拆卸,轻松换电池!去年2月份的MWC大会上,诺基亚一反常态,发布了一款超低端的安卓手机,叫做Nokia1(从这命名就知道了),这部手机直到去年四月才正式开卖。Nokia1最大的特点就是便宜,当时国外当之无愧的世界首富年收入5003亿,家族财富比贝佐斯还多400亿文秉文在今年公布的最新福布斯富豪榜中,亚马逊的创始人杰夫贝佐斯以1310亿美元的净身家蝉联全球首富之位,再度成为世界上最富有的人。但是,有一个家族可比贝佐斯还要富有,如果按照整个家世界上最大的发动机,4层楼高,一小时烧15吨油不够烧!日前,财政部税务总局海关总署近日联合印发关于深化增值税改革有关政策的公告,决定自4月1日起降低部分行业增值税税率。根据公告,成品油增值税税率由16降低至13。今年以来,国内成品油共卢伟冰没说谎!Redmi7插卡待机测试,401小时仍然有电红米Redmi自更名后已经先后发布了三款手机,分别是RedmiNote7,RedmiNote7Pro和Redmi7,定价也有所悬殊,毕竟定位的人群不一样。前两款RedmiNote7偷会员的人爱优腾共享会员乱象揭蛊作者Susan编辑轩辕镜封面来源摄图网出不了门的黄金周,就靠这些资源活了。五一期间,躁动的不仅是很多人无法旅游的心情,还有一门叫做共享会员的生意。雪豹财经社发现,平日里就买卖兴旺的iQOONeo6SE详细配置曝光骁龙87080W快充5月6日晚上1930,iQOO将发布Neo系列新品iQOONeo6SE,该机已在vivo商城京东天猫等各大平台开启预约。人气火爆。数码博主数码闲聊站曝光了iQOONeo6SE详细参骁龙865一代神U真的还能再战三年吗?前段时间看到了一篇文章,是关于骁龙865处理器的,就骁龙865处理器还能不能再战三年,进行了详细的分享。下面我就来给大家分享分享。首先问大家一个问题,关于处理器你了解多少?买手机时小米Mix5真要来了!新版骁龙8Gen12K屏隔空充电,这次稳了对于米粉而言,目前最期待的机型除了小米12Ultra,就属小米Mix5了吧。作为小米最高端系列,每一代小米Mix都搭载了黑科技,那么今年的小米Mix5将带来哪些表现呢?据最新消息曝苹果又出黑科技!轻触支付功能即将在美率先上线当地时间2月8日,苹果公司在其官网发布公告,宣布将在iPhone上推出轻触支付(TaptoPay)功能,这是一种非接触式支付方式。这一创新金融服务将会进一步简化付款过程。在结账时,促进互联网企业健康持续发展工作座谈会发言摘编编者按1月28日下午,中央网信办国家发展改革委工业和信息化部市场监管总局四部门联合召开促进互联网企业健康持续发展工作座谈会,人民网快手美团京东小米等5家互联网企业负责人在会上作了发
吉利向韩国市场进军中国电动车新锐极星2登陆韩国,日前,新兴电动车品牌极星发布了旗下首款面向韩国市场的纯电动汽车极星2。极星是沃尔沃汽车集团与中国母公司吉利控股共同拥有的全球高性能电动汽车品牌,去年3月在韩国设立了全资子公司。此7年烧掉150亿,口碑倒数第一的中国快递公司,最终以68亿卖身极兔文JING审核子扬校正知秋2006年,学霸周韶宁从谷歌离职,拿出1000万自有资金,在杭州创办百世物流。因为拥有地缘优势,百世物流成为马云投资的第一家快递企业。但即便背后有阿里撑腰快递包裹张贴广告涉嫌违法春节临近,网购的年货纷至沓来,然而今年很多消费者在收取快递时发现,包裹上总是贴着印有扫码领100元现金红包随机奖励2箱牛奶扫码抽1个保温杯等内容的二维码,看上去颇为诱人,这究竟是春不用烦了!江苏新能源充电设施高速公路全覆盖长途出行又碰上春运高峰,高速服务区充电排队怎么办?这是不少新能源车主春运长途出行前的主要顾虑。江苏地处东部沿海交通大动脉,春运期间南下北上车流多,为保障春节期间新能源汽车返乡需求,20亿美元薪酬没谈妥,孙正义救火队长离职文观察者网吕栋最近10年里,每当融资变得艰难时,软银集团董事长孙正义都会让他的得力助手马塞洛克劳雷(MarceloClaure)去解决难题。然而,当克劳雷为过去数年的功绩提出20亿一加9后李开新履新刘作虎改任OPPO助理副总裁,负责IoT事业群可能不少小伙伴对于李开新这个名字已经有些淡忘,但是要说到他的光环,关注手机圈的小伙伴应该没人不知。当初华为手机破千万的大功臣360手机辉煌时候的掌门人等,一加9系列发布之前李开新加新能源汽车局部变量,前景可期2021年,中国汽车产业走过了极其不平凡的一年,在疫情与芯片短缺原材料上涨等多重因素影响下,中国汽车市场在危机与挑战中持续升温,市场总体呈现出超预期的表现,尤其是新能源汽车市场,更十项全能的蒸烤炸一体机选购攻略热门机型推荐年夜饭食谱今年带空气炸功能的烤箱特别火,甚至一路火到了蒸烤箱领域,出现了蒸烤炸一体机。理论上只要带热风功能的蒸烤箱,都是具备空气炸功能的,可以替代蒸箱烤箱空气炸锅等家电,可以说是十项全能一步2021年机器人产业融资图景工业机器人上游赛道火热,医疗机器人风口渐起南方财经全媒体记者柳宁馨,实习记者欧阳丽云广州报道2021年是机器人行业蓬勃发展的一年,也带来机器人赛道的融资热潮。根据南方财经全媒体记者不完全梳理,2021年中国机器人行业融资事强者自强,华为重返赛道的强烈信号,路在艰难还是要死磕到底就在2022年的第六天,华为拿出了两款国产芯片,可以说是业内传来一个重大消息,华为即将推出两款芯片,均采用中芯国际14纳米,要知道美国封禁多家芯片企业如台积电停止芯片供应一直封禁,雷军的小米12X值得购买吗?小米12系列哪一款适合自己?小米手机每次新品发布总会引来不少人的追捧,开销5分钟实现了18亿元。也有不少人认为小米雷军发布的小米12手机简配又加价。特别是小米12X减配有点太大,简直就是收割一波韭菜,到底小米