python核心编程(十一&十二)— 函数和函数式编程、模块

来源:互联网 发布:中国网络被攻击2017 编辑:程序博客网 时间:2024/04/29 23:24

函数和函数式编程

函数是对程序逻辑进行结构化或过程化的一种编程方法。能将整块代码巧妙地隔离成易于管理的小块,把重复代码放到函数中而不是进行大量的拷贝–这样既能节省空间,也有助于保持一致性,因为你只需改变单个的拷贝而无须去寻找再修改大量复制代码的拷贝。

返回值与函数类型

函数会向调用者返回一个值,而实际编程中大偏函数更接近过程,不显示地返回任何东西。把过程看待成函数的语言通常对于“什么都不返回”的函数设定了特殊的类型或者值的名字。这些函数在 c 中默认为“void”的返回类型,意思是没有值返回。在 python 中,对应的返回对象类型是 none。

简而言之,当没有显式地返回元素或者如果返回 None 时,python 会返回一个 None.那么调用者接收的就是 python 返回的那个对象,且对象的类型仍然相同。如果函数返回多个对象,python 把他们聚集起来并以一个元组返回。是的,尽管我们声称 python 比诸如 c 那样只允许一个返回值的语言灵活的多,但是老实说,python 也遵循了相同的传统。只是让程序员误以为可以返回多个对象。

调用函数

函数操作符

我们用一对圆括号调用函数

关键字参数

关键字参数的概念仅仅针对函数的调用。这种理念是让调用者通过函数调用中的参数名字来区分参数。这样规范允许参数缺失或者不按顺序,因为解释器能通过给出的关键字来匹配参数的值。

默认参数

默认参数就是声明了默认值的参数。因为给参数赋予了默认值,所以, 在函数调用时,不向该参数传入值也是允许的。

参数组

Python 同样允许程序员执行一个没有显式定义参数的函数,相应的方法是通过一个把元组(非关键字参数)或字典(关键字参数)作为参数组传递给函数。

func(*tuple_grp_nonkw_args, **dict_grp_kw_args)

其中的 tuple_grp_nonkw_args 是以元组形式体现的非关键字参数组, dict_grp_kw_args 是装有关键字参数的字典。

你也可以给出形参!这些参数包括标准的位置参数和关键字参数,所以在 python 中允许的函数调用的完整语法为:

func(positional_args, keyword_args,*tuple_grp_nonkw_args, **dict_grp_kw_args)

该语法中的所有的参数都是可选的—从参数传递到函数的过程来看,在单独的函数调用时,每个参数都是独立的。

创建函数

def 语句

函数是用 def 语句来创建的,语法如下:

def function_name(arguments):    "function_documentation_string"    function_body_suite

标题行由 def 关键字,函数的名字,以及参数的集合(如果有的话)组成。def 子句的剩余部分包括了一个虽然可选但是强烈推荐的文档字串,和必需的函数体。

声明与定义比较

python将这两者视为一体,函数的子句由声明的标题行以及随后的定义体组成的。

前向引用

和其他高级语言类似,Python 也不允许在函数未声明之前,对其进行引用或者调用.

函数属性

内部/内嵌函数

函数(与方法)装饰器

装饰器背后的主要动机源自 python 面向对象编程。装饰器是在函数调用之上的修饰。这些修饰仅是当声明一个函数或者方法的时候,才会应用的额外调用。

装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰 的函数,和装饰函数的可选参数。

装饰器实际就是函数。我们也知道他们接受函数对象。但它们是怎样处理那些函数的呢?一般说来,当你包装一个函数的时候,你最终会调用它。最棒的是我们能在包装的环境下 在合适的时机调用它。我们在执行函数之前,可以运行些预备代码,如 post-morrem 分析,也可以在 执行代码之后做些清理工作。所以当你看见一个装饰器函数的时候,很可能在里面找到这样一些代 码,它定义了某个函数并在定义内的某处嵌入了对目标函数的调用或者至少一些引用。从本质上看, 这些特征引入了 java 开发者称呼之为 AOP(Aspect Oriented Programming,面向方面编程)的概念。 你可以考虑在装饰器中置入通用功能的代码来降低程序复杂度。例如,可以用装饰器来:

  1. 引入日志
  2. 增加计时逻辑来检测性能
  3. 给函数加入事务的能力

传递函数

一个将函数作为参数传递,并在函数体内调用这些函数。

举例:

无参数

# coding=utf-8# 不带参数的装饰器# wraper 将fn进行装饰,return wraper ,返回的wraper 就是装饰之后的fndef test(func):    def wraper():        print "test start"        func()        print "end start"    return wraper@testdef foo():    print "in foo"foo()

有参数

def parameter_test(func):    def wraper(a):        print "test start"        func(a)        print "end start"    return wraper@parameter_testdef parameter_foo(a):    print "parameter_foo:" + a    # parameter_foo('hello')parameter_foo('12')

不确定参数个数

def much_test(func):    def wraper(*args, **kwargs):        print "test start"        func(*args, **kwargs)        print "end start"    return wraper@much_testdef much1(a):    print a@much_testdef much2(a, b, c, d):    print a, b, c, dmuch1('a')much2(1, 2, 3, 4)

综合应用

# coding=utf-8class mylocker:    def __init__(self):        print("mylocker.__init__() called.")    @staticmethod    def acquire():        print("mylocker.acquire() called.")    @staticmethod    def unlock():        print(" mylocker.unlock() called.")class lockerex(mylocker):    @staticmethod    def acquire():        print("lockerex.acquire() called.")    @staticmethod    def unlock():        print(" lockerex.unlock() called.")def lockhelper(cls):    '''cls 必须实现acquire和release静态方法'''    def _deco(func):        def __deco(*args, **kwargs):            print("before %s called." % func.__name__)            cls.acquire()            try:                return func(*args, **kwargs)            finally:                cls.unlock()        return __deco    return _decoclass example:    @lockhelper(mylocker)    def myfunc(self):        print(" myfunc() called.")    @lockhelper(mylocker)    @lockhelper(lockerex)    def myfunc2(self, a, b):        print(" myfunc2() called.")        return a + bif __name__ == "__main__":    a = example()    a.myfunc()    print(a.myfunc())    print(a.myfunc2(1, 2))    print(a.myfunc2(3, 4))

形式参数

python 函数的形参集合由在调用时要传入函数的所有参数组成,这参数与函数声明中的参数列表精确的配对。这些参数包括了所有必要参数(以正确的定位顺序来传入函数的),关键字参数(以 顺序或者不按顺序传入,但是带有参数列表中曾定义过的关键字),以及所有含有默认值,函数调用 时不必要指定的参数。(声明函数时创建的)局部命名空间为各个参数值,创建了一个名字。一旦函数开始执行,即能访问这个名字。

位置参数

默认参数

对于默认参数如果在函数调用时没有为参数提供值则使用预先定义的的默认值。

def func(posargs, defarg1=dval1, defarg2=dval2,...):    "function_documentation_string"    function_body_suite

可变长度的参数

  1. 非关键字可变长参数(元组)
  2. 关键字变量参数(Dictionary)

函数式编程

匿名函数与 lambda

python 允许用 lambda 关键字创造匿名函数。匿名是因为不需要以标准的方式来声明,比如说, 使用 def 语句。(除非赋值给一个局部变量,这样的对象也不会在任何的名字空间内创建名字.)然而, 作为函数,它们也能有参数。一个完整的 lambda“语句”代表了一个表达式,这个表达式的定义体 必须和声明放在同一行。我们现在来演示下匿名函数的语法:lambda [arg1[, arg2, ... argN]]: expression 参数是可选的,如果使用的参数话,参数通常也是表达式的一部分。

例:

def add(x, y): return x + y ? lambda x, y: x + y

内建函数apply()、filter()、map()、reduce()

lambda 函数可以很好的和使用了这些函数的应用程序结合起来,因为它们都带了一个可执行的函数 对象,lambda 表达式提供了迅速创造这些函数的机制。

内建函数 描述 apply(func[, nkw][, kw]) 用可选的参数来调用 func,nkw 为非关键字参数,kw 关键字参数;返回值是函数调用的返回值。 filter(func, seq) 调用一个布尔函数 func 来迭代遍历每个 seq 中的元素; 返回一个使 func 返回值为 ture 的元素的序列。 map(func,seq1[,seq2...]) 将函数func作用于给定序列(s)的每个元素,并用一个列表来提供返回值;如果 func 为 None, func 表现为一个身份函数,返回一个含有每个序列中元素集合的 n 个元组的列表。 reduce(func, seq[, init]) 将二元函数作用于 seq 序列的元素,每次携带一对(先前的结果 以及下一个序列元素),连续的将现有的结果和下雨给值作用在获 得的随后的结果上,最后减少我们的序列为一个单一的返回值;如 果初始值 init 给定,第一个比较会是 init 和第一个序列元素而不是序列的头两个元素。

例:

>>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]>>>>>> print filter(lambda x: x % 3 == 0, foo)[18, 9, 24, 12, 27]>>>>>> print map(lambda x: x * 2 + 10, foo)[14, 46, 28, 54, 44, 58, 26, 34, 64]>>>>>> print reduce(lambda x, y: x + y, foo)139

变量作用域

全局变量与局部变量

“声明适用的程序的范围被称为了声明的作用域。在一个过程中,如果名字在过程的声明之内, 它的出现即为过程的局部变量;否则的话,出现即为非局部的“

模块

正则表达式

请参考正则表达式(regular expression)以及常用语法

使用示例:

# coding=utf-8import redef run(para):    para = str(para)    result = re.match('\d{11}|\d{3,4}-\d{7,8}', para)    if result is not None:        print '这是电话号码:', result.group()        return    else:        result = re.match('\d+(\.\d*)?', para)        if result is not None:            print '这是浮点数:', result.group()            return        else:            result = re.search('(Mr?s?\. )?[A-Z][a-z]* [ A-Za-z-]+', para)            if result:                print '这是名称和姓氏:', result.group()                sub = re.sub('X', para, 'attn: X\n\nDear X,\n')                print sub                return            else:                result = re.match('\w+@(\w+\.)?\w+\.com', para)                if result is not None:                    print '这是邮箱地址:', result.group();                    returnif __name__ == '__main__':    run(123.123)    run(12345678900)    run('Mr A')    run('wsywno1@126.com')

RE 编译(何时应该使用 compile 函数?)

Python 的代码最终会被编译为字节码,然后才被解释器执行。调用 eval() 或 exec()调用一个代码对象而不是一个字符串,在性能上会有明显地提升, 这是因为对前者来说, 编译过程不必执行。换句话说,使用预编译代码对象要比使用字符串快,因为解释器在执行字符串形式的代码前必须先把它编译成代码对象。

这个概念也适用于正则表达式,在模式匹配之前,正则表达式模式必须先被编译成 regex 对象。由于正则表达式在执行过程中被多次用于比较,我们强烈建议先对它做预编译,而且既然正则表达式的编译是必须的,那使用么预先编译来提升执行性能无疑是明智之举。re.compile() 就是用提供此功能的。

其实模块函数会对已编译对象进行缓存,所以不是所有使用相同正则表达式模式的 search()和 match()都需要编译。即使这样,你仍然节省了查询缓存和用相同的字符串反复调用函数的性能开销。

搜索与匹配的比较

match()尝试从字符串起始处进行匹配模式。search() 查找字符串 中模式首次出现的位置,而不是尝试(在起始处)匹配。严格地说,search() 是从左到右进行搜索。


参考资料:
Python核心编程
备注:
转载请注明出处:http://blog.csdn.net/wsyw126/article/details/54563323
作者:WSYW126

0 0
原创粉丝点击