Python 的函数

发布于 2021-06-16 12:35:36 字数 4582 浏览 1487 评论 0

函数的参数

  • 必选参数
  • 默认参数
  • 可变参数

在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是 1 个、2 个到任意个,还可以是 0 个。 这些可变参数在函数调用时自动组装为一个 tuple。

def calc(*numbers):
  sum = 0
  for n in numbers:
    sum = sum + n * n return sum // 结果 calc(1, 2) 5 calc() 0

Python 允许你在 list 或 tuple 前面加一个 * 号,把 list 或 tuple 的元素变成可变参数传进去。

nums = [1, 2, 3]
calc(*nums)
  • 关键字参数

关键字参数允许你传入 0 个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个 dict。

def person(name, age, **kw):
  print 'name:', name, 'age:', age, 'other:', kw

参数组合

在 Python 中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺 序必须是:必选参数、默认参数、可变参数和关键字参数。

小结

Python的函数具有非常灵活的参数形态,既可以实现简单的调用,又可以传入非常复杂的参数。

默认参数一定要用不可变对象,如果是可变对象,运行会有逻辑错误!

要注意定义可变参数和关键字参数的语法:

  • *args 是可变参数,args 接收的是一个 tuple;
  • **kw 是关键字参数,kw 接收的是一个 dict。

以及调用函数时如何传入可变参数和关键字参数的语法:

  • 可变参数既可以直接传入:func(1, 2, 3),又可以先组装 list 或 tuple,再通过 *args 传入:func(*(1, 2, 3));
  • 关键字参数既可以直接传入:func(a=1, b=2),又可以先组装 dict,再通过 **kw 传入:func(**{'a': 1, 'b': 2})。

使用 *args 和 **kw 是 Python 的习惯写法,当然也可以用其他参数名,但最好使用习惯用法。

函数的返回值

1、指定返回值

函数体中 return 语句有指定返回值时返回的就是其值

2、隐含返回值

函数体中没有 return 语句时,函数运行结束会隐含返回一个 None 作为返回值,类型是 NoneType
与 return 、return None 等效,都是返回 None。

3、返回值类型

无论定义的是返回什么类型,return 只能返回单值,但值可以存在多个元素。
return [1,3,5] 是指返回一个列表,是一个列表对象,1,3,5 分别是这个列表的元素
return 1,3,5 看似返回多个值,隐式地被Python封装成了一个元祖返回

注意:

  • return 后续代码不会被执行
  • 只能返回一次,如果要返回多个数据,可先把多个数据包装成一个集合。整体返回(列表、元组、字典.......)

内嵌函数和闭包

内嵌函数

如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数(内嵌函数)。

闭包

在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函 数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

#闭包函数的实例
# outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
    b = 10
    # inner是内函数
    def inner():
        #在内函数中 用到了外函数的临时变量
        print(a+b)
    # 外函数的返回值是内函数的引用
    return inner

闭包中内函数修改外函数局部变量

在闭包内函数中,我们可以随意使用外函数绑定来的临时变量,但是如果我们想修改外函数临时变量数值的时候发现出问题了!

在基本的python语法当中,一个函数可以随意读取全局数据,但是要修改全局数据的时候有两种方法:

  1. global 声明全局变量
  2. 全局变量是可变类型数 据的时候可以修改

在闭包内函数也是类似的情况。在内函数中想修改闭包变量(外函数绑定给内函数的局部变量)的时候:

  1. 在python3中,可以用 nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。
  2. 在python2中,没有 nonlocal 这个关键字,我们可以把闭包变量改成可变类型数据进行修改,比如列表。

修改闭包变量的实例

# outer是外部函数 a和b都是外函数的临时变量
def outer( a ):
    b = 10  # a和b都是闭包变量
    c = [a] #这里对应修改闭包变量的方法2
    # inner是内函数
    def inner():
        #内函数中想修改闭包变量
        # 方法1 nonlocal关键字声明
        nonlocal  b
        b+=1
        # 方法二,把闭包变量修改成可变数据类型 比如列表
        c[0] += 1
        print(c[0])
        print(b)
    # 外函数的返回值是内函数的引用
    return inner

还有一点需要注意:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量 实际上只有一份,每次开启内函数都在使用同一份闭包变量

#coding:utf8
def outer(x):
    def inner(y):
        nonlocal x
        x+=y
        return x
    return inner
a = outer(10)
print(a(1)) //11
print(a(3)) //14

两次分别打印出 11 和 14,由此可见,每次调用 inner 的时候,使用的闭包变量 x 实际上是同一个。

闭包有啥用

1、装饰器!装饰器是做什么的??其中一个应用就是,我们工作中写了一个登录功能,我们想统计这个功能执行花了多长时间,我们可以用装饰器装饰这 个登录模块,装饰器帮我们完成登录函数执行之前和之后取时间。

2、面向对象!经历了上面的分析,我们发现外函数的临时变量送给了内函数。大家回想一下类对象的情况,对象有好多类似的属性和方法,所以我们创建类,用类创建出来的对象都具有相同的属性方法。闭包也是实现面向对象的方法之一。在 python 当中虽然我们不这样用,在其他编程语言入比如 JavaScript 中,经常用闭包来实现面向对象编程

3、实现单利模式! 其实这也是装饰器的应用。单利模式毕竟比较高大,,需要有一定项目经验才能理解单利模式到底是干啥用的,我们就不探讨了。

匿名函数

python 使用 lambda 来创建匿名函数。 匿名函数有个限制,就是只能有一个表达式,不用写 return,返回值就是该表达式的结果。

>>> map(lambda x: x * x, [1, 2, 3, 4, 5, 6, 7, 8, 9])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

通过对比可以看出,匿名函数 lambda x: x * x 实际上就是:

def f(x):
    return x * x

关键字lambda表示匿名函数,冒号前面的x表示函数参数。

lambda 这个名称来自于 LISP,而 LISP 则是从 lambda calculus(一种符号逻辑形式)取这个名称的。 在 Python 中,lambda 作为一个关键字,作为引入表达式的语法。想比较 def 函数,lambda 是单一的表达式,而不是语句块。

所谓匿名,意即不再使用 def 语句这样标准的形式定义一个函数。

1、lambda 只是一个表达式,函数体比 def 简单很多。
2、lambda 的主体是一个表达式,而不是一个代码块。仅仅能在 lambda 表达式中封装有限的逻辑进去。
3、lambda 函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
4、虽然 lambda 函数看起来只能写一行,却不等同于 C 或 C++ 的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

匿名函数的优点

1、使用 Python 写一些脚本时,使用 lambda 可以省去定义函数的过程,让代码更加精简。
2、对于一些抽象的,不会被别的地方再重复使用的函数,有时候函数起个名字也是个难题,使用 lambda 不需要考虑命名的问题
3、使用 lambda 在某些时候然后代码更容易理解

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

沧笙踏歌

文章 0 评论 0

山田美奈子

文章 0 评论 0

佚名

文章 0 评论 0

岁月无声

文章 0 评论 0

暗藏城府

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文