Python高级编程-----读书笔记

1.  Keep Code Simple Not Data

l   减少代码,能减少生成的代码,因此能减少执行时间

2.  使用List Comprehensions构造List,快12倍

                              

List Comprehension性能测试

使用List Comprehension使语法简洁,生成代码减少,执行显著加快

1

[i for i in range(10000000) if i % 2 == 0]

 

 

 

测试结果

6 function calls in 2.494 seconds

 

   Ordered by: standard name

 

   ncalls  tottime   percall  cumtime  percall filename:lineno(function)

        1    0.000     0.000    2.491    2.491 :0(exec)

        1    0.003     0.003    0.003    0.003 :0(setprofile)

        1    0.000     0.000    2.491    2.491 <string>:1(<module>)

        1    0.124     0.124    2.491    2.491 logtest.py:1(test1)

        1    2.367     2.367    2.367    2.367 logtest.py:2(<listcomp>)

        0    0.000             0.000          profile:0(profiler)

        1    0.000     0.000    2.494    2.494 profile:0(test1())

2

def test2():

    numbers = range(10000000)

    size = len(numbers)

    evens = []

    i = 0

    while i < size:

        if i % 2 == 0:

             evens.append(i)

        i += 1

 

 

 

测试结果

5000006 function calls in 30.718 seconds

 

   Ordered by: standard name

 

   ncalls  tottime   percall  cumtime  percall filename:lineno(function)

  5000000   13.001     0.000   13.001    0.000 :0(append)

        1    0.000     0.000   30.715   30.715 :0(exec)

        1    0.000     0.000    0.000    0.000 :0(len)

        1    0.003     0.003    0.003    0.003 :0(setprofile)

        1    0.142     0.142   30.715   30.715 <string>:1(<module>)

        1   17.571    17.571   30.572   30.572 logtest.py:4(test2)

        0    0.000             0.000          profile:0(profiler)

        1    0.000     0.000   30.718   30.718 profile:0(test2())

 


 

3.  使用enumerate来获取index,快20%

enumerate性能测试

使用enumerate减少了索引计算语句,性能有20%提升

1

def test1():

    ll = range(1000000)

    ret = []

    for i, j in enumerate(ll):

         ret.append('%s, %s' % (i, j))

 

 

 

测试结果

1000005 function calls in 7.374 seconds

 

   Ordered by: standard name

 

   ncalls  tottime   percall  cumtime  percall filename:lineno(function)

  1000000    2.575     0.000    2.575    0.000 :0(append)

        1    0.000     0.000    7.371    7.371 :0(exec)

        1    0.003     0.003    0.003    0.003 :0(setprofile)

        1    0.056     0.056    7.371    7.371 <string>:1(<module>)

        1    4.739     4.739    7.315    7.315 logtest.py:9(test2)

        0    0.000             0.000          profile:0(profiler)

        1    0.000     0.000    7.374    7.374 profile:0(test1())

2

def test2():

    ll = range(1000000)

    ret = []

    index = 0

    for i in ll:

        index += 1

         ret.append('%s, %s' % (index, i))

 

 

 

测试结果

1000005 function calls in 7.430 seconds

 

   Ordered by: standard name

 

   ncalls  tottime   percall  cumtime  percall filename:lineno(function)

  1000000    2.575     0.000    2.575    0.000 :0(append)

        1    0.000     0.000    7.428    7.428 :0(exec)

        1    0.002     0.002    0.002    0.002 :0(setprofile)

        1    0.055     0.055    7.427    7.427 <string>:1(<module>)

        1    4.797     4.797    7.372    7.372 logtest.py:1(test1)

        0    0.000             0.000          profile:0(profiler)

        1    0.000     0.000    7.430    7.430 profile:0(test2())

4.  使用Generator处理循环/序列,节省内存

l   List Comprehensions节省CPU Generator节省内存

                              

 

5.  使用multitask并发

l  使用multitask扩展模块和Generator可以实现简单的并发操作

multitask示例

>>> def coroutine_1():

         for i in range(3):

                   print 'c1'

                   yield i         

>>> def coroutine_2():

         for i in range(3):

                   print 'c2'

                   yield i

>>> import multitask

>>> multitask.add(coroutine_1())

>>> multitask.add(coroutine_2())

>>> multitask.run()

c1 c2 c1 c2 c1 c2

 

6.  使用itertools迭代

itertools模块

itertools模块采用C语言编写,覆盖了大部分迭代模式, 主要有islice、tee和groupby

Islice模式用来对子序列进行迭代

import itertools

for x in itertools.islice('1234567890', 2, 5): #创建一个迭代下标范围为[2, 5)的迭代器

print(x)

4

5

for x in itertools.islice('1234567890', 5):   #创建一个迭代头五个字符的迭代器

1

2

3

4

5

Tee模式用来从一个迭代器上创建多个独立的迭代器迭代

import itertools

a, b = itertools.tee(‘abcdefghijklmnopqrstuvwxyz’, 2)  #创建两个迭代器a, b, 用来迭代字符串

Groupby创建一个忽略连续重复字符的迭代器

import itertools

for name, group in itertools.groupby(‘abbccc’):

pass

a, <迭代器for a>

b, <迭代器for bb>

c, <迭代器for ccc>

 

7.  使用Decorator模式

Decorator使代码更加易读、灵活[参考链接]

l  用于参数检查

l  用于缓冲

l  用于代理

l  用于上下文提供

                               

Decorator语法

不带参数的Decorator

带参数的Decorator

def decorator(func):

return func

 

@decorator():

def example(num):

print(num)

example()

 

等价于

def example(num):

print(num)

dec = decorator(example)

dec(num)

 

 

def decorator(logflags=True):

if logflags == True:

    def _decorator(func):

         print(func.__name__)

         return func

     return _decorator

else:

     return func

 

@decorator(logflags=True):

def example(num):

print(num)

example()

 

等价于

def example(num):

print(num)

tmp = decorator(logflags=True)

dec = tmp(example)

dec(num)

一般多层嵌套的装饰器,建议加下划线的方式命名。每多嵌套一层,便多一个下划线。

 

8.  使用with替代try…finally 

try…finally主要用于以下场景:

l  Closing a file

l  Releasing a lock

l  Making a temporary code patch

l  Running protected code in aspecial environment

由于try…finally结构写起来丑陋,因此使用with来代替try…finally

With使用示例

with_stmt ::=   "with" with_item ("," with_item)* ":" suite

with_item ::=   expression ["as" target]

使用with示例

定义支持with的类

fd = open(‘readme.txt’, ‘r)

try:

for line in fd:

     print line

finally:

fd.close()

可以写作

with open(‘readme.txt’, ‘r) as fd:

for line in fd:

     print line

class test():

def __enter__(self):

     print(‘enter context’)

 

def __exit__(self, exp_type, exp_value, exp_tb):

     print(‘exit context’)

with test() as t:

print(t)

当with中没有异常抛出时,传入__exit__的3个参数为None

当有异常抛出时,__exit__函数应该捕获该异常进行处理,不再抛出


@contextmanager使用示例

使用@contextmanager装饰的方法,会自动将方法中yield前面的语句放入__enter__中执行,后面的语句放入__exit__中执行。 在with中执行时, yield表达式作为提交给with的表达式结果

import logging

from contextlib import contextmanager

@contextmanager

def logged(klass):

# logger

    def _log(f):

        def __log(*args, **kw):

            logging.ERROR('%s, %s, %s' % (f.__name__, args, kw))

            return f(*args, **kw)

        return __log

    #遍历类中的所有方法,并用__log方法装饰后,代替原来的方法

    for attribute in dir(klass):

        #遍历非私有方法

        if attribute.startswith('_'):

            continue

        #取得方法名(attrbute)对应的方法对象(element)

        element = getattr(klass, attribute)

        #使用__log封装该方法,并取名为__logged_attribute

        setattr(klass, '__logged_%s' % attribute, element)

        #将原有的attribue方法,替换为封装后的方法

        setattr(klass, attribute, _log(element))

    

    # let's work 执行到这里,返回给with语句,等待with语句执行完毕,再执行下面的语句

    yield klass

    

    # let's remove the logging

    for attribute in dir(klass):

        #遍历所有的__logged_开头,封装过的方法

        if not attribute.startswith('__logged_'):

            continue

        element = getattr(klass, attribute)

        #将方法改名(去掉__logged_头)

        setattr(klass, attribute[len('__logged_'):], element)

        #删除__logged_头的方法

        delattr(klass, attribute)

class One(object):

    def _private(self):

        pass

    def one(self, other):

        self.two()

        other.thing(self)

        self._private()

    def two(self):

        pass

 

class Two(object):

    def thing(self, other):

        other.two()

 

with logged(One):  #返回yield klass中的klass

    one = One()

    two = Two()

    one.one(two)

closing使用示例(仅PYTHON 2.x

closing用于上下文对象执行完毕后,自动调用其close方法,将其关闭。PYTHON 3.x中已无该方法。

from contextlib import closing

from urllib.request import urlopen

 

with closing(urlopen('http://www.python.org')) as page:

    for line in page:

        print(line)

 

等价于

from contextlib import contextmanager

@contextmanager

def closing(thing):

    try:

        yield thing

    finally:

        thing.close()

Decorator模式和Proxy模式不同之处在于,Decorator只用来修饰某个方法,而Proxy模式代理的是一个功能(可能涉及到多个方法)。Decorator一般专用于方法,而Proxy用于类

你可能感兴趣的:(Python高级编程-----读书笔记)