Chinaunix首页 | 论坛 | 博客
  • 博客访问: 65416
  • 博文数量: 43
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 15:04
个人简介

记录,分享

文章分类

全部博文(43)

文章存档

2017年(24)

2015年(1)

2014年(18)

我的朋友

分类: Python/Ruby

2017-03-16 11:16:11

第十一章 函数和函数式编程

1.函数定义举例:
[a]只包含形参列表
def func(arg1,arg2) : 
[b]包含形参列表和默认参数
def func(arg1,arg2,arg3='default'):
[c]包含形参列表,默认参数和非关键字变长参数
def func(arg1,arg2,arg3='default',*nonkey_varlist)
[d]包含形参列表,默认参数,非关键字变长参数和关键字变长参数
def func(arg1,arg2,arg3='default',*nonkey_varlist,**key_varlist)


2.函数的调用
以上节[d]为例,有下面三种调用方法
[1] func(1,2,'hehe','a','b','c,','key1'='one','key2'='two')
[2] func(1,2,'hehe',*('a','b','c'),**{'key1'='one','key2'='two'})
[3] nonkey_vl=('a','b','c')
    key_vl={'key1'='one','key2'='two'}
    func(1,2,'hehe',*nonkey_vl,**key_vl)

3.函数装饰器
(1)作用:与java AOP类似,提供事务、性能统计、日志等切面功能
(2)用法:
[a]无参数的函数装饰器
无参装饰器是一个以函数对象作为参数,返回值为函数对象的函数。

def dc(func):
  def wrappedFunc(*args,**kargs):
    ...//do sth
    return func(*args,**kargs)
  return wrappedFunc

@dc
def foo(*args,**kargs):
  ...//do sth

foo(...) //invoke

效果:foo(...) = dc(foo)(...)

[b]有参数的函数装饰器
有参数的函数装饰器,是一个有参数并且返回值为函数对象的函数,返回的函数对象仍然是个函数装饰器(通常是个无参函数数装饰器)

def dc(dc_args):
  def wrappedFunc0(f):
    def innerWrapped0(*args,**kargs):
        ...//do sth
        return f
    return wrappedFunc0
  def wrappedFunc1(f):
    def innerWrapped1(*args,**kargs):
        ...//do sth
        return f
    return wrappedFunc1
  ... //process dc_args
  return wrappedFuncX

@dc('a')
def foo(...):
  ...//do sth

foo(...) //invoke

效果 : foo(...) = dc('a')(f)(...)

(3)misc:
函数装饰器效果可以叠加,如
@dc1
@dc2
def foo():
  ...
foo() 效果等同于 dc1(dc2(f))

4.函数式编程
(1)lambda表达式:返回一个可调用的函数对象
用法:
a = lambda x,y=2 : x + y
a(3)  //invoke
a(3,3)  //invoke

它等价于
def a(x,y=2):
  return x+y

(2)内建函数:apply(已废弃,由可变长参数列表代替),filter,map,reduce
filter : 过滤列表里的非真元素并生成新列表
map : 将列表的每个元素做为参数传给某个函数,并按顺序生成返回值序列
reduce :将列表第一个和第二个元素传给函数,生成返回值,再将此值与第三个元素传给函数,依次执行最终得到一个返回值。典型例子是计算阶乘。

5.python的闭包
闭包是指有权限访问另一个函数作用域的变量的函数,创建闭包的常见方式就是在一个函数内部创建另一个函数。

例子:
def counter(arg=10):
    count = [arg]
    def incr():
        count[0] += 10
        return count
    return incr

ret = counter(15)
print ret()

输出 :25

def counter(arg=10):
    count = arg
    def incr():
        count += 20
        return count
    print count
    return incr

ret = counter(15)
print ret()

输出错误 : local variable 'count' referenced before assignment

def counter(arg=10):
    count = arg
    def incr():
        count = 100
        return count
    print count
    return incr

ret = counter(15)
print ret()

输出:
15
100

【例】一个结合闭包和函数装饰器的例子
from time import time
'''
该例子演示了函数装饰器和闭包
首先,logged('pre')返回一个无参函数装饰器pre_logged,然后hello0再经过pre_logged装饰
hell0("world") 等价于 logged('pre')(hello0)('world')
'''
def logged(when):
    def log(f,*args,**kargs):
        print '''Called:
        function : %s
        args : %r
        kargs : %r''' % (f,args,kargs)
   
    def pre_logged(f):
        def wrapper(*args,**kargs):
            log(f,*args,**kargs)
            return f(*args,**kargs)
        return wrapper
   
    def post_logged(f):
        def wrapper(*args,**kargs):
            now = time()
            try:
                return f(*args,**kargs)
            finally:
                log(f,*args,**kargs)
                print 'time delta: %s' % (time()-now)
        return wrapper
       
    try:
        return {"pre":pre_logged,"post":post_logged}[when]
    except KeyError,e:
        raise ValueError(e),'must be "pre" or "post"'
   
@logged("pre")
def hello0(name):
    print "hello," , name
@logged("post")
def hello1(name):
    print "hello," , name
   
hello0("world")
print ''
hello1("world")       

6.python的生成器

生成器是一个带yield语句的函数,一个函数或子程序只返回一次,但生成器能暂停执行并返回一个中间的结果——那就是yield的功能,返回一个值给调用者并暂停执行。当生成器的next方法被调用的时候,它会准确地从离开地方继续,直到遇到yield语句停止。带yield语句的函数的真正返回值是生成器。所以不能在这种函数里用return。

yield后面的参数就是生成器next方法的返回值(中间结果),而yield表达式自己有个返回值。
send的参数是yield表达式的返回值,而send的返回值是下一次yield的返回的中间结果。

【例】
from time import sleep
def counter(start_at=0):
    print 'first invoke'
    count = start_at
    while True:
        val = (yield count)
        sleep(2)
        print ' count %s' % count
        if val is not None:
            sleep(2)
            print ' set count to %s' % val
            count = val
        else:
            count += 1
g = counter(3)
print 'next : %s' % g.next()
print 'next : %s' % g.next()
print 'next : %s' % g.next()
print 'begin to send'
print 'send : %s' % g.send(100)  //此处输出100,而不是5,因为send的执行过程会跳过一次yield
print 'next : %s' % g.next()
g.close()
# print g.next()

结果:
first invoke
next : 3
 count 3
next : 4
 count 4
next : 5
begin to send
 count 5
  set count to 100
send : 100
 count 100
next : 101

第十二章:模块

1.模块导入
import module1
import module2,module3
from module4 import funcA
from module4 import varB
from module4 import classC
import longNameModule5 as m5
from module6 import longNamefuncB as funcB

模块可以导入多次,但只会加载一次。加载时,模块顶层代码会被执行,因此在模块顶层中最好只定义函数,类和全局变量。

局部命名空间会覆盖导入的命名空间,如下

from time import sleep
def sleep(sec):
    print 'mock sleep , do nothing'

sleep(3)
print "finish"

结果:
mock sleep, do nothing 
finish
如果删去def sleep...代码段,则真正sleep会被调用。

如果不想某个模块属性被导入,可以让该属性吗以下划线开头。但是,如果显式地导入该模块属性,则加下划线也不起作用。

关于__future__(待续)

警告框架(待续)

2.包
相对导入:在不指明 package 名的情况下导入自己这个 package 的模块,比如一个 package 下有 a.py 和 b.py 两个文件,在 a.py 里 from . import b 即是相对导入 b.py。

绝对导入:指明顶层 package 名。比如 import a,Python 会在 sys.path 里寻找所有名为 a 的顶层模块。

from __future__ import absolute_import: 在 3.0 以前的旧版本中启用相对导入等特性所必须的 future 语句。







阅读(325) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~