1.使用def定义函数
比如:
def max(num1,num2):
return num1 if num1>num2 else num2
说明:def 关键词,max是函数名称,num1,num2是参数名称,若要返回值,则可以使用return。如果函数执行完毕但没有使用return返回值,或者使用了return结束函数但没有指定返回值,默认就会返回None。
支持递归和局部函数
2.参数与自变量
python中不支持函数重载
参数默认值
虽然不支持函数重载的实现,不过在Python中可以使用默认自变量来有限度地模仿函数重载。例如:
def account(name,number,balance=100):return{'name':name,'number':number,'balance':balance}
#显示
print(account('Justin','123-4567'))
{'name': 'Justin', 'number': '123-4567', 'balance': 100}
#显示
print(account('JK','987-234',1000))
{'name': 'JK', 'number': '987-234', 'balance': 1000}
使用参数默认值时,必须小心指定了可变动对象时的一个陷阱,Python在执行到def时,就会按照定义创建相关的资源。看看下面会出现的问题。
def prepend(elem,It=[]):
It.insert(0,elem)
return It
prepend(10)
Out[23]: [10]
prepend(10,[20,30,40])
Out[24]: [10, 20, 30, 40]
prepend(20)
Out[25]: [20, 10]
在上例中,IT默认值设置为[],由于def是条语句,执行到def的函数定义时就创建了[],而这个对象列表会一直存在,如果没有指定It,使用的就会一直是一开始指定的列表对象。想要避免这样的问题,可以将prepend()的It参数默认值设为None,并在函数中指定真正的默认值。例如:
def prepend(elem,It=None):
It=It if It else []
It.insert(0,elem)
return It
prepend(10)
Out[32]: [10]
prepend(10,[20,30,40])
Out[33]: [10, 20, 30, 40]
prepend(20)
Out[34]: [20]
关键词自变量
可以指定
参数名称来设置其自变量值。
*与**
如果有个函数拥有固定的参数,而我们有一个序列,像列表、元组,只要在传入时加上*,列表或元组中各个元素就会自动拆解给各个参数。
比如:
def account(name,number,balance):
return{'name':name,'number':number,'balance':balance}
#显示
print(account(*('Justin','123-4567',1000)))
{'name': 'Justin', 'number': '123-4567', 'balance': 1000}
像sum()这种加总数字的函数,事先无法预期要传入的自变量个数,可以在定义函数的参数时使用*,表示该参数接受不定长度的自变量。例如:
def sum(*numbers):total=0
for i in numbers:
total+=i
return total
#显示
print(sum(1,2))
3
#显示
print(sum(1,2,3,4))
10
传入函数的自变量,会被收集到一个元组中,再设置给numbers参数,这适用于参数个数不固定而且会按序迭代处理参数的场合。
如果有个字典,打算按照键的名称赋值给对应的参数名称,可以在字典前加上**,这样字典中各对键和值就会自动拆解给各个参数。
注意:如果参数个数越来越多,而且每个参数名称都有其意义,像def ajax(url,method,contents,datatype,accept,headers,username,password)这样的函数定义不但“丑陋”,调用时也很麻烦。这个时候可以试着使用**来定义参数,让指定的关键词自变量收集为一个字典。
例如:
def some(*arg1,**arg2):
print(arg1)
print(arg2)
some(2,3,4,a=5,b=8,c=10)
(2, 3, 4)
{'a': 5, 'b': 8, 'c': 10}
3.一级函数的运用
在Python中,函数不单只是个定义,还是个值,定义的函数会产生一个函数对象,它是function的实例,既然函数是对象,也就可以赋值给其他的变量。例如:
def max(num1,num2):
return num1 if num1>num2 else num2
maximum=max
maximum(10,5)
Out[47]: 10
type(max)
Out[48]: function
函数与数值、列表、集合、字典、元组等一样,都被Python视为“一级公民”来对待
实际上,Python内建有filter()、map()函数可以直接调用它们。在Python3中,map()、filter()返回的实例并不是列表,分别是map与filter对象,都具有惰性求值的特性。基本上filter()、map()能做到的,for Comprehension基本上都做得到。在大多数情况下,for Comprehension比较常见,不过有时通过适当的命名,使用filter()、map()会有比较好的可读性。
再来看一个一级函数传递的例子,到目前为止,经常会使用列表、元组等有序结构,有时想将其中的元素进行排序,这时可以使用sorted()函数,它可以按照我们指定的方式进行排序。例如:
sorted([2,1,3,6,5])
Out[53]: [1, 2, 3, 5, 6]
sorted([2,1,3,6,5],reverse=True)
Out[54]: [6, 5, 3, 2, 1]
sorted(('Justin','openhome','momor'),key=len)
Out[55]: ['momor', 'Justin', 'openhome']
sorted(('Justin','openhome','momor'),key=len,reverse=True)
Out[56]: ['openhome', 'Justin', 'momor']
sorted()会返回新的列表,其中包括了排序后的结果,key参数可用来指定针对什么特性来迭代。
如果是可变动的列表,本身也有个sort()方法,这个方法会直接在列表本身排序,不像sorted方法会返回新的列表。例如:
It=[2,1,3,6,5]
It.sort()
It
Out[60]: [1, 2, 3, 5, 6]
It.sort(reverse=True)
It
Out[62]: [6, 5, 3, 2, 1]
4.lambda表达式
当只有一句简单的运算,对于这类情况,可以考虑使用lambda表达式。例如:
def filter_lt(predicate,lt):
result=[]
for elem in lt:
if predicate(elem):
result.append(elem)
return result
lt=['Justin','caterpillar','openhome']
print('大于6:',filter_lt(lambda elem:len(elem)>6,lt))
大于6: ['caterpillar', 'openhome']
print('小于5:',filter_lt(lambda elem:len(elem)<5,lt))
小于5: []
print('有个i:',filter_lt(lambda elem: 'i' in elem,lt))
有个i: ['Justin', 'caterpillar']
在lambda关键词之后定义的是参数,而冒号(:)之后定义的是函数体,运算的结果会作为返回值,不需要加上return,像lambda elem:len(elem)>6这样的lambda表达式会创建function实例,也就是一个函数。有时临时只是需要一个小函数,使用lambda就很方便。
如果lambda不需要参数,直接在lambda后加上冒号就可以了,若需要两个以上的参数,中间要使用逗号(,)分隔开,例如
max=lambda n1,n2:n1 if n1>n2 else n2
max(10,5)
Out[75]: 10
和其他语言中的lambda语句相比,Python使用lambda关键词的方式其实并不简洁,甚至有些妨碍可读性。实际上,Python中的lambda也没办法写太复杂的逻辑,这是Python中为了避免lambda被滥用而特意做的限制。
5.初探变量作用域
在Python中,变量无需事先声明,一个名称在赋值时,就可以成为变量,并创建起自己的作用域(Scope)。在存取一个变量时,会看看当前作用域中是否有指定的变量名称,若无则向外寻找,因此在函数中可存取全局变量。
def func():
print(x)
func()
10
那么如果在func()中对名称x作了赋值的操作呢?
def func():
x=20
print(x)
func()
20
print(x)
10
在func()中进行x=20的时候,其实就创建了func()自己的局部变量x,而不是将全局变量设为20.
注意:就目前而言可以知道的是,变量可以在内建(Builtin)、全局(Global)、外包函数(Endosing function)、局部函数(Local function)中寻找或创建。
存取名称时(而不是对名称赋值)一定是从最内层往外寻找。Python中的全局变量,实际上是以模块文件为界。
Python 3中有个builtins模块,该模块中的名称作用域横跨各个模块。例如:print
locals()函数可以用来查询局部变量的名称和值
global()可以获取全局变量的名称与值
如果对变量赋值时希望针对全局作用域,可以使用global来声明。
因此在Python 3中应避免global声明的使用。
在Python3中新增了nonlocal,可以指明变量并非局部变量,请解释器按照局部函数、外包函数、全局、内建的顺序来寻找变量,就算是赋值运算时,也要求是这个顺序。