周三,晴,记录生活分享点滴
参考博客1:https://www.cnblogs.com/yuanchenqi/articles/5828233.html
参考博客2:https://www.cnblogs.com/alex3714/articles/5740985.html
参考网站3:https://www.runoob.com/python3/python3-namespace-scope.html
Python版本:3.5
函数的创建
定义
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性
1. 减少重复代码
2. 方便修改,使程序变的可扩展
3. 保持代码一致性,使程序变得易维护
语法定义
def sayhi():#函数名 print("Hello, I'm nobody!") sayhi() #调用函数
函数的参数
形参、实参
形参:变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
实参:可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
小结:形参是模子,实参是例子
位置参数
参数传入函数的顺序不能被改变,即name对应chung,age对应23
def f(name,age): print('I am %s,I am %d'%(name,age)) f('Chung',23) f('Zack',30)
关键字参数
正常情况下,给函数传参数要按顺序,不想按顺序就可以用关键参数,只需指定参数名即可,但记住一个要求就是...(看下面)
def f(name,age): print('I am %s,I am %d'%(name,age)) # f(16,'alvin') #报错 f(age=16,name='chung')
在定义参数时,即第一行,关键参数必须放在位置参数之后
def f(name, age, sex='male'): #def f(sex='male',name, age ): # 报错:非默认参数跟随默认参数 print('I am %s,I am %d, a %s' % (name, age, sex)) f('chung',23 )
默认参数
参数在调用时不指定,就是默认参数,指定了的话,就用指定的值。
其中默认参数是占一个位置的,例如下面的male为默认参数,在brother打印的时候,会有出现三组数据占三个位置。
def print_info(name, age, sex='male'): print('Name:%s' % name) print('age:%s' % age) print('Sex:%s' % sex) return print_info('brother', 23) #没有指定性别,默认参数为男,即male # Name:brother # age:23 # Sex:male print_info('sister', 18, 'female') #指定性别,默认参数失效,即female # Name:sister # age:22 # Sex:female
非固定/不定长参数
若你的函数在定义时不确定用户想传入多少个参数,就可以使用非固定/不定长参数。
无命名参数在左边,有命名参数放右边
*arge 参数变元组
def stu_register(name,age,*args): # *args 会把多传入的参数变成一个元组形式 print(name,age,args) stu_register("chung",23) #输出 #chung 23 () #后面这个()就是args,只是因为没传值,所以为空 stu_register("Jack",32,"CN","Python") #输出 # Jack 32 ('CN', 'Python')
**kwargs 参数变字典
def stu_register(name, age, *args, **kwargs): # **kwargs 会把多传入的参数变成一个dict形式 print(name, age, args, kwargs) stu_register("chung", 23) # 输出 # chung 23 () {} # 后面这个{}就是kwargs,只是因为没传值,所以为空 stu_register("Jack", 32, "CN", "Python", sex="Male", province="ShanDong") # 输出 # Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
单独输出元组或字典格式
def f(*args): print(args) f(*[1,2,5]) # (1, 2, 5) def f(**kwargs): print(kwargs) f(**{'name':'alex'}) # {'name': 'alex'}
函数的返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
- return多个对象,解释器会把这多个对象组装成一个元组作为一个一个整体结果输出。
def foo(): return 1, 'chung', [2, 3, 4] print('hello') # 证实第一点,return代表函数结束,无法输出运行print('hello') print(foo()) # (1, 'chung', [2, 3, 4]) # 证实第三点,无论return内容是什么格式,都将以元组的格式返回
函数的作用域
作用域的介绍
python中的作用域分4种情况,从里到外依次是:
L:local,局部作用域,即函数中定义的变量;(当前)
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;(外部)
G:global,全局变量,就是模块级别定义的变量;(全局)
B:built-in,系统固定模块里面的变量,比如int, bytearray等。(内置)
搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是 L > E > G > B
g_count = 0 # 全局作用域 def outer(): o_count = 1 # 闭包函数外的函数中 def inner(): i_count = 2 # 局部作用域
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。
调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。
total = 0 # 这是一个全局变量 # 可写函数说明 def sum(arg1, arg2): # 返回2个参数的和 total = arg1 + arg2 # total在这里是局部变量. print("函数内是局部变量 : ", total) return total # 调用sum函数 sum(10, 20) print("函数外是全局变量 : ", total) # 函数内是局部变量 : 30 # 函数外是全局变量 : 0
global 和 nonlocal关键字
global
当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上
count = 10 def outer(): global count print(count) # 如果没有global声明,提示错误:局部变量“count”在赋值之前被引用,表示如果没有global,此时count为局部变量 count = 100 print(count) outer() #10 #100
nonlocal
如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字
def outer(): count = 10 def inner(): nonlocal count count = 20 # 通过 nonlocal 将 10 改成 20 print(count) inner() print(count) outer() #20 #20
小结
1. 变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;
2. 只有模块、类、及函数才能引入新作用域;
3. 对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
4. 内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。
高阶函数
函数名可以进行赋值
函数名可以作为函数参数,还可以作为函数的返回值
def f(n): return n*n def foo(a, b, func): # 因为print中含有f函数,所以foo中的func里面的运行规则是 f ret = func(a)+func(b) return ret print(foo(1, 2, f)) # 返回结果为 5
递归函数
特性
1. 可以调用自身的函数
2. 有一个结束条件
3. 可以用递归函数解决的也都可以用循环解决
4. 递归函数的效率在大多情况下偏低
阶乘
循环
#阶乘计算用循环的方式来写 def factorial(n): result = n for i in range(1, n): result *= i return result # 24 print(factorial(4))
递归
# 阶乘计算用递归的方式来写 def factorial(n): if n == 1: return 1 return n * factorial(n - 1) # 24 print(factorial(4))
斐波那契数列
循环
# 斐波那契 循环 def fibo(n): before = 0 after = 1 for i in range(n - 1): ret = before + after before = after after = ret return ret # 2 print(fibo(3))
递归
# 斐波那契 递归 def fibo_new(n): # n可以为零,数列有[0] if n <= 1: return n return (fibo_new(n - 1) + fibo_new(n - 2)) # 2 print(fibo_new(3))
内置函数
Built-in Functions
重要的内置函数
filter(function, sequence)
对sequence中的item依次执行function(item),将执行结果为True的item做成一个filter object的迭代器返回。可以看作是过滤函数。
str = ['a', 'b','c', 'd'] def fun1(s): if s != 'a': return s ret = filter(fun1, str) print(list(ret))# ret是一个迭代器对象
map(function, sequence)
对sequence中的item依次执行function(item),将执行结果组成一个map object迭代器返回.
str = [1, 2,'a', 'b'] def fun2(s): return s + "alvin" ret = map(fun2, str) print(ret) # map object的迭代器 print(list(ret))# ['aalvin', 'balvin', 'calvin', 'dalvin']
map也支持多个sequence,这就要求function也支持相应数量的参数输入:
ef add(x,y): return x+y print (list(map(add, range(10), range(10))))##[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
reduce(function, sequence, starting_value)
对sequence中的item顺序迭代调用function,如果有starting_value,还可以作为初始值调用
from functools import reduce def add1(x,y): return x + y print (reduce(add1, range(1, 101)))## 4950 (注:1+2+...+99) print (reduce(add1, range(1, 101), 20))## 4970 (注:1+2+...+99+20)
lambda
匿名函数的命名规则,用lamdba 关键字标识,冒号(:)左侧表示函数接收的参数(a,b) ,冒号(:)右侧表示函数的返回值(a+b)。
因为lamdba在创建时不需要命名,所以叫匿名函数
#普通函数 def add(a,b): return a + b print add(2,3) # 5 #匿名函数 add = lambda a,b : a + b print add(2,3) # 5