Python进阶(一)

博客链接:http://inarrater.com/2016/06/30/pythonadvance1/

前一周听了三节Python进阶课程,有十几年的老程序给您讲解传授一门语言的进阶知识,可能那是在大商店才能享用到的便宜。即使接触使用Python也有三四年岁月了,但是从课程中依旧学习到很多事物,了然了新技巧的用法,精晓了老知识背后的来头。
下载了课件,做了笔记,但自己要么希望用讲述的主意把它们表现出来,为前途的祥和,也给必要的读者。全部以大雄的教程为原本,结合本人在付出中的一些投机的回味和想方设法。

1. 写操作对于命名空间的震慑

第3来看这么一段代码:

import math

def foo(processed):
    value = math.pi

    # The other programmer add logic here.
    if processed:
        import math
        value = math.sin(value)

    print value

foo(True)

思考:你以为那段代码有没有如何难题,它的周转结果是如何?

第叁,小编个人不欣赏在代码中开展import math的操作的点子,平常会建议把这一操作放置到文件头部,那关键处在性能的考虑——就算一度import过的模块不会再也执行加载进度,但终归有三遍从sys.modules中询问的进度。那种操作在tick等往往执行的逻辑中进一步要去幸免。

但那并不是这段代码的难点所在的要害,当你品尝举办那段代码的时候,会输出如下的荒谬:

Traceback (most recent call last):
  File "C:\Users\David-PC\Desktop\Advanced Course on Python 2016\t019.py", line 13, in <module>
    foo(True)
  File "C:\Users\David-PC\Desktop\Advanced Course on Python 2016\t019.py", line 4, in foo
    value = math.pi
UnboundLocalError: local variable 'math' referenced before assignment

在赋值从前被引述了,这不啻是在文件尾部进行import的锅。这几个例子稍微有点复杂,我们品尝写一段有点类似但是更简便的事例,在前头编码进度中本身就遇上过类似的意况:

value = 0
def foo():
    if value > 0:
        value = 1
        print value
foo()

无异于会提示value在被赋值以前被选拔了,让那段代码不奇怪运营很简短,只须要把global value置身foo函数定义的率先行就足以了。

思考: 为何在foo函数内部,不能访问其外表的value变量?

一经你把value = 1这一行代码注释掉,那段代码就可以健康运作,看上去对于value的赋值操作导致了大家不可以不奇怪访问3个外表的变量,无论那个赋值操作在访问操作之前照旧现在。

Write operation will shield the locating outside the current name
space, which is determined at compile time.

大致来说,命名空间内部倘诺有对变量的写操作,这么些变量在那些命名空间中就会被认为是local的,你的代码就不或许在赋值从前使用它,而且检查过程是在编译的时候。使用global关键字可以改变这一表现。
这大家回去第3段代码,为何imort的1个模块也无力回天平常被运用呢?
借使知道import的经过,答案就很简短了——import其实就是1个赋值的进度

总结:从前作者自认为Python的命名空间很简单了解,对于全局变量或然说upvalue的拜访却无独有偶不去注意,有时候觉得不要求写global来标识也足以访问取得,有时候又会赶上语法错误的唤醒,其实平昔尚未知晓了然是什么规则导致那样的结果。
写操作对于命名空间的熏陶解答了这一标题,让自个儿看齐本人此前“面对不可相信提醒编程”的蠢笨和懒惰。。。

2. 巡回引用

Python的杂质回收(GC)结合了引用计数(Reference Count)、对象池(Object
Pool)、标记清除(马克 and Sweep)、分代回收(Generational
Collecting)那两种技术,具体的GC完结放在前边来说,大家先看代码中设有循环引用的动静。
玩耍支付中规划出循环引用分外市大概,比如游戏中常用的实体(Entity)结构:

class EntityManager(object):
    def __init__():
        self.__entities = {}

    def add_entity(eid):
        #Some process code.
        self.__entities[eid] = Entity(id, self)

    def get_entity(eid):
        return self.__entities.get(eid, None)

class Entity(object):
    def __init__(eid, mgr):
        self.eid = _id
        self.mgr = mgr

    def attact(skill_id, target_id):
        target = self.mgr.get_entity(target_id)
        #attack the target
        #...

很明显,这里EntityManager中的__entities天性引用了它所主宰的享有目的,而对于三个游戏实体,有时候须求可以拿到其他实体对象,那么最不难易行的方法就是把EntityManager的友善传递给成立出来的实体,让其保存2个引用,那样在推行攻击那样的函数的时候,就足以很方便地赢拿到想要得到的多少。
EntityManager中的__entities天性引用了Entity对象,Entity对象身上的mgr属性又引述了EntityManager对象,那就存在循环引用。
部分人或然会说,有轮回引用了,so what?
首先自身可以从逻辑上确保自由的时候都会把环解开,那样就可以不荒谬释放内存了。再者,本身Python自个儿就提供了废品回收的点子,它可以帮小编清理。
对于那种想法,作为一个玩耍开发者,我代表——呵呵
我们看贰个在嬉戏开发中广大的轮回引用的事例,有个别景况下写了巡回引用而不自知(实例代码直接接纳大雄课程中的)。

class Animation(object):
    def __init__(self, callback):
        self._callback = callback

class Entity(object):
    def __init__(self):
        self._animation = Animation(self._complete)

    def _complete(self):
        pass

e = Entity()
print e._animation._callback.im_self is e

末尾print输出的结果是True,也解释了那段逻辑中的循环引用所在。
对此多少人搭档来贯彻的大型项目来说,逻辑上保障代码中从不环存在是大约不可以的作业,况且尽管你代码逻辑上得以正确释放,偶发的traceback就只怕让你接环的逻辑没有被实践到,从而造成了循环引用对象的不可以及时放飞。

Python的循环引用处理,借使一个目的的引用计数为0的时候,该对象会立即被假释掉。

接下来Python的GC是很耗的三个历程,会导致CPU眨眼间间的峰值等题材,搜狐有品种就全盘自身达成了一套分片二十四线程的GC机制来替换掉Python原生的GC。
大方循环引用的存在会促成更慢尤其频仍的GC,也会造成内存的动乱。

解决措施:对于EntityManager的事例,使用weakref来消除;对于callback的例子,尽量防止使用对象的办法来作为三个回调。

总结:对于简易的连串来说,不要求关爱循环引用的难题,交给Python的GC就够了,但是要求长日子运作,对于CPU波动敏感的种类,要求关爱循环引用的影响,尽量去回避。

题外话:在我们以往的花色中,EntityManager的例证使用了单例格局来解除循环引用,那是一种常用的方法,可是单例格局也不是“4858mgm,银弹”。那种设计格局在限定对象实例化的还要,也提供了全局访问的接口,意味着那几个单例对象变成了三个大局对象,于是代码中充斥了不考虑耦合性的滥用。在客户端代码中,那么些使用全局单例的逻辑没很是,因为客户端只必要七个EntityManager就可以管理全体的游乐实体,也不会设有其余的相互环境,而当我们要求展开服务端开发的时候,同一份代码得到服务端就改成了不幸——对于服务端来说,可能会设有很多EntityManager管理不一样情境下的二十四日游实体,单例的格局不再可用,以前任意拜访EntityManager的地方都急需通过迭代和整治才方可健康实施。

PPS:刚刚初叶使用马克Down,一些语法还不了解,可是用它写起那种带有代码的稿子来说还是那一个如沐春风的,那篇起始让自身体会到了那一点。所以说,唯有程序员那种geek生物才会喜欢Hexo等依照马克Down须求generate成静态网页的博客。。。

二零一四年一月七日于大阪家园

相关文章