Python函数

函数基础

1、定义函数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
"""
#语法
def 函数名(参数1,参数2,参数3,...):
     '''注释'''
     函数体
     return 返回的值
 
#函数名要能反映其意义
"""
 
def tol(a,b):              # def 定义函数
     """
     求和
     :param a:
     :param b:
     :return:
     """
     ret = a + b                 #函数体
     return ret             #函数返回
tol( 1 , 2 )                    #调用函数  函数名+括号就是调用
print (tol( 1 , 2 ))            #打印返回值,若是没return语句,返回值为None

2、使用原则:先定义,再调用

  • 函数即“变量”,“变量”必须先定义后引用.
  • 未定义而直接引用函数,就至关于在引用一个不存在的变量名.
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 状况1:
def foo():
     print ( 'from foo' )
     bar()
foo()  # 报错 NameError: name 'bar' is not defined
 
# 状况2:
def bar():
     print ( 'from bar' )
def foo():
     print ( 'from foo' )
     bar()
foo()  # 正常
 
# 状况3:
#######定义阶段#######
def foo():
     print ( 'from foo' )
     bar()
def bar():
     print ( 'from bar' )
#######定义阶段#######
 
#######调用阶段#######
foo()  #正常
# ******不报错,调用的时候已经定义好了******#先定义,后调用
#######调用阶段#######

3、定义函数的三种形式

?
1
2
3
4
5
6
7
8
def tell_tag(tag,n): #有参函数
     print (tag * n)
 
def tell_msg(): #无参函数
     print ( 'hello world' )
 
def tell_blank(): #空函数
     pass

4、调用函数的三种形式

  • 语句形式:foo()
  • 表达式形式:3*len('hello')
  • 当中另一个函数的参数:range(len('hello'))

5、函数返回值

  • 无return->None
  • return 1个值->返回1个值
  • return 逗号分隔多个值->元组

6、函数参数

形参即变量名就是函数定义阶段的参数,实参即变量值就是函数调用阶段的参数,函数调用时,将值绑定到变量名上,函数调用结束,解除绑定python

  1. 位置参数:按照从左到右的顺序定义的参数
    • 位置形参:必选参数
    • 位置实参:按照位置给形参传值
  2. 关键字参数:按照key=value的形式定义的实参
    • 无需按照位置为形参传值
    • 注意1:关键字实参必须在位置实参右面
    • 注意2:对同一个形参不能重复传值
  3. 默认参数:形参在定义时就已经为其赋值
    • 能够传值也能够不传值,常常须要变得参数定义成位置形参,变化较小的参数定义成默认参数(形参)
    • 注意1:只在定义时赋值一次
    • 注意2:默认参数的定义应该在位置形参右面
    • 注意3: 默认参数一般应该定义成不可变类型
  4. 可变长参数:
    • 可变长指的是实参值的个数不固定
    • 而实参有按位置和按关键字两种形式定义,针对这两种形式的可变长,形参对应有两种解决方案来完整地存放它们,分别是*args,**kwargs
  5. 命名关键字参数:*后定义的参数,必须被传值(有默认值的除外),且必须按照关键字实参的形式传递
    • 能够保证,传入的参数中必定包含某些关键字
#===========*args===========
def foo(x, y, *args):
    print(x,'-',y,'-',*args,'-',args)

foo(1, 2, 3, 4, 5)  #1 - 2 - 3 4 5 - (3, 4, 5)
foo(1, 2,[3, 4, 5]) #1 - 2 - [3, 4, 5] - ([3, 4, 5],)
foo(1, 2, *[3, 4, 5]) #1 - 2 - 3 4 5 - (3, 4, 5)
foo(*[1, 2, 3]) #1 - 2 - 3 - (3,)

print(*[3, 4, 5]) # 3 4 5
print(*{'b': 2, 'a': 1, 'c': 3}) # b c a

#===========**kwargs===========
def foo(x, y, **kwargs):
    print(x,'-',y,'-',*kwargs,'-',kwargs)

foo(1, y=2, a=1, b=2, c=3) #1 - 2 - b c a - {'b': 2, 'c': 3, 'a': 1}
foo(1, y=2, **{'a': 1, 'b': 2, 'c': 3}) #1 - 2 - b c a - {'b': 2, 'c': 3, 'a': 1}
foo(**{'z': 3, 'x': 1, 'y': 1}) #1 - 1 - z - {'z': 3}

#===========*args+**kwargs===========
def foo(*args, **kwargs):
    print(args,'-',*args, '-', kwargs,'-', *kwargs)
foo(1, y=2, a=1, b=2, c=3) #(1,) - 1 - {'c': 3, 'b': 2, 'y': 2, 'a': 1} - c b y a


#===========*后定义的参数,必须被传值(有默认值的除外)且必须按照关键字实参的形式传递===========
def foo(x,y,*args,b,a=1,**kwargs):
    print(x, '-', y, '-', *args, '-', args,'-',a, '-', b,'-', kwargs,'-', *kwargs)
foo(1,2,3,4,5,b=3,c=4,d=5) #1 - 2 - 3 4 5 - (3, 4, 5) - 1 - 3 - {'c': 4, 'd': 5} - c d

函数对象

函数是第一类对象,即函数能够看成数据传递数据结构

  • 能够被引用
  • 能够看成参数传递
  • 返回值能够是函数
  • 能够看成容器类型的元素
?
1
2
3
4
5
6
7
8
9
10
11
12
13
def foo():
     print ( 'foo' )
def bar():
     print ( 'bar' )
dic = {
     'foo' :foo,
     'bar' :bar,
}
while True :
     choice = input ( '>>: ' ).strip()
     if choice in dic:
         print (dic[choice], type (dic[choice])) # <function foo at 0x00000000010EF9D8> <class 'function'>
         dic[choice]()     #加括号就运行函数

函数嵌套

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def least(x,y):
     return x if x > y else y
 
def max4(a,b,c,d):
     res1 = least(a,b)
     res2 = least(res1,c)
     res3 = least(res2,d)
     return res3
print (max4( 1 , 2 , 3 , 4 ))  #4
 
def f1():
     def f2():
         def f3():
             print ( 'from f3' )
         f3()
     f2()
 
f1() #from f3

名称空间与做用域

1、什么叫名称空间

存放名字的地方,三种名称空间,(x=1,1存放于内存中,那名字x存放在哪里呢?名称空间正是存放名字x与1绑定关系的地方)闭包

2、名称空间的加载顺序

  • python解释器先启动,于是首先加载的是:内置名称空间 builtins(内置模块的名字空间)
  • 执行test.py文件,而后以文件为基础,加载全局名称空间 globals(全局变量,函数定义所在模块的名字空间)
  • 外部嵌套函数的名字空间 enclosing
  • 在执行文件的过程当中若是调用函数,则临时产生局部名称空间 locals(是函数内的名称空间,包括局部变量和形参)

3、名字的查找顺序

  • LEGB 表明名字查找顺序: locals -> enclosing function -> globals -> __builtins__
  • 局部名称空间--->全局名称空间--->内置名称空间
  • 在全局没法查看局部的,在局部能够查看全局的

4、做用域即范围

  • 全局范围(内置名称空间与全局名称空间属于该范围),全局有效
  • 局部范围(局部名称空间属于该范围),局部有效
  • *****做用域关系是在函数定义阶段就已经固定的,与函数的调用位置无关*****
?
1
2
3
4
5
6
7
8
#若是函数收到的是一个不可变对象(好比数字、字符或者元组)的引用,就不能直接修改原始对象,
# 至关于经过“传值’来传递对象,此时若是想改变这些变量的值,能够将这些变量申明为全局变量。
num = 20
def show_num(x = num):
     print (x)
show_num()  #20
num = 30
show_num()  #20
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
name = "jack"   #全局变量
age = 90 #全局变量
gender = 'male' #全局变量
def out():
     name = 'tom' #局部变量
     age = 18   #局部变量
     def inner():
         global name  #global声明此时的name是全局的
         name = "rose" #修改全局name
         print (name, 'inner' ) #rose inner 读取全局的
         print (age, 'inner' ) # 18 inner 本身没有向外找 out里面有就读取,
         print (gender, 'inner' ) # male inner 本身没有向外找,out里也没有,再向外找,找到全局的
     inner()
     print (name, 'out' ) #tom out  先找本身,没有在向外找,本身有就读取
     print (age, 'out' ) #18 out  先找本身,没有在向外找,本身有就读取
     print (gender, 'out' ) #male out  先找本身,没有在向外找,找到全局的
 
out()
 
print (name, 'gl' #rose gl 被inner修改了
print (age, 'gl' #90 gl
print (gender, 'gl' #male gl
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
"""
LEGB 表明名字查找顺序: locals -> enclosing -> globals -> __builtins__
locals 是函数内的名字空间,包括局部变量和形参
enclosing 外部嵌套函数的名字空间(闭包中常见)
globals 全局变量,函数定义所在模块的名字空间
builtins 内置模块的名字空间
"""
x = 1
def f1():
     def f2():
         print (x)
     return f2
x = 100
def f3(func):
     x = 2
     func()
x = 10000
f3(f1()) # locals -> enclosing -> globals ->打印10000
 
name = 'tom'
def change_name():
     global name   #global 声明此时的name是全局的
     name = 'rose'   #修改了全局的name
     print ( 'change_name' ,name)
change_name()  #打印change_name rose
print (name) #rose
 
li = [ "aa" , "bb" ]
def fun():
     global li
     li = [ "cc" ]
     li.append( 'bye' )
     print ( 'fun内' , li)
fun() #fun 内 ['cc', 'bye']
print (li, type (li)) #['cc', 'bye'] <class 'list'>
 
li = [ "aa" , "bb" ]
def fun():
     li = [ "cc" ]
     li.append( 'bye' )
     print ( 'fun内' , li)
fun() #fun内 ['cc', 'bye']
print (li, type (li)) #['aa', 'bb'] <class 'list'>
 
li = [ "aa" , "bb" ]
def fun():
     li.append( 'bye' )
     print ( 'fun内' , li)
fun() #fun内 ['aa', 'bb', 'bye']
print (li, type (li)) #['aa', 'bb', 'bye'] <class 'list'>

闭包函数

  • 建立闭包函数必须知足3点:
    1. 一、必须有一个内嵌函数
    2. 二、内嵌函数必须引用外部函数中的变量(非全局做用域的引用)
    3. 三、外部函数的返回值必须是内嵌函数
  • 闭包意义:
    1. 以前咱们都是经过参数将外部的值传给函数,闭包提供了另一种思路
    2. 返回的函数对象,在该函数外还包裹了一层做用域,这使得,该函数不管在何处调用,优先使用本身外层包裹的做用域
  • 应用领域:
    1. 延迟计算
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
def count():
     n = 0
     def fun():
         nonlocal n   # nonlocal,指定上一级变量,若是没有就继续往上直到找到为止
         n + = 1
         return n
     print (n, '===' )
     return fun
 
c = count()
print (c())
print (c())
print (c())
c = count()
"""
0 ===
1
2
3
0 ===
"""
 
from urllib.request import urlopen
def index(url):
     def get():
         return urlopen(url).read()
     return get
baidu = index( 'http://www.baidu.com' )
print (baidu) #<function index.<locals>.get at 0x0000000002CC59D8>
print ( type (baidu())) #<class 'bytes'>
print (baidu().decode( 'utf-8' ))

递归函数

递归调用是函数嵌套调用的一种特殊形式,函数在调用时,调用了自身,就是递归调用。app

  • 必须有一个明确的结束条件
  • 每次进入更深一层递归时,问题规模相比上次递归都应有所减小
  • 递归效率不高,递归层次过多会致使栈溢出(在计算机中,函数调用是经过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。因为栈的大小不是无限的,因此,递归调用的次数过多,会致使栈溢出)
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def f(n):
     if 0 = = n:                   # n=0 的话直接返回空,对用户输入的零进行判断
         return None
     elif 1 = = n:                 # n=1 的话就再也不递归
         return n
     else :
         return n * f(n - 1 )       # 递归在执行f(n-1) 直到f(1)
print (f( 5 ))                   # 120
'''
     f(5)的执行过程以下
         ===> f(5)
         ===> 5 * f(4)
         ===> 5 * (4 * f(3))
         ===> 5 * (4 * (3 * f(2)))
         ===> 5 * (4 * (3 * (2 * f(1))))
         ===> 5 * (4 * (3 * (2 * 1)))
         ===> 5 * (4 * (3 * 2))
         ===> 5 * (4 * 6)
         ===> 5 * 24
         ===> 120
'''
相关文章
相关标签/搜索