DataWhale学习计划(第六期):python基础任务4

本文详细介绍了Python中的函数,包括函数关键字、函数定义、函数参数(位置参数、默认参数、可变参数、关键字参数、命名关键字参数)及作用域。函数返回值部分讨论了返回值类型和return语句的使用。文章通过实例讲解了各种参数类型,并探讨了函数作用域的LEGB原则,帮助读者深入理解Python函数的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 函数关键字

关键字

是python内置的,具有特殊意义的标识符。
关键字后面不需要使用括号。

# 一些查看内置关键字的命令
>>> import keyword
>>> print(keyword.kwlist)
>>> print(len(keyword.kwlist))

函数

封装了独立功能,可以直接调用。
格式:函数名(参数)
函数名需要机械性记忆。

方法

方法和函数类似,同样是封装了独立的功能。
方法需要通过对象来调用,表示针对这个对象要做的操作:

>>> 对象.方法名(参数)

在变量后面输入.,然后选择针对这个变量要进行的操作,记忆起来会比函数要简单的多。

2. 函数的定义

def 函数名():
函数封装的代码
1.def是英文define的缩写
2.函数名称应该能够表达函数封装代码的功能,方便后续的调用
3.函数名称的命名应该符合标识符的命名规则:可由字母,下划线和数字组成,不能以数字开头,不能与关键字重名
4.定义一个函数要使用def语句,依次写出函数名、括号、括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回。
在这里插入图片描述
5.空函数
如果想定义一个什么事也不做的空函数,可以用pass语句:

def nop():
    pass

pass可以用来作为占位符,比如现在还没想好怎么写函数的代码,就可以先放一个pass,让代码能运行起来。
pass还可以用在其他语句里,比如:

if age >= 18:
    pass

缺少了pass,代码运行就会有语法错误。

3. 函数参数与作用域

参数

位置参数
我们先写一个计算x2的函数:

def power(x):
    return x * x

对于power(x)函数,参数x就是一个位置参数。
当我们调用power函数时,必须传入有且仅有的一个参数x:

>>> power(5)
25
>>> power(15)
225

把power(x)修改为power(x, n),用来计算xn:

def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
对于这个修改后的power(x, n)函数,可以计算任意n次方:

>>> power(5, 2)
25
>>> power(5, 3)
125

修改后的power(x, n)函数有两个参数:x和n,这两个参数都是位置参数,调用函数时,传入的两个值按照位置顺序依次赋给参数x和n。

默认参数
新的power(x, n)函数定义没有问题,但是,旧的调用代码失败了,原因是我们增加了一个参数,导致旧的代码因为缺少一个参数而无法正常调用:

>>> power(5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'

Python的错误信息很明确:调用函数power()缺少了一个位置参数n。
这个时候,默认参数就排上用场了。由于我们经常计算x2,所以,完全可以把第二个参数n的默认值设定为2:

def power(x, n=2):
    s = 1
    while n > 0:
        n = n - 1
        s = s * x
    return s

这样,当我们调用power(5)时,相当于调用power(5, 2):

>>> power(5)
25
>>> power(5, 2)
25

默认参数可以简化函数的调用。设置默认参数时,有几点要注意:
一 必选参数在前,默认参数在后,否则Python的解释器会报错;
二 设置默认参数:当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
三 默认参数降低了函数调用的难度,而一旦需要更复杂的调用时,又可以传递更多的参数来实现。无论是简单调用还是复杂调用,函数只需要定义一个
四 定义默认参数要牢记一点:默认参数必须指向不变对象!

可变参数
在Python函数中,还可以定义可变参数。顾名思义,可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个。
我们以数学题为例子,给定一组数字a,b,c……,请计算a2 + b2 + c2 + ……。要定义出这个函数,我们必须确定输入的参数。由于参数个数不确定,我们首先想到可以把a,b,c……作为一个list或tuple传进来,这样,函数可以定义如下:

def calc(numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

但是调用的时候,需要先组装出一个list或tuple:

>>> calc([1, 2, 3])
14
>>> calc((1, 3, 5, 7))
84

如果利用可变参数,调用函数的方式可以简化成这样:

>>> calc(1, 2, 3)
14
>>> calc(1, 3, 5, 7)
84

所以,我们把函数的参数改为可变参数:

def calc(*numbers):
    sum = 0
    for n in numbers:
        sum = sum + n * n
    return sum

定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加了一个*号。在函数内部,参数numbers接收到的是一个tuple,因此,函数代码完全不变。但是,调用该函数时,可以传入任意个参数,包括0个参数:

>>> calc(1, 2)
5
>>> calc()
0

如果已经有一个list或者tuple,Python允许你在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:

>>> nums = [1, 2, 3]
>>> calc(*nums)
14

*nums表示把nums这个list的所有元素作为可变参数传进去。这种写法相当有用,而且很常见。

关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。请看示例:

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

函数person除了必选参数name和age外,还接受关键字参数kw。在调用该函数时,可以只传入必选参数:

>>> person('Michael', 30)
name: Michael age: 30 other: {}

也可以传入任意个数的关键字参数:

>> person('Bob', 35, city='Beijing')
name: Bob age: 35 other: {'city': 'Beijing'}
>>> person('Adam', 45, gender='M', job='Engineer')
name: Adam age: 45 other: {'gender': 'M', 'job': 'Engineer'}

关键字参数可以扩展函数的功能。比如,在person函数里,我们保证能接收到name和age这两个参数,但是,如果调用者愿意提供更多的参数,我们也能收到。试想你正在做一个用户注册的功能,除了用户名和年龄是必填项外,其他都是可选项,利用关键字参数来定义这个函数就能满足注册的需求。
和可变参数类似,也可以先组装出一个dict,然后,把该dict转换为关键字参数传进去:

>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}

extra表示把extra这个dict的所有key-value用关键字参数传入到函数的kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。

命名关键字参数
对于关键字参数,函数的调用者可以传入任意不受限制的关键字参数。至于到底传入了哪些,就需要在函数内部通过kw检查。
仍以person()函数为例,我们希望检查是否有city和job参数:

def person(name, age, **kw):
    if 'city' in kw:
        # 有city参数
        pass
    if 'job' in kw:
        # 有job参数
        pass
    print('name:', name, 'age:', age, 'other:', kw)

但是调用者仍可以传入不受限制的关键字参数:

>>> person('Jack', 24, city='Beijing', addr='Chaoyang', zipcode=123456)

如果要限制关键字参数的名字,就可以用命名关键字参数,例如,只接收city和job作为关键字参数。这种方式定义的函数如下:

def person(name, age, *, city, job):
    print(name, age, city, job)

和关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命名关键字参数。

调用方式如下:

>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer

如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了:

def person(name, age, *args, city, job):
    print(name, age, args, city, job)

命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错:

>>> person('Jack', 24, 'Beijing', 'Engineer')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: person() takes 2 positional arguments but 4 were given

由于调用时缺少参数名city和job,Python解释器把这4个参数均视为位置参数,但person()函数仅接受2个位置参数。

命名关键字参数可以有缺省值,从而简化调用:

def person(name, age, *, city='Beijing', job):
    print(name, age, city, job)

由于命名关键字参数city具有默认值,调用时,可不传入city参数:

>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer

使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个作为特殊分隔符。如果缺少,Python解释器将无法识别位置参数和命名关键字参数:

def person(name, age, city, job):
    # 缺少 *,city和job被视为位置参数
    pass

参数组合
在Python中定义函数,可以用必选参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。

作用域

在一个Python程序只用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。也就是说,在代码中变量名被赋值的位置决定了这个变量名能被访问到的范围,也即决定了它存在于哪个命名空间中。
除了打包程序之外,函数还为程序增加了一个额外的命名空间层:默认情况下,一个函数所有变量名都是与函数的命名空间相关联的。这意味着:
一个在def内的定义的变量能够在def内的代码使用,不能在函数的外部应用这样的变量名。
def之中的变量名与def之外的变量名并不冲突,一个在def之外被赋值的变量X与在这个def之中赋值的变量X是完全不同的变量。
作用域法则
在开始编写函数之前,我们编写的所有代码都是位于一个模块的顶层(也就是说,并不是嵌套在def之中),所以我们使用的变量名要么是存在于模块文件本身,要么就是Python内置预先定义好的。函数定义本地作用域,而模块定义的全局作用域。这两个作用域有如下关系:
1.内嵌的模块是全局作用域 每个模块都是一个全局作用域(也就是说,一个创建于模块文件顶层的变量的命名空间)。对于模块外部来说,该模块的全局变量就成为了这个模块对象的属性,但是在这个模块中能够像简单的变量一样使用。
2.全局作用域的作用范围仅限于单个文件 这里的全局指的是在一个文件的顶层的变量名仅对于这个文件内部的代码而言是全局的。在Python中是没有基于一个单个的、无所不包的情景文件的全局作用域的。
3.每次对函数的调用都创建了一个新的本地作用域
4.赋值的变量名除非声明为全局变量或非局部变量,否则均为局部变量
5.所有的变量名都可以归纳为本地、全局或者内置的
变量名解析:LEGB原则
Python的变量名解析机制有时称为LEGB法则,当在函数中使用未认证的变量名时,Python搜索4个作用域:
1.本地作用域(L)

2.上一层结构中def或lambda的本地作用域(E)(其实就是函数嵌套的情况)
对于一个函数来说:
一个引用(X)首先在本地(函数内)作用域查找变量名X;之后会在代码的语法上嵌套了的函数中的本地作用域,从内到外查找;之后查找当前的全局作用域(模块文件);最后在内置作用域内(模块builtin)。全局声明将会直接从全局(模块文件)作用域进行搜索。其实就是从引用X的地方开始,一层一层网上搜索,直到找到的第一个X。
在默认情况下,一个赋值(X=value)创建或修改了变量名X的当前作用域。如果X在函数内部声明为全局变量,它将会创建或改变变量名X为整个模块的作用域。另一方面,如果X在函数内部声明为nonlocal,赋值会修改最近的嵌套函数的本地作用域中的名称X。

3.全局作用域(G)
global语句是一个命名空间的声明,它告诉Python解释器打算生成一个或多个全局变量,也就是说,存在于整个模块内部作用域(命名空间)的变量名。关于全局变量名:
全局变量是位于模块文件内部顶层的变量名。
全局变量如果是在函数内部被赋值的话,必须经过声明。
全局变量名在函数的内部不经过声明也可以被引用。
global语句包含了关键字global,其后跟着一个或多个由逗号分开的变量名。当在函数主题被赋值或引用时,所有列出来的变量名将被映射到整个模块的作用域内。 举个例子:

X=88
def func():
 global X
 X = 99
 
func()
print(X) #Prints 99

4.最后是内置作用域(B)
内置作用域是通过一个名为builtin的标准模块来实现的,但是这个变量名自身并没有放入内置作用域内,所以必须导入这个文件才能够使用它。在Python3.0中,可以使用以下的代码来查看到底预定义了哪些变量:

import builtins
dir(builtins)

Python按顺序在上面4个作用域中查找变量,并且在第一个能够找到这个变量名的地方停下来,如果在这4个作用域中都没找到,Python会报错。
这里需要强调的是,上面四个作用域是函数中代码的搜索过程,也就是说,在函数中能直接使用上一层中的变量!

s=10
def times(x,y):
 x=s
 return x*y
 
times(3,4) #return 40 not 12

4. 函数返回值

一个函数可以返回一个计算结果,也可以返回一个函数。
返回一个函数时,牢记该函数并未执行,返回函数中不要引用任何可能会变化的变量。

返回值简介
1.简单介绍 print 和 return 的区别,print 仅仅是打印在控制台,而 return 则是将 return 后面的部分作为返回值作为函数的输出,可以用变量接走,继续使用该返回值做其它事。
2.函数需要先定义后调用,函数体中 return 语句的结果就是返回值。如果一个函数没有 reutrn 语句,其实它有一个隐含的 return 语句,返回值是 None,类型也是 ‘NoneType’。
3.return 语句的作用:结束函数调用、返回值

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

return 语句位置与多条 return 语句
1.python 函数使用 return 语句返回 “返回值”,可以将其赋给其它变量作其它的用处;
2.所有函数都有返回值,如果没有 return 语句,会隐式地调用 return None 作为返回值;
3.一个函数可以存在多条 return 语句,但只有一条可以被执行,如果没有一条 reutrn 语句被执行,同样会隐式调用 return None 作为返回值;
4.如果有必要,可以显式调用 return None 明确返回一个None(空值对象)作为返回值,可以简写为 return,不过 python 中懒惰即美德,所以一般能不写就不写;
5.如果函数执行了 return 语句,函数会立刻返回,结束调用,return 之后的其它语句都不会被执行了

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

https://blog.youkuaiyun.com/sj349781478/article/details/79399213
https://blog.youkuaiyun.com/weixin_41131904/article/details/87438558
https://blog.youkuaiyun.com/ningyuxuan123/article/details/81113447
https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/001431679203477b5b364aeba8c4e05a9bd4ec1b32911e2000
https://blog.youkuaiyun.com/lxlmycsdnfree/article/details/78595838

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值