[关闭]
@jk88876594 2017-06-20T01:26:57.000000Z 字数 6780 阅读 2062

函数

阿雷边学边教python数据分析第2期——python基础


1.什么是函数

函数就是一个魔术箱,你可以把你要处理的对象放进去,然后它就会给你希望得到的结果。因此当你需要完成特定的任务时,你可以通过函数来帮你获得处理结果。
例如:我希望将一个负数转化成正数,那么abs()函数就能帮我快速地实现这个任务

  1. abs(-3)
3

2.调用函数

调用函数就是指我们通过输入函数名称并向括号内传递正确的参数,从而实现对函数的调用。

还是以abs()为例,当我希望将负数转成正数时,我会调用abs()函数时,此时我就必须输入正确的参数,这样才能保证abs()函数正常运转,如果输入了错误的参数,则会出错。

  1. abs("aaa")
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-20-6fc10118d3fb> in <module>()
----> 1 abs("aaa")

TypeError: bad operand type for abs(): 'str'

那么将会报错,因为字符串没有正负之分,传入的字符串并不符合abs()函数的参数要求,如果你不了解abs()函数,那么可以通过abs?的方式来查看帮助文档,这是一种非常有效的帮助我们理解一个函数的学习方式。

  1. abs?
Signature: abs(x, /)
Docstring: Return the absolute value of the argument.
Type:      builtin_function_or_method
  1. abs([-3,-1,-10])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-45de7925eef1> in <module>()
----> 1 abs([-3,-1,-10])

TypeError: bad operand type for abs(): 'list'

我们发现abs并不能作用于列表,难道就实现不了了吗,并不是,既然abs的参数只能是数值类型,那么我们可以通过循环来实现我们的目的:

  1. [abs(number) for number in [-3,-1,-10]]
[3, 1, 10]

总结一下

  • 当我们需要快速地完成某件任务时,我们可以通过相应功能的函数来帮助我们实现,并且在调用函数时我们需要知道的两点:
    1.相应功能的函数名
    2.输入正确的参数
  • 如果你不知道什么函数能帮助你实现你的任务,你可以到以下地址查看python自带的函数
    python内建函数

  • 如果自带的函数也无法满足你的需求时,那么你可以自定义创建满足你需求的函数,至于如何创建,待会会讲

  • 如果你知道了一个函数具有实现你需求的功能,但是你不知道怎么使用时,有两种做法:
    1.在python中通过运行函数名?的这种形式(如abs?),来查看帮助文档,如果看不懂,可以通过翻译来理解大致意思
    2.通过搜索引擎(谷歌,百度等)来得到帮助

3.自定义函数

当python自带的函数都无法满足我们需求时,我们需要自己来创建自定义函数了。

函数.png-50.8kB
def:即定义的意思,是define的缩写,它的作用是定义一个函数,也即创建函数,通过def关键词,我们向python指出了函数名,并且在括号内指出函数为了完成其任务所需要的信息。

function:函数名,应选择一个尽可能简洁地描述清楚函数作用的名称。

arg:即参数的意思,是argument的缩写,在没有具体的值传入以前,arg是形参,是一个空壳子,它的作用就是存储传入进来的实参,即实际的参数,装载了实参后的形参会被当做材料一样被函数吸收进去,再经过函数的一系列操作后,产生相应的结果。

文档字符串:用三引号括起来,里面写上关于该函数的作用,以此来生成有关该函数的文档。

return:能够返回结果,即返回一个值或一组值。

整体解读下这个定义函数的公式,即:定义一个名为function的函数,它有两个参数arg1、arg2(当然也可以更多),经过一系列代码操作,最终返回相应的结果

更形象地来理解定义函数的公式
形象说明函数.png-174.2kB

例如:我们来创建一个根据直角三角形直角的两边a和b来求第三边c的函数,即勾股定理
1.jpg-12.1kB

  1. def c_length(a,b):
  2. """返回直角三角形的斜边长度"""
  3. c = (a ** 2 + b ** 2) ** 0.5
  4. return c
  5. c_length(3,4)
5.0

4.传递参数

先了解两个概念:形参和实参
在定义c_length函数时,变量a和b就是形参,函数完成其工作需要材料,而形参就是存储材料的壳子。而在我们调用函数c_length(3,4)时,所输入的3和4就是实参,实参就是在调用函数时传递给函数的具体信息,3和4作为实参会被存储在形参里,然后被函数吸收掉,从而产生结果。

(1)位置参数

要求传入的实参顺序与形参顺序一样,也就是基于形参的顺序将每一个实参都关联到函数定义中的形参中。

例如,我们需要打印出一个考生的基本信息:

  1. def message(name,gender,grade):
  2. """打印出一个考生的基本信息"""
  3. print("我的名字是:" + name + "\n性别:" + gender + "\n成绩:" + str(grade))
  4. message("利威尔","男",100)
我的名字是:利威尔
性别:男
成绩:100

位置参数要求函数调用中的实参按照顺序关联到形参中,如果顺序错了,那么得到的结果可能会很滑稽

(2)关键字参数

要求实参和形参直接对应上,即以某形参名称=某实参的形式填写参数,这样就无需考虑顺序了。

依然以前面的例子为例,我们通过关键字参数的方式输入另一个考生的基本信息:

  1. def message(name,gender,grade):
  2. """打印出一个考生的基本信息"""
  3. print("我的名字是:" + name + "\n性别:" + gender + "\n成绩:" + str(grade))
  4. message(gender = "女",grade = 100,name = "mikasa")
我的名字是:mikasa
性别:女
成绩:100

使用关键字参数,必须准确地写出函数定义中的形参名,并与对应的实参配对好

(3)默认参数

在定义函数时,可以给形参指定默认值,如果在调用函数时给形参提供了实参,此时python会使用给定的实参值,如果没有提供实参,那么就使用默认值。这种做法可以简化函数调用过程。

依然以输入基本信息的例子为例,假设对象大部分都是男生,那么我们可以给性别设定默认值为男:

  1. def message(name,grade,gender = "男"):
  2. """打印出一个考生的基本信息"""
  3. print("我的名字是:" + name + "\n性别:" + gender + "\n成绩:" + str(grade))
  1. message("艾伦",80)
我的名字是:艾伦
性别:男
成绩:80
  1. message("克里斯塔",85,"女")
我的名字是:克里斯塔
性别:女
成绩:85

相信你会产生一个疑问,为什么默认参数必须放在没有默认值参数的后面?

原因如下:
假设默认参数放在了前面,如message(name,gender = "男",grade),那么当我们调用message("路人甲",90)的时候,python不能判断现在应该得出

我的名字是:路人甲
性别:男
成绩:90

这种结果呢亦或是下面这种结果:

我的名字是:路人甲
性别:90

也就是说出现了歧义,因此默认参数必须放在没有默认值的参数(即必选参数)的后面。

使用默认值时,在形参列表里必须将没有默认值的形参也就是必选参数放在前面,将有默认值的形参放在后面,这样python就能够正确解读参数了。

(4)可变参数

有时候个别实参不确定需不需要,或者实参的个数不确定,那么此时就需要可变参数了。

  1. def name(first_name,middle_name,last_name):
  2. """得到大写的姓名"""
  3. full_name = first_name + " " + middle_name + " " + last_name
  4. return full_name.upper()
  5. name("jack","bally","damon")
'JACK BALLY DAMON'

但此时你可能想到一个问题,并非所有人都有中间名,那怎么办呢,这时就需要让中间名变成可选的,因此给形参middle_name指定一个默认值——空字符串,当用户没有提供中间名的时候就不用这个middle_name这个参数,做法如下:

  1. def name(first_name,last_name,middle_name = ""):
  2. """得到大写的姓名"""
  3. if middle_name:
  4. full_name = first_name + " " + middle_name + " " + last_name
  5. else:
  6. full_name = first_name + " " + last_name
  7. return full_name.upper()
  1. name("jack","baby")
'JACK BABY'
  1. name("jack","baby","lucy")
'JACK LUCY BABY'

例如,当我们需要计算1+2+3或者1+2+3+4+5或者更多的情况时,我们可以这么做:

  1. def super_sum(*numbers):
  2. s = 0
  3. for i in numbers:
  4. s = s + i
  5. return s
  1. super_sum(1,2,3)
6
  1. super_sum(1,2,3,4,5)
15

我们通过在形参前面加一个星号*,使得无论添加多少实参,*numbers都会统统把它们收入囊中,*numbers会创建出一个空元组tuple,将收到的所有值都装到这个元组中。

或者你会问,如果我已经有一个list或tuple,那我怎么把其中的元素都通过这个函数运算?你可以在函数括号内写入*list或者*tuple就能将list或tuple中的所有元素作为可变参数传进去。做法如下:

  1. list_1 = [1,2,3]
  2. super_sum(*list_1)
6
  1. tuple_1 = (2,4,6,8)
  2. super_sum(*tuple_1)
20

(5)生成dict的关键字参数

有时候,需要接受任意数量的实参,但是事先不确定会传递给函数哪些新增的信息,这种情况,你可以将函数编写成接受任意数量的键-值对,我们给函数提供了多少信息,它就接收多少。

例如,我们需要打印出一个考生的基本信息,但是每个考试的信息数量可能不一样:

  1. def complete_information(name,gender,grade,**others):
  2. """得到考生的完整信息"""
  3. information = {}
  4. information["name"] = name
  5. information["gender"] = gender
  6. information["grade"] = grade
  7. for key,value in others.items():
  8. information[key] = value
  9. return information
  10. complete_information("saber","female",100,age = 24,country = "古不列颠王国")
{'age': 24,
 'country': '古不列颠王国',
 'gender': 'female',
 'grade': 100,
 'name': 'saber'}

形参**others的两个星号创建了一个名为others的空字典dict,并将接收到的所有名称-值对都装到这个字典中,然后将这个字典转换成关键字参数返回给函数调用。生成dict的关键字参数有什么用呢?它的作用就是在确保能接收到name、gender、grade这3个必选参数的前提下,如果我们提供了更多的参数,那么我们也能接收到这些参数。换言之也就是能满足我们额外的需求。

(6)命名关键字参数

通过双星号**我们可以传入不受数量限制的关键字参数,那如果我们希望能有个限制,只传入我们希望传入的关键字参数,别的不准传入,这时候就需要命名关键字参数来帮助我们实现了。

  1. def complete_information(name,gender,grade,*,age,master):
  2. print(name,gender,grade,age,master)
  3. complete_information("saber","female",100,age = 24,master="shilang")
saber female 100 24 shilang

通过特殊分隔符,使得后面的参数成为命名关键字参数,这样就只接收*后面的参数作为关键字参数了。

(7)参数组合

前面提到的必选参数、默认参数、可变参数、命名关键字参数和关键字参数可以进行一些组合,它们的顺序优先级由前至后为:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
例如:

  1. def combind_args(x,y=2,*z,**kw):
  2. print("x=",x,"y=",y,"z=",z,"kw=",kw)
  1. combind_args(1)
x= 1 y= 2 z= () kw= {}
  1. combind_args(1,3)
x= 1 y= 3 z= () kw= {}
  1. combind_args(1,3,10,20,30)
x= 1 y= 3 z= (10, 20, 30) kw= {}
  1. combind_args(1,3,10,20,30,name="jack",city="Beijing")
x= 1 y= 3 z= (10, 20, 30) kw= {'name': 'jack', 'city': 'Beijing'}

总结一下:
1.参数分为形参和实参,形参是壳子,实参是传递给函数的具体信息
2.传递参数的方式主要有4种,分别有:

  • 位置参数:实参顺序与形参顺序一样
  • 关键字参数:1)以某形参名称=某实参的形式填写参数,使得形参和实参直接对应上,即function(x=1,y=2)的形式。2)通过**kw的形式传入字典dict,无接收数量限制,即function(**{"x":1,"y":2})的形式。3)通过命名关键字参数的形式限制传入的关键字参数数量,指定了传入的参数名,即function(x,y,*,name,age)的形式
  • 默认参数:给形参指定默认值,如果提供了实参,就用给定的实参值,否则使用默认值
  • 可变参数:1)实参的需要性不确定时,通过空值、空字符串等形式加以条件判断来应对多种情况 2)如果不确定传入的实参数量,那么通过*args的形式创建一个空元组tuple来接收任意数量的实参,再将tuple传给函数。

5.导出与导入模块

(1)将函数导出为模块

我们可以将写好的函数存储在称为模块的独立文件中,这样当我们需要在其他程序中去调用该函数时,直接导入即可使用。

函数导出为模块的步骤:
将写好的函数另存为.py文件,然后放置在python的工作路径中

(2)导入模块

  1. import module_name #导入模块名(即.py文件)

当要使用该模块内的函数时,调用方式为:

module_name.function_name()
  1. from module_name import function_name #导入模块中的1个特定函数
  1. from module_name import function_name1,function_name2,... #导入模块中的多个函数

当要使用该模块内的函数时,不需要使用句点来调用,直接输入函数名调用即可

  1. import module_name as new_name #导入模块并另起新名字,用的时候直接用新名字即可使用

当要使用该模块内的函数时,调用方式为:

new_name.function.name()
  1. from module_name import * #导入该模块中的所有函数

当要使用该模块内的函数时,不需要使用句点来调用,直接输入函数名称即可,但是有一个很大的问题是,如果该模块内的函数与你目前项目里的函数重名了的话,会覆盖掉重名函数,如果你不清楚导入的模块内的函数是否与你目前项目的函数有重名现象,就会很麻烦,因此不推荐这种方式。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注