pythopn 函数

一 函数是什么?

函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的
函数能提高应用的模块性,和代码的重复利用率。你已经知道Python提供了许多内建函数,比如print()。
但你也可以自己创建函数,这被叫做用户自定义函数。
定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可
特性:
                    1.代码重用
                    2.保持一致性
                    3.可扩展性

二 函数的创建

2.1 格式:
Python 定义函数使用 def 关键字,一般格式如下:
def 函数名(
    参数列表):
函数体
>>> def hello():
>>>     print('hello')
>>> hello()  # 调用

2.2 函数名的命名规则:

函数名必须以下划线或字母开头,可以包含任意字母、数字或下划线的组合。
不能使用任何的标点符号;
函数名是区分大小写的。                         #变量也是区分大小写的
函数名不能是保留字。

2.3 形参和实参

形参:形式参数,不是实际存在,是虚拟变量。在定义函数和函数体的时候使用形参,目的是在函数调用时接收
实参(实参个数,类型应与实参一一对应)

实参:实际参数,调用函数时传给函数的参数,可以是常量,变量,表达式,函数,传给形参   

区别:形参是虚拟的,不占用内存空间,.形参变量只有在被调用时才分配内存单元,实参是一个变量,占用内存
空间,数据传送单向,实参传给形参,不能形参传给实参

>>> def add(a,b):          #           a   b 是形参
>>>     print(a+b)
>>> add(5,6)                 #           5   6 是形参

2.4 实例

>>> import time
>>> def logger(n):
>>>     time_format='%Y-%m-%d %x'
>>>     time_current=time.strftime(time_format)
>>>     with open('日志记录', 'a') as f:
>>>         f.write('%s end action%s\n' %(time_current, n))
>>> def action1(n):
>>>     print ('starting action1...')
>>>     logger(n)
>>> def action2(n):
>>>     print ('starting action2...')
>>>     logger(n)
>>> def action3(n):
>>>     print ('starting action3...')
>>>     logger(n)
>>> action1(1)
>>> action2(2)
>>> action3(3)

三 函数的参数

必备参数
关键字参数
默认参数
不定长参数

必备参数:
必备参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
>>> def f(name,age):
>>>     print('I am %s,I am %d'%(name,age))
>>> f('name',age)                                 #位置一一对应

关键字参数:
关键字参数和函数调用关系紧密,函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用
时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
>>> def f(name,age):
>>>     print('I am %s,I am %d'%(name,age))
>>> # f(16,'name')                                                #会报错
>>> f(age=16,name='name')

缺省参数(默认参数):
调用函数时,缺省参数的值如果没有传入,则被认为是默认值。下例会打印默认的age,如果age没有被传入:
>>> def print_info(name,age,sex='male'): 
>>>     print('Name:%s'%name)
>>>     print('age:%s'%age)
>>>     print('Sex:%s'%sex)
>>>     return 
>>> print_info('alex',18)
>>> print_info('铁锤',40,'female')

不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时
不会命名。
>>> def add(*tuples):
>>>     sum=0
>>>     for v in tuples:
>>>         sum+=v 
>>>     return sum 
>>> print(add(1,4,6,9))
>>> print(add(1,4,6,9,5))

>>> def add(*t):                #    *t   等同于   上段代码中的 *tuples   名字可以自定义
>>>     print(type(t))           #      <class 'tuple'>    t个元组
>>>     print(t)                    #     (1, 4, 6, 9, 5)      
>>> add(1,4,6,9,5)

加了星号(*)的变量名会存放所有未命名的变量参数。而加(**)的变量名会存放命名的变量参数

>>> def print_info(**kwargs):
>>>     print(kwargs)
>>>     for i in kwargs:
>>>         print('%s:%s'%(i,kwargs[i]))           #根据参数可以打印任意相关信息了
>>>     return
>>> print_info(name='n',age=18,sex='female',hobby='girl')

输出:
{'name': 'n', 'age': 18, 'sex': 'female', 'hobby': 'girl'}
name:n
age:18
sex:female
hobby:girl

>>> def print_info(**k):                   #    **k  等同于   上段代码中的 **kwargs   名字可以自定义
>>>     print(type(k))                        # <class 'dict'>   #     k是个字典
>>>     print(k)                                  #      {'name': 'n', 'age': 18, 'sex': 'female', 'hobby': 'girl'}
>>> print_info(name='n',age=18,sex='female',hobby='girl')

 关于不定长参数  *args 放左边  **kwargs放右边
 形式如下   
 关键字参数   默认参数  *args    **kwargs 
 def  function(name,age=22,*args,**kwargs)

补充(高阶函数):

 高阶函数是至少满足下列一个条件的函数:
接受一个或多个函数作为输入
输出一个函数

>>> def add(x,y,f):
>>>     return f(x) + f(y)
>>> res = add(3,-6,abs)             #abs为其他函数
>>> print(res)

>>> def foo():
>>>     x=3
>>>     def bar():
>>>         return x
>>>     return bar

四 函数的返回值

要想获取函数的执行结果,就可以用return语句把结果返回
注意:
函数在执行过程中只要遇到return语句,就会停止执行并返回结果, 也可以理解为 return 语句代表着函数的结束
如果未在函数中指定return,那这个函数的返回值为None  
return多个对象,解释器会把这多个对象组装成一个元组作为一个一个整体结果输出。

五 作用域

5.1 作用域介绍 

python中的作用域分4种情况:

L:local,局部作用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G:globa,全局变量,就是模块级别定义的变量;
B:built-in,系统固定模块里面的变量,比如int, bytearray等。 
搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。

>>> x = int(2.9)                        # int built-in
>>> g_count = 0                     # global
>>> def outer():
>>>     o_count = 1                # enclosing
>>>     def inner():
>>>         i_count = 2              # local
>>>         print(o_count)
>>>     # print(i_count)            超出作用于找不到
>>>     inner() 
>>> outer()

当然,local和enclosing是相对的,enclosing变量相对上层来说也是local。

5.2 作用域产生 

在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码
块(如if、try、for等)是不会引入新的作用域的,如下代码:

>>> if 2>1:
>>>     x = 1
>>> print(x)  # 1
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。

>>> def test():
>>>     x = 2
>>> print(x)                     # NameError: name 'x2' is not defined
def、class、lambda是可以引入新作用域的。 

5.3 变量的修改 

>>> x=6
>>> def f2():
>>>     print(x)
>>>     x=5
>>> f2()

# 错误的原因在于print(x)时,解释器会在局部作用域找,会找到x=5(函数已经加载到内存),但x使用在声明前了,
所以报错:
# local variable 'x' referenced before assignment.如何证明找到了x=5呢?简单:注释掉x=5,x=6
# 报错为:name 'x' is not defined
#同理
>>> x=6
>>> def f2():
>>>     x+=1 #local variable 'x' referenced before assignment.
>>> f2()

5.4 global关键字 

当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,
当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,
代码如下:

>>> count = 10
>>> def outer():
>>>     global count   
>>>     print(count)              #10            
>>>     count = 100
>>>     print(count)              #100
>>> outer()

5.5 nonlocal关键字 

global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,
外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了

>>> def outer():
>>>     count = 10
>>>     def inner():
>>>         nonlocal count
>>>         count = 20
>>>         print(count)                         #20
>>>     inner()
>>>     print(count)                            #20
>>> outer()

5.6 小结 

(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;

(2)只有模块、类、及函数才能引入新作用域;

(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;

(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal
关键字。nonlocal是python3新增的关键字,有了这个 关键字,就能完美的实现闭包了。 

六 递归函数

定义:在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
实例1(阶乘)

>>> def factorial(n):
>>>     result=n
>>>     for i in range(1,n):
>>>         result*=i
>>>     return result 
>>> print(factorial(4))

#**********递归*********
>>> def factorial_new(n):
>>>     if n==1:
>>>         return 1
>>>     return n*factorial_new(n-1)
>>> print(factorial_new(3))

实例2(斐波那契数列)

>>> def fibo(n):
>>>     before=0
>>>     after=1
>>>     for i in range(n-1):
>>>         ret=before+after
>>>         before=after
>>>         after=ret
>>>     return ret
>>> print(fibo(3))

#**************递归*********************

>>> def fibo_new(n):#n可以为零,数列有[0]

>>>     if n <= 1:
>>>         return n
>>>     return(fibo_new(n-1) + fibo_new(n-2))
>>> print(fibo_new(3))                                       #1

>>> print(fibo_new(30000))            #maximum recursion depth exceeded in comparison
递归函数的优点:    是定义简单,逻辑清晰。理论上,所有的递归函数都可以写成循环的方式,
但循环的逻辑不如递归清晰。

递归特性:

1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,
每当进入一个函数调用,栈就会加一层栈帧,每当函数返     回,栈就会减一层栈帧。由于栈的大小不是无限的,
所以,递归调用的次数过多,会导致栈溢出。)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章