在许多编程语言中都存在函数,python也不例外。
函数是将单一或者相关联的功能打包的代码段。函数将代码打包,外界只需要调用接口,不必知道其实现过程
函数的意义是代码复用,一次定义多次使用,不仅减轻了代码工作者的作业,而且使得程序的架构更加完善,更改,维护得到提升,扩展性更强(不用类的情况下)
python中的函数分为 内置函数 和 用户自定义函数。
内置函数此处不讲,下面我们看看用户自定义函数
在python中,函数名的命名符合变量命名规则,一般就用驼峰式或用下划线连接,如下:
1 >>>
2 >>> def MyFirstFunc(): #驼峰命名,这样可以按照大小写区分一个单词,读懂函数名的意思
3 pass
4 #这里定义的空函数
5 >>>
6 >>> def my_first_func(): #用'_'连接,个人觉得更清晰,所以一般自用这种方式命名函数,用驼峰式命名类
7 pass
8
9 >>>
python定义函数的固定格式:
def function_name([arg1[,arg2...]]):
return
说明:
def: 是 define function ,定义函数说明,python解释器在读到 def 时,就会把其后的代码块当成一个函数,此时python解释器不会把函数的代码
读到内存中,跳过整个代码块继续读后面的代码,当函数被调用时,python解释器才会去解释执行函数的代码块。
function_name: 用户自定义的函数名,注意不要与python里面存在的函数重名,否则相当于重写内置函数,若不需要,尽量避免。在定义完成后,
函数名就相当于函数在内存中地址的一个引用,此时若直接打印函数名,则会返回函数的内存地址
() :在定义时的固定格式,里面可以没有参数,也可以有参数(参数可以是python中各种数据结构)。在调用时,函数名() 表示执行函数,所以经常在
给函数名创建引用后,给引用加个()就能执行函数
[arg1[,arg2...]] : 表示可选参数
' : ' :固定写法,指明下面是属于当前行的代码块
return : 函数中的出口。当函数在执行到return时,当前函数会结束执行(后面的代码将不会执行),并把return后面的值(或表达式)返回,此时可以用
一个变量来接收函数的返回值,当一个函数中没有定义return时,这个函数也有返回值,默认返回None
1 >>> 2 >>> def hello(name): 3 print('hello %s' %name) 4 return 'hello everyone!' 5 print('just test') #没有被执行 6 7 8 >>> h = hello('root') # hello() 表示调用函数 9 hello root 10 >>>h
11 'hello everyone!' 12 >>>
参数
在python中,参数是没有类型的,类型是属于对象。eg:
1 >>>
2 >>> l = [1,2,3,'a']
3 >>> s = 'hello'
4 >>>
上面的 [1,2,3,'a'] 是List类型,'hello' 是String类型,而变量 l、s 是没有类型的,她仅仅是一个对象的引用(一个指针),可以是 List 类型对象,
也可以指向 String 类型对象。
在 python 中,strings, tuples, 和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。
-
不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变a的值,相当于新生成了a。
-
可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
python 函数的参数传递:
-
不可变类型:类似 c++ 的值传递,如 整数、字符串、元组。如fun(a),传递的只是a的值,没有影响a对象本身。比如在 fun(a)内部修改 a 的值,只是修改另一个复制的对象,不会影响 a 本身。
-
可变类型:类似 c++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后fun外部的la也会受影响
对上面传递不可变对象,eg:
1 >>>
2 >>> def test(a):
3 a = 10 # a 是一个局部变量,只是作用在函数test内部,出了函数,是不能调用它的
4
5
6 >>> b = 2
7 >>> test(b) #因为b=2,是numbers,不可变类型,所以这里传递的是值2,即test(2),所以函数里面的更改与 b 无关
8 >>> b
9 2
10 >>> a
11 Traceback (most recent call last):
12 File "<pyshell#40>", line 1, in <module>
13 a
14 NameError: name 'a' is not defined
15 >>>
对上面可变类型,eg:
1 >>> l = [1, 2, 3, 4, 5]
2 >>> def change_list(ol):
3 if len(ol) >= 3:
4 ol[2] = 'hello'
5 return 'just test'
6 else:
7 print('Not change everything')
8
9
10 >>> cl = change_list(l)
11 >>> l
12 [1, 2, 'hello', 4, 5]
13 >>> cl
14 'just test'
15 >>>
python 中一切都是对象,严格意义我们不能说 值传递 还是 引用传递,我们应该说传 不可变对象 和传 可变对象 。
传递给函数的参数也有很多种形式:
关键字参数: 实参位置与形参位置按顺序一一对应
1 >>>
2 >>> def say_hello(name1,name2):
3 print('name1:',name1)
4 print('name2:',name2)
5 return 'just test'
6
7 >>> sh = say_hello('admin','root')
8 name1: admin
9 name2: root
10 >>> sh = say_hello('root','admin')
11 name1: root
12 name2: admin
13 >>>
指定参数: 类似键值对,对传递参数的位置顺序无关
1 >>>
2 >>> def say_hello(name1,name2):
3 print('name1:',name1)
4 print('name2:',name2)
5 return 'just test'
6
7 >>> sh = say_hello(name2='admin',name1='root')
8 name1: root
9 name2: admin
10 >>>
默认参数: 在函数定义时为参数赋初值,防止后面没输入报错 (注意:有默认值的参数放在最后)
1 >>>
2 >>> def user_info(name,age,hobbie='python'):
3 print('%s is %s year old and his hobbie is %s' %(name,age,hobbie))
4
5 >>> ui = user_info('root',22,'php')
6 root is 22 year old and his hobbie is php
7 >>> ui = user_info('root',22)
8 root is 22 year old and his hobbie is python
9 >>> type(ui)
10 <class 'NoneType'>
11 >>>
动态参数:参数可变,自动把传入的参数转换为元祖或字典
前面有一个*,如 *args 表示 会把接受到的 非键值对形式 的所有参数放进一个元祖里面
前面有两个*,如 **kwargs 表示 会把接收到的 键值对形式 的所有参数放进一个字典里面
注意:键值对形式的参数必须放在最后面
1 >>> 2 >>> def collect_func(*args,**kwargs): 3 print('your input *args:',args) # * 只是指明后面的参数是(元祖)收集参数,并不是变量名的一部分,同理,** 也是(字典)收集参数 4 print('your input **kwargs:',kwargs) 5 6 7 >>> collect_func(1,2,'hello',[5,6],'a',name='root',age=22) 8 your input *args: (1, 2, 'hello', [5, 6], 'a') 9 your input **kwargs: {'name': 'root', 'age': 22} 10 11 >>> collect_func(1,2,'hello',age=22,[5,6],'a',name='root') 12 SyntaxError: positional argument follows keyword argument 13 >>>
变量作用域:
在函数内部定义的变量为局部变量,仅在函数内有用,出了函数就无法访问。全局变量易于访问,但不易于修改。
若要在函数内部定义一个全局变量,可用 global eg: 在函数内: global x = 10 (global会影响执行速度,并且不安全,不建议这样用)
注意:
在函数内部修改全局变量(如重新赋值),python会自动新建一个与全局变量名字相同的局部变量。全局变量存在于栈中,局部变量
存在于其他地方,所以互不影响
闭包:
闭包使用实例:装饰器
注意:
使用函数时:在函数内部和程序其他部分可以使用的变量不同,在函数内应该只是使用通过参数传递进来的变量,而在函数外部,应该只使用接收函数返回值的变量
1 >>> 2 >>> def func1(): 3 print('func1正在被调用...') 4 def func2(): 5 print('func2正在被调用...') 6 return func2 7 8 >>> a = func1() 9 func1正在被调用... 10 >>> a() 11 func2正在被调用... 12 >>> func2() #不能直接从外部调用某个函数的内嵌函数 ,内嵌函数的作用域都在外部函数内 13 Traceback (most recent call last): 14 File "<pyshell#57>", line 1, in <module> 15 func2() 16 NameError: name 'func2' is not defined 17 >>>
匿名函数:
lambda 表达式
作用:
1、在使用函数时,用lambda表达式可以省下定义函数的过程
2、简化代码可读性
1 >>> 2 >>> g = lambda x,y:x+y 3 >>> g(3,5) 4 8 5 >>>
说明:lambda后面空格,然后跟变量,有多个变量用 ' , ' 隔开,' : '是参数和函数体的分割点,' : '后面表示是函数体,
给lambda 表达式创建引用(一个指针) g ,使g指向lambda表达式的地址,再加上 () 执行lambda 表达式
过滤器:
作用:筛选,把满足条件的去掉,留下的生成一个filter object,可用list将其转化
1 >>> 2 >>> #用法:filter(function or None , iterable) 3 >>> 4 >>> l = [1,0,3,'a',False,True] 5 >>> filter(None,l) 6 <filter object at 0x0000014EC44EBBA8> 7 >>> list(filter(None,l)) 8 [1, 3, 'a', True] 9 >>> 10 >>> #用filter写一个筛选奇数的函数 11 >>> 12 >>> def singnal_num(x): #这里用lambda改进: lambda x:x%2 13 return x%2 14 15 >>> ls = range(10) 16 >>> show = filter(singnal_num,ls) #show = filter(lambda x:x%2,ls) 17 >>> list(show) 18 [1, 3, 5, 7, 9] 19 >>>
映射:map()
将序列的每一个元素作为函数的参数(对应除默认参数外,只能传递一个)进行运算加工,直到把序列的所有元素加工完毕,返回所有加工后的元素构成的新序列
1 >>> 2 >>> #用法: map(规则函数,迭代器) 3 >>> 4 >>> m = map(lambda x:x*2,range(10)) 5 >>> list(m) 6 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 7 >>> 8 >>> [i for i in m] 9 [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] 10 >>>