Python之--自定义函数:

在Python中,定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。

以下自定义一个函数用于判断一个人是成年人好事青少年:

 >>> def judge_person(age):
... if age < 18:
... print("teenager!")
... else:
... print("adult!")
...
>>> judge_person(12)
teenager!
>>> judge_person(23)
adult!
>>>

请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为None

return None可以简写为return

 >>> def get_age(age):
... if age > 18:
... return "older"
... else:
... return
...
>>> get_age(12)
>>> get_age(56)
'older'
>>>

空函数:

  什么叫做”空函数“?所谓的空函数就是你定义一个函数,但是什么也不用做,就是定义了一个空函数!例如:

 >>> def Empty():
... pass
...
>>> def Empty2():
... pass
...
>>>

pass语句什么都不做,那有什么用?实际上pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。

pass还可以用在其他语句里,比如:

 >>> age = 90
>>> if age:
... pass
...
>>> #如果没有pass就会报错。
...
>>> if age:
...
File "<stdin>", line 2 ^
IndentationError: expected an indented block
>>>

调用函数时,如果参数个数不对,Python解释器会自动检查出来,并抛出TypeError

但是如果参数类型不对,Python解释器就无法帮我们检查。

当传入了不恰当的参数时,内置函数abs会检查出参数错误,而我们定义没有参数检查,所以,这个函数定义不够完善。

以下定义一个求绝对值的函数:

 >>> def get_abs(value):
... if value < 0:
... return -value
... else:
... return value >>> get_abs(2)
2
>>> get_abs(-3)
3
>>> get_abs(0)
0
>>>

让我们修改一下我们函数定义get_abs,对参数类型做检查,只允许整数和浮点数类型的参数。数据类型检查可以用内置函数isinstance实现:

 >>> get_abs(dada)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'dada' is not defined
>>> #在没有进行参数检查之前,报出了一个NameError:的错误
... #以下我们对函数进行参数检查,提高函数的健壮性。
...
>>> def get_abc(value):
... if not isinstance(value,(int,float)):
... raise TypeError('参数类型不对,不好意思啊!')
... if value >= 0:
... return value
... else:
... return -value
...
>>> #传入正确的参数:
...
>>> get_abc(12)
12
>>> get_abc(-12)
12
>>> #传入错误的参数:
>>> get_abc('gn')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in get_abc
TypeError: 参数类型不对,不好意思啊!
>>>

返回多个值:

比如在游戏中经常需要从一个点移动到另一个点,给出坐标、位移和角度,就可以计算出新的新的坐标:

 import math

 def move(x, y, step, angle=0):
nx = x + step * math.cos(angle)
ny = y - step * math.sin(angle)
return nx, ny

例子:

 >>> import math
>>>
>>> def move(x,y,step,angle = 0):
... nx = x + step*math.cos(angle)
... ny = y - step*math.sin(angle)
... return nx,ny
...
>>> x1,y1 = move(100,10,60,math.pi/6)
>>> print x1,y1
151.961524227 -20.0
>>>

其实,返回的值是一个元组(tuple)。

函数的参数:

定义函数的时候,我们把参数的名字和位置确定下来,函数的接口定义就完成了。对于函数的调用者来说,只需要知道如何传递正确的参数,以及函数将返回什么样的值就够了,函数内部的复杂逻辑被封装起来,调用者无需了解。

Python的函数定义非常简单,但灵活度却非常大。除了正常定义的必选参数外,还可以使用默认参数、可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代码。

1.默认参数:

定义一个计算平方的函数:power()

 >>> def power(x):
... return x*x
...
>>> power(5)
25
>>> power(7)
49
>>>

当我们调用power函数时,必须传入有且仅有的一个参数x.但是此时我们要定义一个计算x的三次方甚至更多的次方该怎么办呢,或许聪明的读者已经想到了把power(x)修改为:power(x,n)实例如下:

 >>> def power(x,n):
... s = 1
... while n > 0:
... n = n-1
... s = s * x
... print s
...
>>> power(2,2)
4
>>> power(2,9)
512
>>> #但是此时想要使用power(x)求x的平方的话,该方法已经没有效果了。
...
>>> power(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: power() takes exactly 2 arguments (1 given)
>>> #此处我们可以引入默认参数来解决这个问题:
...
>>> def power(x,n = 2):
... s = 1
... while n > 0:
... n -= 1
... s *= x
... print s
...
>>> power(5,2)
25
>>> power(5)
25
>>> #这样就可以实现效果了!是不是很帅!

而对于n > 2的其他情况,就必须明确地传入n,比如power(5, 3)

从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意:

一是必选参数在前,默认参数在后,否则Python的解释器会报错(思考一下为什么默认参数不能放在必选参数前面);

二是如何设置默认参数。

当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。

使用默认参数有什么好处?最大的好处是能降低调用函数的难度。

可见,默认参数降低了函数调用的难度,而一旦需要更复杂的调用时,又可以传递更多的参数来实现。无论是简单调用还是复杂调用,函数只需要定义一个。

默认参数虽然可以带来很大的便利,但是也有一个相当大的弊端:

先定义一个函数,传入一个list,添加一个END再返回:

 >>> def add_end(L=[]):
... L.append(['END'])
... return L
...
>>> add_end([1,2,3])
[1, 2, 3, ['END']]
>>> add_end(['x','y','z'])
['x', 'y', 'z', ['END']]
>>> #当你使用默认参数的时候,刚开始是对的:
...
>>> add_end()
[['END']]
>>> #但是再次调用add_end()时,结果就不对了
...
>>> add_end()
[['END'], ['END']]
>>> add_end()
[['END'], ['END'], ['END']]
>>>

默认参数是[],但是函数似乎每次都“记住了”上次添加了'END'后的list。这是为什么呢?

Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。

所以,定义默认参数要牢记一点:默认参数必须指向不变对象!

要修改上面的例子,我们可以用None这个不变对象来实现:

 >>> def add_end(L = None):
... if L is None:
... L = []
... L.append('END')
... return L
...
>>> #演示:
...
>>> add_end()
['END']
>>> add_end()
['END']
>>> add_end()
['END']
>>>

为什么要设计str、None这样的不变对象呢?因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象 不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。

2. 可变参数:

在Python函数中可以传入默认参数,但是也可以传入可变参数.不难理解,可变参数的含义就是说,参数的个数时可以改变的,可以是1个、2个到任意个,还可以是0个。

我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。

要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:

在没有使用可变参数的情况:

 >>> def get_value(numbers):
... sum = 0
... for n in numbers:
... sum += n * n
... return sum
...
>>> #但是调用的时候要先拼接一个元组或者列表
...
>>> get_value([1,2,3,4,5,6,7,8,9,10])
385
>>> get_value((1,2,3,3,4,5,6))
100

使用可变参数,把函数修改为如下:

 >>> def get_value(*numbers):
... sum = 0
... for n in numbers:
... sum += n*n
... return sum
...
>>> get_value(1,2,3,4,5,6)
91

定义可变参数和定义list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:

>>> get_value(1) 1 >>> get_value(0) 0

但是,当你传入一个列表或者元组会出现错误:

 >>> get_value([1,2,3,4,5,6])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in get_value
TypeError: can't multiply sequence by non-int of type 'list'
>>> get_value((1,2,3,4,5,6))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in get_value
TypeError: can't multiply sequence by non-int of type 'tuple'
>>>

可以这样解决列表和元组的问题:

 >>> list1 = [8,9]
>>> tuple1 = (1,2,3)
>>> list1
[8, 9]
>>> tuple1
(1, 2, 3)
>>> get_value(list1[0],list1[1])
145
>>> get_value(tuple1[0],tuple1[1],tuple1[2])
14
>>>

但是,这种方法不是最好的,假如元组或者列表很大的时候就会出现工作量的问题,因此有一个更好的办法就是:Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

 >>> list1
[8, 9]
>>> tuple1
(1, 2, 3)
>>> get_value(*tuple1)
14
>>> get_value(*list1)
145
>>>

有木有感觉python真的是无可挑剔啊,确实是这样的。

3. 关键字参数:

可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例:

 >>> def person(name,age,**kw):
... print 'name:',name,'age:',age,'other:',kw
...
>>> #函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:
...
>>> person('lt',20)
name: lt age: 20 other: {}
>>>

也可以传入任意个关键字参数:

 >>> person('lt',20,city = 'shanghai',height = 178,love = 'lt')
name: lt age: 20 other: {'city': 'shanghai', 'love': 'lt', 'height': 178}
>>> person('lt',20,city = 'shanghai',height = 178,love = 'lt',salary = 200000)
name: lt age: 20 other: {'salary': 200000, 'city': 'shanghai', 'love': 'lt', 'height': 178}
>>>

关键字参数有什么用?它可以扩展函数的功能。比如,在person函数里,我们保证能接收到nameage这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。

和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

 >>> kw = {'name':'lt','city':'shanghai','hometown':'xinnong','age':20}
>>> kw
{'city': 'shanghai', 'age': 20, 'name': 'lt', 'hometown': 'xinnong'}
>>> person('jack',20,city=kw['city'],hometown = kw['hometown'])
name: jack age: 20 other: {'city': 'shanghai', 'hometown': 'xinnong'}

但是,更简单便捷的方法时这样的:

 >>> kw = {'city':'shanghai','hometown':'xingnong'}
>>> kw
{'city': 'shanghai', 'hometown': 'xingnong'}
>>> person('Jack',12,**kw)
name: Jack age: 12 other: {'city': 'shanghai', 'hometown': 'xingnong'}
>>>

4.参数组合:

在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数和关键字参数。

比如定义一个函数,包含上述4种参数:

 >>> def func(a,b,c=0,*args,**kw):
... print 'a=',a,'b=',b,'c=',c,'args = ',args,'kw = ',kw
...
>>> func(1,2)
a= 1 b= 2 c= 0 args = () kw = {}
 >>> func(1,2,c=3)
a= 1 b= 2 c= 3 args = () kw = {}
>>> func(1,2,3,'a','b')
a= 1 b= 2 c= 3 args = ('a', 'b') kw = {}
>>> func(1,2,3,'a','b',x = 45,y = 65,z = 32)
a= 1 b= 2 c= 3 args = ('a', 'b') kw = {'y': 65, 'x': 45, 'z': 32}
>>>

最神奇的是通过一个tuple和dict,你也可以调用该函数:

 >>> args = (1, 2, 3, 4)
>>> kw = {'x': 99}
>>> func(*args, **kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'x': 99}

所以,对于任意函数,都可以通过类似func(*args, **kw)的形式调用它,无论它的参数是如何定义的。

python学习之--自定义函数:的更多相关文章

  1. MySQL学习——操作自定义函数

    MySQL学习——操作自定义函数 摘要:本文主要学习了使用DDL语句操作自定义函数的方法. 了解自定义函数 是什么 自定义函数是一种与存储过程十分相似的过程式数据库对象.它与存储过程一样,都是由SQL ...

  2. Python学习之路——函数

    一.Python2.X内置函数表: 注:以上为pyton2.X内置函数,官方网址:https://docs.python.org/2/library/functions.html 二.Python3. ...

  3. Python学习笔记 - day6 - 函数

    函数 函数在编程语言中就是完成特定功能的一个词句组(代码块),这组语句可以作为一个单位使用,并且给它取一个名字.可以通过函数名在程序的不同地方多次执行(这叫函数的调用).函数在编程语言中有基本分为:预 ...

  4. Python学习笔记之函数

    这篇文章介绍有关 Python 函数中一些常被大家忽略的知识点,帮助大家更全面的掌握 Python 中函数的使用技巧 1.函数文档 给函数添加注释,可以在 def 语句后面添加独立字符串,这样的注释被 ...

  5. Python 学习:常用函数整理

    整理Python中常用的函数 一,把字符串形式的list转换为list 使用ast模块中的literal_eval函数来实现,把字符串形式的list转换为Python的基础类型list from as ...

  6. 【Python学习之五】函数

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 python3.6 Python不但能非常灵活地定义函数,而且本身内置 ...

  7. Python学习-第一天-函数和模块的使用

    目录 Python学习-第一天总结 print输出的一种简单格式 函数参数之可变参数 模块管理函数 if else语句的单行实现(简洁) 变量作用域 函数书写格式 Python学习-第一天总结 pri ...

  8. python学习道路(day4note)(函数,形参实参位置参数匿名参数,匿名函数,高阶函数,镶嵌函数)

    1.函数 2种编程方法 关键词面向对象:华山派 --->> 类----->class面向过程:少林派 -->> 过程--->def 函数式编程:逍遥派 --> ...

  9. python学习-day16:函数作用域、匿名函数、函数式编程、map、filter、reduce函数、内置函数r

    一.作用域 作用域在定义函数时就已经固定住了,不会随着调用位置的改变而改变 二.匿名函数 lambda:正常和其他函数进行配合使用.正常无需把匿名函数赋值给一个变量. f=lambda x:x*x p ...

随机推荐

  1. oracle学习----逻辑读

    1.物理读 当数据块第一次读取到,就会缓存到buffer cache 中,而第二次读取和修改该数据块时就在内存buffer cache 清空数据缓冲区 SQL> alter session se ...

  2. 删除sd卡的文件

    public static void deleteAllFile(){ String path = Environment.getExternalStorageDirectory().getAbsol ...

  3. iOS 并行编程:GCD Dispatch Sources

    1 简介 dispatch source是一种用于处理事件的数据类型,这些被处理的事件为操作系统中的底层级别.Grand Central Dispatch(GCD)支持如下的dispatch sour ...

  4. Linux common resources

    Useful Linux Web reources list Linux die manual Linux Man Pages Archive Linux RPM find Linux RPM Sea ...

  5. magento搜索属性值的设置方法

    前台特性(Frontend Properties)在快速搜索中应用(Use in quick search) - 开启此选项,在客户使用Header中的 搜索功能时Magento将搜索所有产品这个At ...

  6. CDOJ-10(栈的应用)

    In Galgame We Trust Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Othe ...

  7. w3c 学习html DOM

    什么是DOM? DOM是W3C标准,定义了访问HTML 和 XML文档的标准 W3C 文档对象模型(DOM)是中立于平台和语言接口,它允许程序动态的访问和更新文档的内容.结构和样式. W3C DOM ...

  8. MVC小系列(二)【Razor 模板引擎】

    Razor 模板引擎 Razor模板页:它使我们不用再使用master模板了 一 :@Url.Content:是可以加载CSS和JS等文件比如: <link href="@Url.Co ...

  9. Oracle之Merge用法

    Merge用来从一个表中选择一些数据更新或者插入到另一个表中.而最终是用更新还是用插入的方式取决于该语句中的条件. 下面我们简单的举一个例子: SQL)) 表已创建. SQL)) 表已创建. SQL, ...

  10. SVN的那些事

    1,终端报错:is too old (format 29) to work with client version '1.9.4 (r1740329)' (expects format 31). Yo ...