经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » Python » 查看文章
第10天 函数详解
来源:cnblogs  作者:沉沦的罚  时间:2018/10/15 9:26:17  对本文有异议

一. 人生三问

  1. 1. 什么是函数
      函数就是用def关键字声明的为了实现一组功能的代码块。
  2. 2. 为什么要用函数
      在开发程序的过程中,我们可能会遇到一些相同的功能,为了避免写重复的代码,从而出现了函数。
  3. 3. 怎么使用函数
      函数分为定义和调用两个阶段,函数名()就是调用函数的过程
  1.   # 函数的定义
  2.   def fun1(x, y, z):
  3.   '''注释'''
  4.   code1
  5.   code2
  6.   return x, y, z
  7.   # 函数调用
  8.   fun1(1, 2, 3)

 

二. 函数的使用原则

  1. # 函数在调用过程中必须要先定义才能进行使用

    1. 函数的定义阶段
      只检测函数体中是否存在语法错误
  2. 2. 函数的调用阶段
      调用过程才会去真正的执行代码块,查看是否有逻辑错误

测试:

  1. def fun1():
  2. print('from fun1')
  3. bar()
  4. # 当执行fun1代码的时候发现要执行bar
  5. # 但是bar函数还没有定义,所以报错
  6. fun1()
  7. def bar():
  8. print('from bar')
View Code

1. 函数的三种定义方式

  1. 1. 无参函数
  2. 2. 有参函数
  3. 3. 空函数

 

2. 函数的三种调用方式

  1. 1. 语句的形式 =====》 register()
  2. 2. 表达式调用========》 res = register() * 12
  3. 3. 作为参数传递调用 ===========》

 

3. return的特点

  1. 功能
  2. 1. 可以返回值
  3. 1.1 函数的返回值没有类型的限制
  4. 1.2 函数的返回值没有个数的限制
         <1>.返回的是一个值就是函数本身
         <2>.返回多个值就是元祖
         <3>.返回0个值或者干脆没有就返回None
    2. 可以结束函数的执行
  5. 函数内可以有多个return,只要执行了任意一个return函数就结束了

 

三. 参数详解

参数的分类:

  1. 1. 形式参数(形参)
      在函数定义阶段,传递的参数就是形参
  2. 2. 实际参数(实参)
      在函数调用阶段,传递的参数就是实参
    细分:
      1. 位置参数
      2. 关键字参数(默认形参)
      3. 可变长参数
  1. # 这个是函数的定义阶段
  2. # 里面的参数x, y, z是函数的形参
  3. def fun(x, y, z):
  4. print('hhhh')
  5. # 这个是函数的调用阶段
  6. # 里面的参数1,2,3是实参
  7. fun(1, 2, 3)

 

1. 位置参数

  1. 位置参数:

    1. 位置实参
      在调用阶段,按照从左到右的顺序依次定义的参数叫做位置实参
      # 特点:与形参的值一一对应

  2. 2. 位置形参
      在定义阶段,按照从左到右的顺序依次定义的参数叫做位置形参
      # 特点:必须被传值,多一个不行,少一个不行

 

验证:

  1. # 形参和实参的值必须一一对应
  2. def fun1(x, y, z):
  3. print(x, y, z)
  4. fun1(1) # 会报错
  5. fun1(1, 2, 3)
  6. fun1(1, 2, 3, 4) # 会报错

 

2. 关键字参数

  1. 1. 关键字实参
  2. 在函数调用阶段,按照key=value的形式定义的实参叫做关键字实参
  3.    # 特点:
       # 1. 关键字实参必须放在位置实参的后面
       # 2. 不能给同一个形参赋多个值

    2. 关键字形参(默认形参)
  4. 在函数定义阶段,按照key=value的形式定义的形参叫做关键字形参。我们一般称之位默认形参
    # 特点:
       # 1. 在定义阶段已经有值,意味着在调用阶段可以不用传值
       # 2. 位置形参必须放在默认形参的前面
       # 3. 默认形参的值在定义阶段已经固定死了,之后的更改不会影响
       # 4. 默认形参的值通常应该是不可变类型

 

验证:关键字参数

  1. # 关键字参数必须放在位置参数的后面
  2. def fun1(x, y, z):
  3. print(x, y, z)
  4. fun1(1, y=2, 3) # 报错
  5. fun1(1, 2, z=3)
关键字参数必须放在位置参数的后面
  1. # 不能给同一个形参传递多个值
  2. def fun1(x, y, z):
  3. print(x, y, z)
  4. fun1(1, 2, 3, x=1)# 会报错
不能给同一个形参传递多个值

 

验证:默认形参

  1. # 调用阶段可以不用传值
  2. def func1(x, y, z=2):
  3. print(x, y, z)
  4. func1(1, 2)
调用阶段可以不用传值
  1. # 位置形参必须在默认形参之前
  2. def func1(x,z=2, y):# 会报错
  3. print(x, y, z)
  4. func1(1, 2)
位置形参必须在默认形参之前
  1. # 默认形参的值在定义阶段已经固定死了
  2. m = 10
  3. def func1(x, y, z = m):
  4. print(x, y, z)
  5. m = 100
  6. func1(1, 2) # 答案依然是10
默认形参的值在定义阶段已经固定死了
  1. # 默认形参通常应该是不可变类型
  2. # 以下例子的耦合性非常高
  3. m = []
  4. def fun1(x, y, z = m):
  5. z.append(x)
  6. z.append(y)
  7. print(z)
  8. fun1(1,2)
  9. fun1(3,4)
  10. fun1(5,6)
  11. print(m)
  12. # 结果:
  13. # [1, 2]
  14. # [1, 2, 3, 4]
  15. # [1, 2, 3, 4, 5, 6]
  16. # [1, 2, 3, 4, 5, 6]
默认形参通常应该是不可变类型

 

3. 可变长参数

  1. 1. 可变长实参
  2. 在函数调用阶段,实参值的个数是不固定的。
  3. 2. 可变长形参
  4. 在函数定义阶段,形参值的个数是不固定的。

 

可变长形参

  1. * ====》会将溢出的位置实参存到一个元祖中,然后赋值给*后面的形参中
  2. ** =====》会将溢出的关键字实参以keyvalue的形式存成字典,然后赋值给**后面的形参中

 

可变长实参

  1. * ========》会将*后面的值打散成一个个的位置实参,然后与形参一一对应
  2. ** ========》会将**后面的值以key=value的形式打散成一个个的关键字参数,然后与形参一一对应

 

 

(1) 多出来的位置实参赋值给*args

  1. def fun(x, y, *args): # args=(3, 4, 5,6)
  2. print(x, y, args)
  3. fun(1, 2, 3, 4, 5, 6)# 多出来3,4,5,6四个位置实参

 

(2)任意数求和:

  1. # 任意数求和
  2. def sum2(*args): # args=(1,2)
  3. res = 0
  4. for i in args:
  5. res += i
  6. return res
  7. res = sum2(1, 2,3)
  8. print(res)

 

(3)形参和实参的对应关系

  1. def fun(x,y,*z):# z = (1,2,3,4 )
  2. print(x, y, z)
  3. fun(11,22,*[1, 2,3,4]) # fun(11, 22, 1,2,3,4)

 

(4)*args, **kwargs的应用

  1. # *args,**kwargs可以被当作参数传递

    def
    index(name, age, sex):
  2. print(name, age, sex)
  3. def wrapper(*args, **kwargs):
  4. # args = ('egon')
  5. # kwargs = {'sex': 'male', 'agse': 18}
  6. index(*args, **kwargs)# index('egon', sex='male', agse=18)
  7. wrapper('egon',sex='male', age='18')

 

4. 命名关键字参数

  1. 关键字参数:
  2. *和**之间的定义的参数称为命名关键字参数
  3. 关键字参数:
  4. 命名关键字参数必须按照key=value的形式进行传值

 

  1. # 在*号后面的形参在实参传递的过程中必须是关键字参数
  2. def fun(x, *, y, z):
  3. print(x, y, z)
  4. fun(1, y=2, z=3)

 

四. 函数对象

  1. 函数对象:
  2. 函数是第一类对象:函数的内存地址可以像一个变量值一样去使用
    变量值的使用方法:
    1. 可以被引用
      a = 1
      b = a
    2. 可以当作参数传递
    3. 可以作为返回值
    4. 可以当作容器内的元素

1. 函数被引用

  1. def f1():
  2. print('from f1')
  3. f = f1
  4. f1 = f
  5. f()
  6. f1()

 

2. 可以被当作参数进行传递

  1. def f1(func):
  2. func()
  3. def f2():
  4. print('from f2')
  5. f1(f2)

 

3. 可以作为返回值

  1. def f1(func):
  2. return func
  3. def f2():
  4. print('from f2')
  5. f1(f2)()

 

4. 作为容器内的元素

作为功能字典使用:

  1. def login():
  2. print('login.....')
  3. def register():
  4. print('register.....')
  5. func_dict = {'1': login, '2': register}
  6. choice = input('>>').strip()
  7. if choice in func_dict:
  8. func_dict[choice]()
  9. else:
  10. print('wrong!')

 

五. 函数嵌套

  1. 函数嵌套的两种类型
  2.   1. 函数的嵌套调用
  3.   2. 函数的嵌套定义

1. 函数的嵌套调用

  1. # 函数的嵌套调用就是把一个复杂的功能拆分成
  2. # 更小的功能,然后去调用它来解决问题
  3. def max2(a, b):
  4. if a > b:
  5. return a
  6. else:
  7. return b
  8. def max4(a,b,c,d):
  9. res = max(a, b)
  10. res = max(res,c)
  11. res = max(res, d)
  12. return res
  13. print(max4(1, 2, 3, 4))

 

2. 函数的嵌套定义

  1. # 从这个例子可以看出来,函数的嵌套声明可以把一类函数
  2. # 打包到一块,然后通过传入一个参数执行不同的函数
  3.  
  4. from math import pi
  5. def circle(banjing, choice):
  6. '''choice == 1计算周长,其他的计算面积'''
  7. def zhouchang():
  8. return banjing * 2 * pi
  9. def mianji():
  10. return pi * banjing ** 2
  11. if choice == '1':
  12. res = zhouchang()
  13. else:
  14. res = mianji()
  15. return res

 

六. 名称空间

  1. 名称空间
  2. 名称空间就是python的一个专门用来存储名字和值的内存地址映射关系的一个空间。

    名称空间的分类
      1. 内置名称空间
      2. 全局名称空间
      3. 本地名称空间

    内置名称空间:
      存放的名字:存放的是python解释器自带的名字
      产生:打开python解释器的时候会产生
      销毁:关闭python解释器的时候会销毁

    全局名称空间: 
      存放的名字:存放的是顶格写入的p名字
      产生:在执行python文件的时候会产生
      销毁:在python文件执行完毕之后销毁

    局部名称空间:
      存放的名字:存放的是函数内的名字
      产生:在执行函数代码体的时候会产生
      销毁:在函数执行完毕之后会销毁


    名称空间的加载顺序: 内置名称空间----》全局名称空间-------》局部名称空间
    名称空间的销毁顺序: 局部名称空间----》全局名称空间-------》内置名称空间

    名称空间的查找顺序: 从当前名称空间一层一层往上查找

 

七. 作用域

  1. 作用域:
  2. 作用域其实就是把名称空间分成了两大类
  3. 1. 全局作用域: 内置名称空间和全局名称空间的名称
      特点: 全局存活,全局有效
  4. 2. 局部作用域: 局部名称空间的名称
      特点: 临时存活,局部有效

 

作用域关系在函数定义阶段已经定义死了,与调用的位置无关:

  1. # 例一:作用域关系在定义阶段已经定义死了
  2. xxx = 2
  3. def f1():
  4. print(xxx)
  5. xxx = 1
  6. # 此时函数执行的时候是会报错的
  7. # 原因:当定义函数f1的时候发现局部命名空间中是有xxx这个变量的
  8. # 因此无论什么时候调用f1函数都会使用局部命名空间,因此在调用
  9. # f1()函数的时候,执行print(xxx)中的xxx的时候,发现局部名称空间
  10. # 目前还没有这个变量,因此会报错。
  11. f1()
例一:作用域关系在定义阶段已经定义死了
例二:作用域关系在定义阶段已经定义死了

 

八. 闭包函数

  1. 闭包函数运用的知识:
  2. 函数嵌套: 闭包函数就是在一个函数外面包上一层函数
  3. 函数对象: 会返回内部函数的内存地址
  4. 作用域关系:会传递值给内部函数进行使用

  5. # 创建了一个闭包函数innter
  6. def outter():
  7. x = 1
  8. def innter(): # 函数的嵌套
  9. print('from inner', x)  # 函数的作用域关系
  10. return innter # 函数的对象


    什么是闭包函数呢?
      闭包函数本质上就是一个函数的嵌套。在嵌套的过程中会牵涉到函数的作用域关系。应用广泛的是装饰器。

 

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号