【Python】-4.Python中的函数


在编程中,我们经常要调用相同或者类似的操作,这些相同或者类似的操作是由同一段代码完成的,而函数的出现,可以帮助我们避免重复编写这些代码。函数的作用就是把相对独立的某个功能抽象出来,使之成为一个独立的实体。

例如,我们开发一个支持人与人之间对话的社交网站,“对话”这个功能实现起来比较复杂,我们可以将它封装为一个函数,每次调用函数就可以发起对话。大型网站都有日志功能,所有重要操作都会记录日志,而日志处理需要由多行Python文件操作的相关代码组成,将这些代码组装为函数,每次写日志调用此函数即可。

1. 函数的定义

定义一个函数以 def 开头

def function_name(arg1, arg2):
function body
return value

  • 函数名(function_name): 和Python中其他标识符命名规则相同,有效的函数名以字母或下划线开头,后面可以跟字母、数字或下划线,函数名应该能反映函数的功能。

    注意: Python 中函数名区分大小写,字母相同但是大小写不同的函数视为两个不同的函数

  • 函数参数(arg1, arg2): 调用一个函数时可以传递的参数,参数可以有一个或多个,也可以没有参数

  • 函数内容(function body): 任何有效的代码都可以出现在函数内部。函数内容和 def 缩进 4 个空格

  • 函数返回值(return value): 函数执行完成后返回的值。也可以不返回任何内容,不返回内容可视为返回 “None”

def introduce(name):
    print("Hello", name)


introduce("world") # Hello world
introduce("soulballad") # Hello soulballad

2. 函数的参数

在创建函数时,可以设置参数,也可以不设置参数。对于设置参数的函数,调用时需要向函数内传递参数,被传入的参数称为实参,函数定义时的参数为形参。

Python 中的参数可以分为以下几种类型:

  • ❤ 1. 必须参数
  • ❤ 2. 关键字参数
  • ❤ 3. 默认参数
  • ❤ 4. 可变参数
  • ❤ 5. 组合参数

2.1 必须参数

必须参数:顾名思义就是函数调用时必须传入,并且在调用时数量和顺序必须和定义时参数保持一致

def add(a, b):
    print("a + b =", a + b)

add(1, 2) # a + b = 3

add(1) # 如果只传入一个参数,出现错误: TypeError: add() missing 1 required positional argument: 'b'
add(1,2,3) # 如果多传入一个参数,出现错误: TypeError: add() takes 2 positional arguments but 3 were given

2.2 关键字参数

使用关键字参数可以不按函数定义时的参数顺序来调用函数,Python解释器能够根据函数定义时的参数名字来匹配参数

def hello(name, age):
    print("姓名:", name)
    print("年龄:", age)

# 按顺序传递参数
hello(name="零一", age=18)
# 姓名: 零一
# 年龄: 18

# 不按顺序传递参数
hello(age=3, name="小明")
# 姓名: 小明
# 年龄: 3

hello(name="张三",age=20,gender="男") # 传入没有定义的参数,出现错误: TypeError: hello() got an unexpected keyword argument 'gender'

2.3 默认参数

在定义函数时可以给函数添加默认值,如果调用函数时没有传入参数,函数就会使用默认值,并且不会像必传参数那样报错

def default_value(name, age=18):
    print("我的名字是:", name)
    print("我今年:", age, "岁")

default_value("零一")
# 我的名字是: 零一
# 我今年: 18 岁

注意: 默认参数必须定义在最后,而且在默认参数之后定义必须参数会报错

def default_value(age=10, name):
    print("我的名字是:", name)
    print("我今年:", age, "岁")
# SyntaxError: non-default argument follows default argument

默认参数用法:

def student_score(name, score=60, location="Shanghai"):
    print("姓名:", name)
    print("成绩:", score)
    print("地区:", location)

print("---------- 传入所有参数 ----------")
student_score("张三", 100, "Beijing")
print("---------- 不传最后一个参数 ----------")
student_score("小明", 80)
print("---------- 不传中间参数 ----------")
student_score("小红", location="广州")
print("---------- 只传必须参数 ----------")
student_score("胖虎")
print("---------- 只传关键字参数 ----------")
student_score(name="元太")

# ---------- 传入所有参数 ----------
# 姓名: 张三
# 成绩: 100
# 地区: Beijing
# ---------- 不传最后一个参数 ----------
# 姓名: 小明
# 成绩: 80
# 地区: Shanghai
# ---------- 不传中间参数 ----------
# 姓名: 小红
# 成绩: 60
# 地区: 广州
# ---------- 只传必须参数 ----------
# 姓名: 胖虎
# 成绩: 60
# 地区: Shanghai
# ---------- 只传关键字参数 ----------
# 姓名: 元太
# 成绩: 60
# 地区: Shanghai

2.4 可变参数

在某些情况下,不能再定义时就确定参数的数量和内容,这时就可以使用可变参数

2.4.1 语法

可变参数语法如下:

some_func(*args, **kwargs)

  • some_func 为函数名
  • *args 和 **kwargs 为可变参数

2.4.2 *args可变参数

def foo(*args):
    print(args)

foo()
foo(1, 2)
foo("Python", "function", "parameters")

# ()
# (1, 2)
# ('Python', 'function', 'parameters')

2.4.3 **kwargs可变参数

def foo(**kwargs):
    print(kwargs)

foo()
foo(name="python study")

# {}
# {'name': 'python study'}

2.4.4 混合参数

从上面例子可以看出: *args 参数获取到的是一个元组**kwargs 参数获取到的是一个字典。在日常使用中,*args 和 **kwargs 经常出现,用于解决一些未知问题

def calculate_sum(*args, **kwargs):
    s = 0
    for i in args:
        s += i
    print("输入的数字之和是:", s)
    for k, v in kwargs.items():
        print(k, v)

calculate_sum(1, 2, 3, 4, 5, name="python")

# 输入的数字之和是: 15
# name python

2.4.5 可变参数传递未知参数

使用可变参数的方式来传递未知参数

def exp(*args, **kwargs):
    print(args)
    print(kwargs)

l = (1, 2, 3, 4)
d = {"参数1": "arg1", "参数2": "arg2"}
exp(l, d)
exp(*l, **d)

# ((1, 2, 3, 4), {'参数1': 'arg1', '参数2': 'arg2'})
# {}
# (1, 2, 3, 4)
# {'参数1': 'arg1', '参数2': 'arg2'}

3. 变量作用域

Python 中有两种最基本的变量作用域:局部变量和全局变量

3.1 局部变量

一般情况下,在函数内赋值的变量,不做特殊声明的变量都是局部变量

def foo():
    x = "hello"
    print(x)

foo() # hello

3.2 全局变量

在函数外赋值的变量就是全局变量,全局变量可以在整个程序范围内被访问

3.2.1 全局变量使用

x = "hello"

def foo():
    print(x)

foo() # hello
print(x) # hello

3.2.2 重写全局变量

函数体内重写赋值的同名变量,不会改变函数体外的全局变量

x = "函数体外"

def foo():
    x = "函数体内"
    print(x)

foo() # 函数体内
print(x) # 函数体外

3.2.3 修改全局变量

使用 global 关键字在函数体内对函数体外的全局变量进行修改

x = "函数体外"

def foo():
    global x
    x = "函数体内"
    print(x)

foo() # 函数体内
print(x) # 函数体内

4. 函数返回值

如果想要获取函数中的局部变量,可以使用 “return” 关键字进行返回

4.1 有返回值

def foo():
    x = "局部变量"
    return x

result = foo()
print(result) # 局部变量

4.2 无返回值

def no_return():
    print("没有return")

def no_return_value():
    print("有return没有返回值")
    return

def has_return():
    x = "局部变量"
    print("有return有返回值")
    return x

result1 = no_return()
print(result1) 
# 没有return
# None

result2 = no_return_value()
print(result2) 
# 有return没有返回值
# None

result3 = has_return()
print(result3)
# 有return有返回值
# 局部变量

4.3 多个返回值

def multi_value():
    r1 = "第一个返回值"
    r2 = "第二个返回值"
    r3 = "第三个返回值"
    r4 = "第四个返回值"
    r5 = "第五个返回值"
    return r1, r2, r3, r4, r5

s = multi_value()
print(s) # ('第一个返回值', '第二个返回值', '第三个返回值', '第四个返回值', '第五个返回值')

从执行结果来看,有多个返回结果时,Python 会返回一个元组;当Python返回了元祖时,就可以赋值给多个变量了

4.4 获取多个返回值

    return "第一个返回值", "第二个返回值"

r1, r2 = two_value()
print(r1) # 第一个返回值
print(r2) # 第二个返回值

5. Lambda表达式

Lambda 表达式也称作匿名函数。

5.1 Lambda 定义

以 “lambda” 开头,就表示是 lambda 表达式。它由 “:” 分为两部分,左边的是函数的参数,右边的是要返回的值。

lambda 表达式不需要用 return 关键字返回内容,函数默认会返回 “:” 右边的值

def add(x, y):
    return x+y

lambda x,y: x+y

5.2 Lambda 使用场景

lambda 表达式一般有两种使用情况:

  1. 程序只执行一次,不需要定义函数,使用 lambda 表达式方便定义,且节省了内存中变量的定义
  2. 在某些函数中必须以函数作为参数,但是函数本身十分简单且在一处使用
f = lambda x, y: x+y

z = f(1,2)
print(f) # <function <lambda> at 0x000001D1DC518B80>
print(z) # 3

5.3 filter过滤

filter 是 Python的内置函数,用于过滤序列,过滤掉不符合条件的元素。

filter 函数的第一个参赛需要传入另一个函数,传入的函数用来作为筛选条件,满足条件的返回 “True”,否则返回 “False”。

l1 = [1,2,3,4,5,6,7,8]
l2 = [item for item in filter(lambda x: x>5, l1)]
print(l2) # [6, 7, 8]

6. 扩展知识

6.1 文档字符串

使用 def 定义的函数,第一行可以是字符串,这个字符串就是文档字符串

def add(x, y):
    """
    返回参数x和y的两数之和
    :param x: int 第一个参数
    :param y: int 第二个参数
    :return: 返回 x+y
    """
    return x + y


print(add(1, 2)) # 3

# 可以使用 __doc__ 方式获取文档字符串
print(add.__doc__)
#   返回参数x和y的两数之和
#   :param x: int 第一个参数
#   :param y: int 第二个参数
#   :return: 返回 x+y

6.2 内置函数

Python 解释器内置了很多不同功能和类型的函数,可以直接使用

截取自菜鸟教程:Python 内置函数

abs() divmod() input() open() staticmethod()
all() enumerate() int() ord() str()
any() eval() isinstance() pow() sum()
basestring() execfile() issubclass() print() super()
bin() file() iter() property() tuple()
bool() filter() len() range() type()
bytearray() float() list() raw_input() unichr()
callable() format() locals() reduce() unicode()
chr() frozenset() long() reload() vars()
classmethod() getattr() map() repr() xrange()
cmp() globals() max() reverse() zip()
compile() hasattr() memoryview() round() import()
complex() hash() min() set()
delattr() help() next() setattr()
dict() hex() object() slice()
dir() id() oct() sorted() exec 内置表达式

6.3 函数注释

函数注释是一个可选功能,它允许在函数参数和返回值中添加任意的元数据

函数注释定义如下:

def function_name(a:expression, b:expression) -> expression:
function body
return value

def compile(source: "something compilable",
            filename: "where the compilable thing comes from",
            mode: "is this a single statement or a suite?") -> bool:
    return True

print(compile.__annotations__)
# {'source': 'something compilable', 'filename': 'where the compilable thing comes from', 'mode': 'is this a single statement or a suite?', 'return': <class 'bool'>}

文章作者: Soulballad
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Soulballad !
评论
 上一篇
【Python】-5.Python面向对象 【Python】-5.Python面向对象
Python是一门面向对象的语言,所以在Python中需要创建类和对象 1. 面向对象1.1 类的创建类的定义: class [类名]: [语法块] class EmptyClass: pass 1.2 类的使用class
2020-09-08
下一篇 
【Python】-3.Python中的流程控制 【Python】-3.Python中的流程控制
所有编程语言在编写时都要遵循语言结构和流程控制,它们控制了整个程序运行的步骤。流程控制包括顺序控制、条件控制和循环控制。所谓控制顺序,就是按照正常的代码执行顺序,从上到下、从文件头到文件尾依次指定每条语句。 1. if判断1.1 if语
2020-09-05
  目录