Python青少年简明教程:函数

news2024/9/23 17:11:59

Python青少年简明教程:函数

在Python中,函数是一段可重用的代码块,用于执行特定的任务。函数能够接受输入参数,执行特定的操作,并返回结果。

Python提供了许多内置函数,如print()、len()、eval()等,可以直接使用。编程人员还可以自定义函数。

先看几个内置函数,然后重点介绍编程人员自定义函数。

内置函数

Python 提供了许多内置函数,这些函数可以在任何 Python 程序中直接使用,不需要额外导入。下面介绍几个常用的内置函数。

1) len()函数

语法(用法):

len(object)

其中,object 是你想要获取长度的对象。

用途:返回对象的长度(元素个数)

适用于:字符串、列表、元组、字典等

示例:

print(len("Hello"))  # 输出:5
print(len([1, 2, 3]))  # 输出:3

my_string = "Hello"
print(len(my_string))  # 输出 5

2) eval()函数

语法(用法):

eval(expression, globals=None, locals=None)

其中,expression 是一个字符串,必须是有效的 Python 表达式——能计算的字符串表达式。

globals(可选):一个字典,表示全局命名空间。

locals(可选):一个字典,表示局部命名空间。

示例:

x = 1
print(eval("x + 1"))  # 输出:2
result = eval("3 + 5")
print(result)  # 输出 8

# 使用字典作为命名空间的例子:
globals_dict = {"a": 5, "b": 10}
result = eval("a + b", globals_dict)
print(result)  # 输出: 15

更多的情况可参见,内置函数官方文档内置函数 — Python 3.12.5 文档

下面介绍程序员自定义函数。

函数定义

编程人员还可以自定义函数。

使用 def 关键字定义函数,后跟函数名和括号(包含参数列表)。语法:

def函数名(参数列表):

    # 函数体

    return返回值

函数名:函数名可以是任何有效的标识符,但最好是有意义的名字,能反映出函数的功能。

参数列表:在圆括号中定义,用于接收传递给函数的值。多个参数用逗号分隔。参数是可选的,如果没有参数,圆括号内为空。

函数体:包含函数执行的操作或计算。

返回值:使用 return 语句返回结果给调用者。如果没有 return 语句,函数将返回 None。

函数调用

使用函数名后跟一对括号,括号中包含参数——如果有的话。

形参(形式参数,parameters)和实参(实际参数,arguments)

形参是指函数定义中使用的参数,它们相当于占位符,用于指定函数可以接受的输入。形参在函数定义时出现,用于接收函数调用时传入的实参。

实参是指在函数调用时传递给函数的具体值。实参在函数调用时出现,用于替换形参的值。

示例:

#定义add函数
def add(x, y):  
return x + y  

result = add(5, 3)  # 调用函数,并接收返回值  
print(result)  # 输出:8

文档字符串

如果三重引号用放在函数、类或模块的开头,Python 会把它们当作文档字符串(docstring),这是一种特别的多行注释形式,用于生成文档,可以通过 __doc__ 属性 或 help(add) 函数查看。

def add(a, b):
    """返回两个数的和。
    
    参数:
    a -- 第一个数
    b -- 第二个数
    """
    return a + b

print(add.__doc__)  # 打印函数的文档字符串

在这个例子中,你可以通过 add.__doc__ 或 help(add) 来查看这个文档字符串的内容。

参数传递的内部机制

官方术语,参数传递使用按值调用(call by value)的方式(其中的值始终是对象的引用,而不是对象的值)。实际上,Python函数参数传递的始终对象的引用,而不是对象的值。这方面的内容,因一些人和资料介绍的比较混乱,特地附注。

【附注(有关官方文档节选):

The actual parameters (arguments) to a function call are introduced in the local symbol table of the called function when it is called; thus, arguments are passed using call by value (where the value is always an object reference, not the value of the object). [1] When a function calls another function, or calls itself recursively, a new local symbol table is created for that call.

https://docs.python.org/3/tutorial/controlflow.html#defining-functions

在调用函数时会将实际参数(实参)引入到被调用函数的局部符号表中;因此,实参是使用 按值调用 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)。 [1] 当一个函数调用另外一个函数时,会为该调用创建一个新的局部符号表。

https://docs.python.org/zh-cn/3/tutorial/controlflow.html#defining-functions

Remember that arguments are passed by assignment in Python. Since assignment just creates references to objects, there’s no alias between an argument name in the caller and callee, and so no call-by-reference per se.

https://docs.python.org/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference

请记住,Python 中的实参是通过赋值传递的。由于赋值只是创建了对象的引用,所以调用方和被调用方的参数名都不存在别名,本质上也就不存在按引用调用的方式。

https://docs.python.org/zh-cn/3/faq/programming.html#how-do-i-write-a-function-with-output-parameters-call-by-reference】

这种机制有时也被一些人非正式称呼较多如“传递对象引用”(pass by object reference)、按对象引用调用(call by object reference),但机制本质不变。

对于不可变对象(如整数、字符串、元组),因为其不可变性,函数内对参数的任何修改不会影响到外部变量。对于可变对象(如列表、字典、集合),函数内对参数的修改会影响到外部变量。

a)如果传入的参数是不可变类型(如数字、字符串、元组),那么在函数体内修改参数的值,并不会影响到原来的变量。因为不可变类型的变量实际上是值的引用,当试图改变变量的值时,相当于是在创建新的对象。例如:

def change_number(num):
    num = 100

x = 10
change_number(x)
print(x)  # 输出:10

在上面的例子中,尽管在函数内部num的值被改变了,但是原变量x的值并没有改变。参见下图:

b)如果传入的参数是可变类型(如列表、字典),那么在函数体内修改参数的值,会影响到原来的变量。因为可变类型的变量存储的是一个地址,当试图改变变量的值时,实际上是在改变这个地址所指向的内容。例如:

def change_list(lst):
    lst.append(100)

x = [1, 2, 3]
change_list(x)
print(x)  # 输出:[1, 2, 3, 100]

在上面的例子中,函数内部对参数lst的修改影响到了原变量x的值。参见下图:

从内存管理的角度来看,Python中的变量和参数传递有一些特点

☆ 变量是对象的引用:在Python中,变量实际上是对象的引用,而不是对象本身。当你给一个变量赋值时,实际上是将变量指向了一个对象。这意味着变量可以指向不同类型的对象,并且可以在程序中随时改变指向的对象。

☆ 引用计数:Python使用引用计数来管理内存。每个对象都有一个引用计数,表示有多少个变量引用了该对象。当引用计数为0时,对象将被自动回收。当一个变量不再引用一个对象时,引用计数会减少。当引用计数为0时,对象的内存将被释放。

☆ 对象的可变性:Python中的对象分为可变对象和不可变对象。可变对象(如列表、字典)的值可以被修改,而不可变对象(如整数、字符串、元组)的值不能被修改。这意味着如果你修改了一个可变对象,那么所有引用这个对象的变量都会受到影响。

☆ 参数传递方式:在Python中,函数的参数传递是按值调用(call by value) 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)——实际上,按对象引用调用(call by object reference)调用这种说法更好。对于不可变对象(如整数、字符串、元组),由于它们的值不能被改变,所以函数内部对这些对象的修改实际上是创建了一个新的对象。因此,函数内部的修改不会影响到函数外部的实际参数。对于可变对象(如列表、字典),由于它们的值可以被改变,所以函数内部对这些对象的修改会直接改变原始对象的值。因此,函数内部的修改会影响到函数外部的实际参数。

【附、Python语言的变量和参数传递情况https://blog.csdn.net/cnds123/article/details/134159800

多种(C++、Java、JavaScript、Python)编程语言参数传递方式介绍https://blog.csdn.net/cnds123/article/details/132981086 】

参数情况说明

☆位置参数(Positional Arguments)

位置参数是最基本的参数传递方式,按照参数在函数定义中的位置传递。例如:

def add(a, b):
    return a + b

result = add(3, 5)  # 位置参数,3 传给 a,5 传给 b
print(result)  # 输出 8

☆关键字参数(Keyword Arguments)

关键字参数通过参数名传递,可以不按照定义时的顺序传递。例如:

def greet(name, msg):
    print(f"{msg}, {name}!")

greet(name="Alice", msg="Hello")  # 关键字参数
greet(msg="Hi", name="Bob")  # 顺序可以不同

☆默认参数(Default Arguments)

默认参数在函数定义时指定了默认值,如果调用函数时没有提供该参数,则使用默认值。例如:

def greet(name, msg="Hello"):
    print(f"{msg}, {name}!")

greet("Alice")  # 使用默认参数,输出 "Hello, Alice!"
greet("Bob", "Hi")  # 覆盖默认参数,输出 "Hi, Bob!"

☆可变参数(Variable-length Arguments)

Python 支持可变数量的参数,使用 *args 和 **kwargs。

1) *args 用于传递任意数量的位置参数,接收的是一个元组。例如:

def print_numbers(*args):
    for num in args:
        print(num)

print_numbers(1, 2, 3, 4)  # 输出 1 2 3 4

2)不定长关键字参数(**kwargs)

**kwargs 用于传递任意数量的关键字参数,接收的是一个字典。例如:

def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=25)  # 输出 "name: Alice" "age: 25"

☆在 Python 3.8 及以后的版本中,函数参数传递机制中引入了两个新的语法元素:/ 和 *,它们用来指定参数的类型,即位置参数、关键字参数以及两者混合的参数。

1)仅限位置参数(Positional-only Parameters)

使用 / 将参数标记为仅限位置参数。这意味着这些参数必须通过位置进行传递,不能使用关键字来传递。例如:

def func(a, b, /, c, d):
    print(a, b, c, d)

func(1, 2, 3, 4)  # 正确
func(1, 2, c=3, d=4)  # 错误,会引发 TypeError

在这个例子中,a 和 b 必须通过位置传递,而 c 和 d 可以通过位置或关键字传递。

2)仅限关键字参数(Keyword-only Parameters)

使用 * 将参数标记为仅限关键字参数。这意味着这些参数必须通过关键字传递。例如:

def func(a, b, *, c, d):
    print(a, b, c, d)

func(1, 2, c=3, d=4)  # 正确
func(1, 2, 3, 4)  # 错误,会引发 TypeError

在这个例子中,c 和 d 必须通过关键字传递,而 a 和 b 可以通过位置或关键字传递。

3)同时使用 / 和 *

在函数定义中可以同时使用 / 和 *,以指定不同类型的参数。例如:

def func(a, b, /, c, *, d):
    print(a, b, c, d)

func(1, 2, 3, d=4)  # 正确
func(1, 2, c=3, d=4)  # 正确
func(1, 2, 3, 4)  # 错误,会引发 TypeError
func(a=1, b=2, c=3, d=4)  # 错误,会引发 TypeError

在这个例子中,a 和 b 必须通过位置传递,c 可以通过位置或关键字传递,d 必须通过关键字传递。

☆参数解包

Python 支持参数解包(unpacking),这是一种将容器(如列表、元组或字典)中的元素解包并传递给函数参数的方式。参数解包可以通过 * 和 ** 实现。

1)使用 * 解包列表或元组

当你有一个包含多个元素的列表或元组,并且你希望将这些元素作为单独的参数传递给函数时,可以使用 * 进行解包。例如:

def add(a, b, c):
    return a + b + c

numbers = [1, 2, 3]
result = add(*numbers)  # 等同于 add(1, 2, 3)
print(result)  # 输出 6

values = (4, 5, 6)
result = add(*values)  # 等同于 add(4, 5, 6)
print(result)  # 输出 15

2) 使用 ** 解包字典

当你有一个字典,并且字典的键与函数参数名匹配时,可以使用 ** 进行解包,将字典中的键值对作为关键字参数传递给函数。例如:

def greet(name, greeting, punctuation):
    print(f"{greeting}, {name}{punctuation}")

params = {'name': 'Alice', 'greeting': 'Hello', 'punctuation': '!'}
greet(**params)  # 等同于 greet(name='Alice', greeting='Hello', punctuation='!')

变量作用域(scope

Python 中的作用域(scope)是指变量的可访问范围。Python 主要有以下几种作用域:

☆全局作用域(Global)

全局变量在函数外部定义,全局作用域是在整个程序(模块或脚本文件)中都可以访问的变量。例如:

global_var = "I'm global"

def access_global():
    print(global_var)

access_global()  # 输出: I'm global
print(global_var)  # 输出: I'm global

☆局部作用域(Local)

局部作用域指的是在函数内部定义的变量,只在函数内部可见。例如:

def local_scope_example():
    x = "local"
    print(x)

local_scope_example()  # 输出: local
# print(x)  # 这会引发 NameError,因为 x 只在函数内部定义

☆闭包函数外的函数中(Enclosing)

这指的是嵌套函数中外层函数的作用域。例如:

def outer_function():
    x = "outer"
    
    def inner_function():
        print(x)  # 可以访问外层函数的变量
    
    inner_function()

outer_function()  # 输出: outer

☆内置作用域(Built-in)

这是 Python 内置的名字空间,包含了内置函数和异常名称。例如:

print(len("Python"))  # 使用内置函数 len(),输出: 6

变量查找顺序

Python 按照 LEGB规则顺序查找变量:Local → Enclosing → Global → Built-in。

例如:

x = "global"

def outer():
    x = "outer"
    
    def inner():
        x = "inner"
        print("inner:", x)
    
    inner()
    print("outer:", x)

outer()
print("global:", x)

# 输出:
# inner: inner
# outer: outer
# global: global

特别提示:

1) global 关键字

如果你想在函数内部修改全局变量,需要使用 global 关键字。例如:

count = 0

def increment():
    global count
    count += 1
    print(count)

increment()  # 输出: 1
increment()  # 输出: 2

2) nonlocal 关键字

在嵌套函数中,如果要修改外层函数的变量,需要使用 nonlocal 关键字。例如:

def outer():
    x = 0
    def inner():
        nonlocal x
        x += 1
        print(x)
    return inner

counter = outer()
counter()  # 输出: 1
counter()  # 输出: 2

理解 Python 的作用域规则对于编写清晰、可维护的代码非常重要。它可以帮助你避免命名冲突,更好地组织代码结构,并理解变量在不同上下文中的行为。

递归函数

函数调用自身的函数。需要有基本情况来结束递归。

递归是一种强大的编程技术,它允许函数调用自身来解决问题。

递归的基本概念:

递归函数是在其定义中直接或间接调用自身的函数。它通常用于解决可以被分解成相似的子问题的问题。

递归函数的结构:

一个典型的递归函数包含两个主要部分:

基本情况(Base case):不再递归调用的条件,用于终止递归。

递归情况(Recursive case):函数调用自身的部分。

示例1 - 计算阶乘

阶乘是最经典的递归函数之一。数学上,n 的阶乘(n!)定义为:

0! = 1

n! = n * (n-1)!,当n > 0时

源码如下:

def factorial(n):
    # 基准情况:当 n 为 0 时,返回 1
    if n == 0:
        return 1
    # 递归情况:n * (n-1) 的阶乘
    else:
        return n * factorial(n - 1)

print(factorial(5))  # 输出: 120

解释:

factorial(0) 返回 1(基准情况)。

factorial(n) 对于 n > 0,会递归调用 factorial(n - 1)。

计算 factorial(5) 的过程如下:

factorial(5) = 5 * factorial(4)

factorial(4) = 4 * factorial(3)

factorial(3) = 3 * factorial(2)

factorial(2) = 2 * factorial(1)

factorial(1) = 1 * factorial(0)

factorial(0) = 1(基准情况)

递归调用结束并逐步回溯,最终计算出结果 5! = 120。

匿名函数(Lambda函数)

在 Python 中,匿名函数(Anonymous Function)指的是没有名字的函数,通常使用 lambda 关键字来定义。匿名函数通常用于需要一个简单函数且只使用一次的场景。

名函数的语法非常简洁,使用 lambda 关键字定义,语法格式如下:

lambda 参数1, 参数2, ... : 表达式

lambda 是关键字,表示这是一个匿名函数。

参数1, 参数2, ... 是函数的参数,多个参数用逗号分隔。

表达式 是函数体,只能是一个表达式,计算结果就是这个函数的返回值。匿名函数的结果会自动返回,无需使用 return 关键字。

简单的匿名函数示例

一个简单的匿名函数,计算两个数的和:

add = lambda x, y: x + y

这个 lambda 表达式定义了一个匿名函数,并将其赋值给 add 变量。add 现在可以像普通函数一样使用:

result = add(3, 5)
print(result)  # 输出: 8

与普通函数的对比

匿名函数和普通函数(使用 def 关键字定义的函数)的主要区别在于匿名函数更适合定义简单的、一次性的函数。普通函数适用于更复杂的逻辑或者需要多次使用的情况下。

普通函数:

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

result = add(3, 5)
print(result)  # 输出: 8

匿名函数可写为:

add = lambda x, y: x + y
result = add(3, 5)
print(result)  # 输出: 8

在这个简单的例子中,匿名函数和普通函数的效果是一样的,但匿名函数更加简洁。

在使用像 map()、filter()、sorted()、reduce() 等高阶函数时,经常会用到匿名函数。关于高阶函数就不多说了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2099799.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java基于微信小程序的校园兼职小程序

博主介绍:✌stormjun、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇&…

shadertoy-sdf 操作

vec3 col getBackgroundColor(uv); float d1 sdCircle(uv, 0.1, vec2(0., 0.)); float d2 sdSquare(uv, 0.1, vec2(0.15, 0));float res; // result1、union res min(d1, d2); // union2、intersection res max(d1, d2); // intersection3、subtraction res max(-d1, d…

Python实战案例数据合并订单表和商品价格表数据

有如下数据,订单表和商品价格表,进行数据合并,输出客户需要的效果。 数据样例:👇 订单表: 商品价格表: 最终效果: 01实现思路 目的是将订单数据和商品价格数据按照商品id和时间进行匹配,以…

基于nodejs+vue+uniapp的学习资料销售平台小程序

开发语言:Nodejs框架:expressuniapp数据库:mysql 5.7(一定要5.7版本)数据库工具:Navicat11开发软件:VS Code 系统展示 管理员登录 管理员主界面 用户管理 学习资料管理 订单管理 系统管理 用户…

未来已来:2024年远程控制行业的新星工具推荐

个人用户对于设备管理的便捷需求,远程控制软件都以其独特的优势,搭建起一座座沟通的桥梁。今天,我们就来探索一款集高效性、安全性与易用性于一体的远程控制软件。为了软件得到的方便我会介绍比如能从向日葵远程控制官网、TD官网、GH官网能直…

用RPC Performance Inspector 优化你的区块链

目录 什么是RPC? RPC Performance Inspector 是做什么的? 为什么需要这个工具? 如何使用它? 适合谁用? 如何使用? 什么是RPC? RPC Performance Inspector 是一个专门用于测试和分析RPC性能…

C语言 动态内存管理 #动态内存函数的介绍 #常见的动态内存错误 #C\C++ 程序的内存开辟 #柔性数组

文章目录 前言 一、为什么存在动态内存分配 二、动态内存函数的介绍 1、malloc 2、free 3、calloc 4、realloc realloc 的工作原理: 三、常见的动态内存错误 1、对NULL指针的解引用操作 2、对动态开辟空间的越界访问 3、对非动态开辟的空间使用 free 来释…

数学建模强化宝典(8)粒子群算法

前言 粒子群算法(Particle Swarm Optimization, PSO)是一种基于群体智能的优化算法,它源于对鸟群捕食行为的研究。通过模拟鸟群中的个体相互协作和信息共享来寻找最优解,粒子群算法已被广泛应用于函数优化、神经网络训练、模糊系统…

跨地域工作利器:深度解析2024年远程控制软件的新特性

无论是跨地域的团队协作、技术支持,使用远程控制工具可以让距离不再是障碍。这次我介绍一些可以直接下载使用的远程工具,比如从向日葵远程控制官网,EV官网、TV官网等就能直接下载使用的工具。 1.向日葵远程控制 链接直通车:http…

微服务--Nacos

一、Nacos简介 Nacos(Naming and Configuration Service)是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。它致力于帮助开发者快速实现动态服务发现、服务配置、服务元数据及流量管理。Nacos支持几乎所有主流类型的服…

惠中科技智能高效综合光伏清洗技术

惠中科技综合光伏清洗技术:,引领绿色清洁新时代 随着全球对可再生能源需求的不断增长,光伏产业作为绿色能源的重要组成部分,正迎来前所未有的发展机遇。然而,光伏电站的广泛应用也带来了光伏板清洁维护的挑战。灰尘、…

SprinBoot+Vue问卷调查微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平…

AI耳机是不是好赛道

AI耳机是不是好赛道? 数科星球原创 作者丨苑晶 编辑丨大兔 AI硬件方兴未艾,行业里出现了新变化。 最近,AI耳机开始受到关注。有人将其看作可堪比无线蓝牙耳机革命的大时代,也有人认为其鸡肋无比、并不看好。询问了多家投资机…

Pr:项目设置 - 颜色

Pr菜单:文件/项目设置 File/Project Settings “项目设置”对话框中的颜色 Color选项卡主要用于管理项目的色彩空间和显示设置,确保在不同设备和环境下色彩显示的一致性和准确性,特别是处理 HDR 或对数格式的视频素材时。 颜色设置 Color Set…

SprinBoot+Vue在线商城微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平…

网络攻击的类型

网络攻击的数量正在增长,迫切需要更强大的网络安全措施来应对这些攻击。作为程序员和 IT 专业人员,我们必须了解顶级组织中发生的最常见的网络攻击类型。 以下各节详细介绍了可能损害任何系统的不同类型的网络攻击。了解这些攻击对于检测和防止进一步攻…

esp32 中断最简验证程序

13脚接3.3v脚,显示OK ,不能直接接5v电压脚 中断程序最好是为各种执行设置标志位。不能处理占用长时间的指令 准备利用中断对超声波模块编程 #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/…

3.4 数据传送指令

🎓 微机原理考点专栏(通篇免费) 欢迎来到我的微机原理专栏!我将帮助你在最短时间内掌握微机原理的核心内容,为你的考研或期末考试保驾护航。 为什么选择我的视频? 全程考点讲解:每一节视频都…

MQ专题:顺序消息落地方案

一、什么是顺序消息 投递消息的顺序和消费消息的顺序一致。 比如生产者按顺序投递了1/2/3/4/5 这 5 条消息,那么消费的时候也必须按照1到5的顺序消费这些消息。 二、顺序消息如何实现?(2种方案) 方案1:生产者串行发…

OpenCV颜色空间转换(1)颜色空间转换函数cvtColor()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 将图像从一个颜色空间转换到另一个颜色空间。 此函数将输入图像从一个颜色空间转换到另一个颜色空间。在进行 RGB 颜色空间之间的转换时&#x…