总结Python编程中函数的使用要点


Posted in Python onMarch 20, 2016

为何使用函数

  • 最大化代码的重用和最小化代码冗余
  • 流程的分解

编写函数

>>def语句
在Python中创建一个函数是通过def关键字进行的,def语句将创建一个函数对象并将其赋值给一个变量名。def语句一般的格式如下所示:

def <name>(arg1,arg2,... argN):
  <statements>

通常情况下,函数体中会有一个return语句,可以出现在函数体的任何位置,它表示函数调用的结束,并将结果返回至函数调用处。但是return语句是可选的,并不是必须的。从技术角度上说,一个没有返回值的函数自动返回了none对象,但是这个值可以被忽略掉。

>>def语句是实时执行的
Python的def语句实际上是一个可执行的语句:当它运行的时候,它创建一个新的函数对象并将其赋值给一个变量名。(请记住,Python中所有的语句都是实时运行的,没有对像独立编译时间这样的流程)因为它是一个语句,它可以出现在任一语句可以出现的地方——甚至是嵌套在其他语句中。

if test:
  def func():
    ...
else:
  def func():
    ...
...
func()

它在运行时简单地给一个变量名进行赋值。与C语言这样的编译语言不同,Python函数在程序运行之前并不需要全部定义,更确切地说,def在运行时才评估,而在def之中的代码在函数调用时才会评估。

就像Python中其他语句一样,函数仅仅是对象,在程序执行时它清除地记录在了内存之中。实际上,除了调用之外,函数允许任意的属性附加到记录信息以供随后使用:

othername=func #Assign function object
othername() #Call func again

func() #call object
func.attr=value #attach attribute

一个例子:定义和调用

def times(x,y):
  return x*y

times(2,4) #return 8
times(3.12,4) #return 12.56
times('Ni',4) #return 'NiNiNi'

上面代码中对函数的三次调用都能正确运行,因为”*“对数字和序列都有效,在Python我们从未对变量、参数或者返回值有过类似的声明,我们可以把times用作数字的乘法或是序列的重复。

换句话说,函数times的作用决定于传递给它的参数,这是Python的核心概念之一。

需要强调的是,如果我们传入了一个不支持函数操作的参数,Python会自动检测出不匹配,并抛出一个异常,这样就能减少我们编写不必要的类型检测代码。

>>局部变量
所有在函数内部定义的变量默认都是局部变量,所有的局部变量都会在函数调用时出现,并在函数退出时消失。

函数设计概念

  • 耦合性:对于输入使用参数并且输出使用return语句。
  • 耦合性:只有在真正必要的情况下使用全局变量。
  • 耦合性:不要改变可变类型的参数,除非调用者希望这样做。
  • 聚合性:每一个函数都应该有一个单一的、统一的目标。
  • 大小:每一个函数应该相对较小。
  • 耦合:避免直接改变在另一个模块文件中的变量。
  • 函数对象:属性和注解

>>间接函数调用
由于Python函数是对象,我们可以编写通用的处理他们的程序。函数对象可以赋值给其他的名字、传递给其他函数、嵌入到数据结构、从一个函数返回给另一个函数等等,就好像它们是简单的数字或字符串。

把函数赋值给其他变量:

def echo(message):
 print(message)

x = echo
x('Indirect call!')  #Prints:Indirect call!

传递给其他函数:

def indirect(func,arg):
  func(arg)

indirect(echo,'Argument call')  #Prints:Argument call

把函数对象填入到数据结构中:

schedule=[(echo,'Spam!'),(echo,'Ham!')]
for (func,arg) in schedule:
  func(arg)

从上述的代码中可以看到,Python是非常灵活的!

>>函数内省
由于函数是对象,我们可以用用常规的对象工具来处理函数。

func.__name__
dir(func)

内省工具允许我们探索实现细节,例如函数已经附加了代码对象,代码对象提供了函数的本地变量和参数等方面的细节:

dir(func.__code__)
func.__code__.co_varnames
func.__code__.co_argument

工具编写者可以利用这些信息来管理函数。

>>函数属性
函数对象不仅局限于上一小节中列出的系统定义的属性,我们也可以向函数附加任意的用户定义的属性:

func.count=0
func.count+=1

func.handles='Button-Press'

这样的属性可以用来直接把状态信息附加到函数对象,而不必使用全局、非本地和类等其他技术。和非本地不同,这样的属性信息可以在函数自身的任何地方访问。这种变量的名称对于一个函数来说是本地的,但是,其值在函数退出后仍然保留。属性与对象相关而不是与作用域相关,但直接效果是类似的。

>>Python3.0中的函数注解
在Python3.0也可以给函数对象附加注解信息——与函数的参数相关的任意的用户定义的数据。Python为声明注解提供了特殊的语法,但是,它自身不做任何事情;注解完全是可选的,并且,出现的时候只是直接附加到函数对象的__annotations__属性以供其他用户使用。

从语法上讲,函数注解编写在def头部行,对于参数,它们出现在紧随参数名之后的冒号之后;对于返回值,它们编写于紧跟在参数列表之后的一个->之后。

def func(a:'spam',b:(1,10),c:float) -> int:
  return a+b+c

注解和没注解过的函数在功能和使用上完全一样,只不过,注解过的函数,Python会将它们的注解的数据收集到字典中并将它们附加到函数对象自身。参数名变成键,如果编写了返回值注解的话,它存储在键return下,而注解的值则是赋给了注解表达式的结果:

func.__annotations__
 #Prints:{'a':'spam','c':<class 'float'>,'b':(1,10),'return':<class 'int'>}

注意点

如果编写了注解的话,仍然可以对参数使用默认值,例如:a:'spam'=4 意味着参数a的默认值是4,并且用字符串'spam'注解它。
在函数头部的各部分之间使用空格是可选的。
注解只在def语句中有效。
匿名函数:lambda

除了def语句之外,Python还提供了一种生成函数对象的表达式形式。由于它与LISP语言中的一个工具很相似,所以称为lambda。就像def一样,这个表达式创建了一个之后能够调用的函数,但是它返回了一个函数而不是将这个函数赋值给一个变量名。这也就是lambda有时叫做匿名函数的原因。实际上,它们常常以一个行内函数定义的形式使用,或者用作推迟执行一些代码。

>>lambda表达式
lambda的一般形式是关键字lambda,之后是一个或多个参数,紧跟的是一个冒号,之后是一个表达式:

lambda argument1,argument2,...argumentN:expression using arguments

由lambda表达式所返回的函数对象与由def创建并赋值后的函数对象工作起来是完全一样的,但是lambda有一些不同之处让其在扮演特定的角色时很有用。

lambda是一个表达式,而不是一个语句。
lambda的主体是一个单个的表达式,而不是一个代码块。
一下两段代码生成了同样功能的函数:

def func(x,y,z):return x+y+z
func(2,3,4)          #Return 9

f = lambda x,y,z : x + y + z
f(2,3,4)           #Return 9

默认参数也能在lambda中使用

x=(lambda a="fee",b="fie",c="foe": a+b+c)
x("wee")           #Prints:'weefiefoe'

在lambda主体中的代码像在def内的代码一样都遵循相同的作用域查找法则。

>>为什么要使用lambda
通常来说,lambda起到了一种函数速写的作用,允许在使用的代码内嵌入一个函数的定义。它们总是可选的,因为总是能够用def来代替。

lambda通常用来编写跳转表:

L=[lambda x: x ** 2,
  lambda x: x ** 3,
  lambda x: x ** 4]

for f in L:
 print(f(2))      #Prints:4,8,16
print(L[0](3))      #Prints:9

实际上,我们可以用Python中的字典或者其他数据结构来构建更多种类的行为表:

key='got'
{'already':(lambda: 2+2),
 'got':(lambda: 2*4),
 'one':(lambda: 2 ** 6)}[key]()     #Prints:8

这样编写代码可以使字典成为更加通用的多路分支工具。

最后需要注意的是,lambda也是可以嵌套的

((lambda x:(lambda y: x+y))(99))(4)   #Prints:103

在序列中映射函数:map

map函数会对一个序列对象中的每个元素应用被传入的函数,并且返回一个包含了所有函数调用结果的一个列表。

counters=[1,2,3,4]
def inc(x):return x+10
list(map(inc,counters))     #[11,12,13,14]

由于map期待传入一个函数,它恰好是lambda最常出现的地方之一。

list(map((lambda x: x+10),counters)) #[11,12,13,14]

函数式编程工具:filter和reduce

在Python内置函数中,map函数是用来进行函数式编程的这类工具中最简单的内置函数代表。所谓的函数式编程就是对序列应用一些函数的工具。例如过滤出一些元素(filter),以及对每对元素都应用函数并运行到最后的结果(reduce)。

list(filter((lambda x: x>0),range(-5,5)))  #[1,2,3,4]

序列中的元素若其返回值是真的话,将会被加入到结果列表中。

reduce接受一个迭代器来处理,但是,它自身不是一个迭代器,它返回一个单个的结果。

from functools import reduce  #Import in 3.0,not in 2.6
reduce((lambda x,y: x+y),[1,2,3,4]) #Return:10
reduce((lambda x,y: x*y),[1,2,3,4]) #Return:24

上面两个reduce调用,计算了一个列表中所有元素的累加和与累积乘积。

Python 相关文章推荐
Python实现partial改变方法默认参数
Aug 18 Python
深入解析Python中的变量和赋值运算符
Oct 12 Python
python开发中module模块用法实例分析
Nov 12 Python
python3 pillow生成简单验证码图片的示例
Sep 19 Python
通过pykafka接收Kafka消息队列的方法
Dec 27 Python
python如何删除文件中重复的字段
Jul 16 Python
python中tkinter的应用:修改字体的实例讲解
Jul 17 Python
Python发送邮件的实例代码讲解
Oct 16 Python
Python合并2个字典成1个新字典的方法(9种)
Dec 19 Python
Python3 pyecharts生成Html文件柱状图及折线图代码实例
Sep 29 Python
写好Python代码的几条重要技巧
May 21 Python
如何理解及使用Python闭包
Jun 01 Python
两个命令把 Vim 打造成 Python IDE的方法
Mar 20 #Python
Python中列表、字典、元组数据结构的简单学习笔记
Mar 20 #Python
Python的Socket编程过程中实现UDP端口复用的实例分享
Mar 19 #Python
使用Python编写基于DHT协议的BT资源爬虫
Mar 19 #Python
浅析Python基础-流程控制
Mar 18 #Python
浅析Python编写函数装饰器
Mar 18 #Python
python正则表达式之作业计算器
Mar 18 #Python
You might like
深入解析PHP的引用计数机制
2013/06/14 PHP
php 判断字符串中是否包含html标签
2014/02/17 PHP
Symfony页面的基本创建实例详解
2015/01/26 PHP
php中curl使用指南
2015/02/05 PHP
PHP实现获取毫秒时间戳的方法【使用microtime()函数】
2019/03/01 PHP
jQuery textarea的长度进行验证
2009/05/06 Javascript
使用FlexiGrid实现Extjs表格效果方法分享
2014/12/16 Javascript
浅谈JSON中stringify 函数、toJosn函数和parse函数
2015/01/26 Javascript
Js控制滑轮左右滑动实例
2015/02/13 Javascript
javascript手风琴下拉菜单实现代码
2015/11/12 Javascript
Jquery 效果使用详解
2015/11/23 Javascript
初识 Vue.js 中的 *.Vue文件
2017/11/22 Javascript
vue 组件使用中的一些细节点
2018/04/25 Javascript
利用Dectorator分模块存储Vuex状态的实现
2019/02/05 Javascript
使用jquery的cookie实现登录页记住用户名和密码的方法
2019/03/13 jQuery
微信小程序实现带参数的分享功能(两种方法)
2019/05/17 Javascript
Python使用htpasswd实现基本认证授权的例子
2014/06/10 Python
python基于xml parse实现解析cdatasection数据
2014/09/30 Python
Python使用Matplotlib实现Logos设计代码
2017/12/25 Python
python正则表达式匹配[]中间为任意字符的实例
2018/12/25 Python
对Python 两大环境管理神器 pyenv 和 virtualenv详解
2018/12/31 Python
Python 3.3实现计算两个日期间隔秒数/天数的方法示例
2019/01/07 Python
对Python使用mfcc的两种方式详解
2019/01/09 Python
在python中实现求输出1-3+5-7+9-......101的和
2020/04/02 Python
scrapy头部修改的方法详解
2020/12/06 Python
美国床垫连锁店:Mattress Firm
2021/02/13 全球购物
Oracle中delete,truncate和drop的区别
2016/05/05 面试题
电焊工岗位职责
2014/03/06 职场文书
运动会广播稿200米(5篇)
2014/10/15 职场文书
导师工作推荐信
2015/03/27 职场文书
公司员工辞职信范文
2015/05/12 职场文书
母亲去世追悼词
2015/06/23 职场文书
积极心理学课程心得体会
2016/01/22 职场文书
MySQL中int (10) 和 int (11) 的区别
2022/01/22 MySQL
flex布局中使用flex-wrap实现换行的项目实践
2022/06/21 HTML / CSS
Linux下搭建SFTP服务器的命令详解
2022/06/25 Servers