深入理解python(四)python基础知识之函数
函数部分
函数部分大概想分成两个部分来讲,第一部分是关于对函数参数的介绍,第二部分是局部变量全局变量和内置变量也就是变量作用域的LGB原则
函数的参数
1.关于形参和实参的问题
第一点要注意的是python中形参和实参的问题、
以不可变对象为参数,不会修改不可变对象的值(形参和实参的原因)
但对于可变对象(例如列表字典等),会在原地修改对象的值
例:
>>> def immutableob(a):#在函数中修改不可变对象的值 ... a+=1 >>> b=1 >>> immutableob(b) >>> b 1 #对象的值并没有改变
所以一般需要改变不可变对象的时候,一般使用返回值来处理
但是对于可变对象,函数内部值的改变会影响到外部
例:
>>> def mutableob(a): ... a[0]=3 ... >>> b=[1,2,3] >>> mutableob(b) >>> b [3, 2, 3] #作为参数的不可变对象的值发生了改变
2.几个参数类型
a.默认值参数
调用函数时,设置一些有默认值的参数
例:
def power(x, n=2): s = 1 while(n > 0): n -= 1 s *= n reutrn s power(3) #9 power(2, 3) #8
但是不建议默认值参数指向一个可变对象,很容易出现危险
这里给一个默认值对象指向空列表的例子
>>> def my_func(a=[]): ... a.append(1) ... print(a) >>> my_func() [1] >>> my_func() [1, 1] >>> my_func() [1, 1, 1]
可以看到,这样做的结果是,默认值参数的值会随着函数运行的次数而不断改变
b.可变长参数
可变长度参数有两种形式:*parameter 和 **parameter
*parameter 用来接受多个实参并将其放在一个元组中
**parameter 用来接受字典形式的实参
>>> def my_func(*a): #*parameter ... for x in a: ... print(x) ... >>> my_func(1,2,3) 1 2 3 >>> def my_func(**a): #**parameter ... print(a) ... >>> my_func(a=1,b=2) {‘a‘: 1, ‘b‘: 2}
d.参数的解包
列表解包时,保持列表项数与参数数一致
#解包--list,元组,集合 def connect(ip,port,username,password): print(ip) print(port) print(username) print(password) info_list=[‘192.168.1.1‘,3309,‘zhaozhao‘,‘123456‘] info_tuple=(‘192.168.1.1‘,3309,‘zhaozhao‘,‘123456‘) info_set={‘192.168.1.1‘,3309,‘zhaozhao‘,‘123456‘} connect(*info_list) connect(*info_tuple) connect(*info_set)
字典解包时,使用两个**代表对值的解包,但需要参数名称和key的值一样:
dic={"name":"zhaozhao","password":"123456"} def dic_fun(name,password): print(name) print(password) dic_fun(**dic) zhaozhao
这里要注意一下函数解包和变长参数的区别
变长参数是在函数定义时作为形参在函数定义内的
而函数解包相当于把要传入的字典或者列表进行解包,然后作为实参传入函数
lambda表达式和几个常用函数
lambda表达式可以用来声明匿名函数(anonymous function),即没有函数名字的临时使用的小函数
只可以包含一个表达式,且该表达式的计算结果为函数的返回值,不允许包含其他复杂的语句,但在表达式中可以调用其他函数。
>>> x=lambda a,c:a+c >>> x(1,2) 3
常见的使用情景时在map函数中调用
>>> a=[1,2,3,4] >>> list(map(lambda c:c*c,a)) [1, 4, 9, 16]
内置函数reduce可以将一个接受两个参数的函数以累积的方式从左到右依次作用到一个序列或迭代器对象的所有元素上
注意一点,python3在使用reduce时要注意需要
from functools import reduce
>>> reduce(lambda x,y:x+y,[1,2,3,4]) 10 >>>
之后是关于sort的东西:
首先是list.sort()和sorted()的区别
list.sort()是原地排序,而sorted()是非原地排序返回排完序的列表
>>> a=[2,4,3,1] >>> a.sort() >>> a [1, 2, 3, 4] >>> a=[2,4,3,1] >>> b=sorted(a) >>> b [1, 2, 3, 4] >>> a [2, 4, 3, 1]
之后是python2和python3的区别:
先说说这几个参数:
reverse -- 排序规则,reverse = True 降序, reverse = False 升序(默认)
key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。
关于key,这里给个例子:
>>> a=[(1,2),(5,3),(2,1)] >>> def mykey(a): ... return a[1] >>> a.sort(key=mykey) >>> a [(2, 1), (1, 2), (5, 3)]
关于cmp函数,在python2中作为传入的比对函数来使用,默认函数就是comp(x,y),在python3中没有这个参数
Python 2.7.14 (v2.7.14:84471935ed, Sep 16 2017, 20:19:30) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> cmp(1,2) #注意这是在在python2环境下 -1 >>> cmp(2,1) 1
所以在python2中我们可以任意修改比对规则,例:
#升序排列 >>>numbers = [5,2,9,7] >>>numbers.sort(cmp = lambda x,y: x-y) >>>numbers [2,5,7,9] #降序排列 >>>numbers = [5,2,9,7] >>>numbers.sort(cmp = lambda x,y: y-x) >>>numbers [9,7,5,2]
最后关于yeild的使用
这里先简述一下generator的概念
严格来讲,Python中“生成器”这一概念包括两种具体的语法实现:
生成器函数(generator function): 类似于用常规的 def 语句定义的函数,但是使用 yield 语句一次返回一个结果,并在每个结果之间挂起 / 继续执行的状态
生成器表达式(generator expression): 类似于列表解析式,但是它们返回一个迭代器,而不是返回一个结果列表
也可以简单理解为生成一个可迭代对象,,,
例如使用生成器表达式:
例
>>> for x in (i for i in range(1,5)): ... print(x) ... 1 2 3 4
这是生成器表达式,我们使用生成器函数做同样的事情
>>> def number(i): ... for k in range(i): ... yield k ... >>> for x in number(5): ... print(x) ... 0 1 2 3 4 #我们来看看函数的返回类型 >>> type(number(5))<class ‘generator‘>