函数声明、调用的过程

news2025/1/19 2:56:44

【 一 】函数声明、调用的过程详述

1. 函数必须先定义后调用,没有定义函数是一定不能够调用的
2. 函数在定义阶段,只检测语法是否错误,不检测逻辑是否有问题
3. 逻辑上的错误只会在调用阶段检测
4. 函数一定是被调用之后才会执行函数内部的代码块,不调用函数一定不会执行函数的
    # 如何调用函数
    函数名() # 只要函数名加括号一定会执行函数体代码
    函数如果在定义阶段有参数,那么,在调用的时候,连参数一块写上
    
**************************************************************************************

函数调用的内部原理:
1. 先在内存空间中申请一块空间地址来存储函数体代码
2. 把函数名和函数体所在的空间地址绑定在一起
3. 以后只需要通过函数名()来访问函数体代码即可

        def用来声明一个函数,python的函数包括函数名称、参数、函数体、函数体中涉及到的变量、返回值。

        实际上,函数名称其实是一个变量名,def表示将保存在某块内存区域中的函数代码体赋值给函数名变量。例如:

def myfunc(x,y,z):
    ...CODE...

上面表示将函数体赋值给变量名myfunc。如下图:

既然是变量,就可以进行输出:

def myfunc(x):
    return x+5

print(myfunc)

输出结果:

<function myfunc at 0x032EA6F0>

由于python是解释型语言,所以必须先定义函数,才能调用函数。

        如果导入一个模块文件,导入的时候会解释、执行文件中的代码,包括def语句,也就是说,导入文件时会先声明好函数。

【  二 】 函数变量的细节

        请一定理解本节内容,也许细节方面可能会有些不准确,但对于深入理解函数来说(不仅限于python语言),是非常有帮助的,特别是理解作用域规则的时候。

        python是解释性语言,读一行解释一行,解释一行忘记一行。而函数是一种代码块,代码块是一个解释单元,是一个整体。在代码块范围内不会忘记读取过的行,也不会读一行就立即解释一行,而是读取完所有代码块内的行,然后统筹安排地进行解释。关于这一点,在后面的文章代码块详述中有非常详细的解释,建议一读。

        当python读取到def所在行的时候,知道这是一个函数声明语句,它有一个属于自己的代码块范围,于是会读完整个代码块,然后解释这个代码块。在这个解释过程中,会记录好变量以及该变量的所属作用域(是全局范围内的变量还是函数的本地变量),但一定注意,def声明函数的过程中不会进行变量的赋值(参数默认值除外,见下文),只有在函数调用的时候才会进行变量赋值。换句话说,在def声明函数的过程中,在函数被调用之前,函数所记录的变量一直都是变量的地址,或者通俗一点理解为记录变量的名称,而不会进行变量的赋值替换

        实际上,变量的明确的值会当作常量被记录起来。如a=10的10被作为常量,而变量a赋值给变量b时b=a,a显然不会作为常量。

如下函数:

x=3
def myfunc(a,b):
    c=10
    print(x,a,b,c)

myfunc(5,6)

输出结果为:"3 5 6 10"。

上面的函数涉及到了4个变量:a、b、c、x。其中:

  • 全局变量x
  • 本地变量a、b、c,其中本地变量a和b是函数的参数

        在def的过程中,会完完整整地记录好这些变量以及所属作用域,但只会记录,不会进行变量的赋值。如下图:

        然后函数被调用,这时候才会开始根据记录的作用域搜索变量是否存在,是否已经赋值(非本地变量),并对需要赋值的变量赋值:

  • 查找全局变量变量x,它在全局作用域内已经赋值过了,所以只需找到这个全局变量即可
  • 查找本地变量a、b、c,它们是属于函数myfunc的本地变量,而a和b是参数变量,所以最先对它们进行赋值a=5,b=6,然后赋值普通的本地变量c=10

如图:

最后执行print(x,a,b,c)输出这些变量的值。

        还需注意,python是读一行解释一行的,在函数调用过程中,因为c=10print()的前面,所以是先赋值c=10,再执行print,如果print在c=10前面,则先执行print,再赋值,这显然是错误的,因为print()中使用了变量c,但目前还没有对其赋值。这和其它语言可能有些不同(特别是编译型语言),它们可能会无视变量赋值以及变量使用的位置前后关系。

如果上面的示例中,函数myfunc调用之前,将变量x赋值为另一个值:

x=3
def myfunc(a,b):
    c=10
    print(x,a,b,c)

x=33
myfunc(5,6)

        这时将输出:"33 5 6 10"。因为x是全局变量,只有在函数调用的时候才会去找到变量x对应的值,而这时全局变量的值已经是33。

【  三  】 定义函数

  1. 定义函数 -- 封装独立的功能
  2. 调用函数 -- 享受封装的结果

【1】打印九九乘法表

# 我们将以下代码复制到python文件中,保存为 九九乘法表.py
def multiple_table():
    for i in range(1,10):
        for j in range(1,10):
            if j<=i:
                print(f"{i} * {j} = {i*j}",end='\t')
        print("")
multiple_table()  # 调用该函数
  • 函数的文档注释
# 给函数添加注释,应该定义在函数下方,在连续的三对引号中编写对函数的说明文字
def multiple_table():
"""这是一个生成九九乘法表的函数"""
    for i in range(1,10):
        print('\n')
        for j in range(1,10):
            if j<=i:
                print("%d * %d = %d" % (i,j,i*j),end = '\t')

【 2 】函数的声明和调用: 

def 函数名(形参1,形参2,...,形参n):   #函数名的命名符合标识符的命名规则
   "函数_文档字符串"
    函数体
    return 语句    #不带表达式的 return 相当于返回 None,None的逻辑值恒为False

# 例1
def sumup(x,y):
	"两数之和"
	return x+y
sumup(3,4)

( 1 )函数中参数的传递:

函数参数的作用:增加函数的通用性

位置参数:所谓位置参数,指的是当调用一个函数时,实参按位置依次传递

def sumup(x,y)
	return x+y

关键字参数:所谓关键字参数,指的是当调用一个函数的时候,可以用key=value的方式指定给某个参数赋值,这样就不一定严格遵守函数声明里的参数顺序。

def myfunc(a,b,c):
    print(f"a:{a},b:{b},c:{c}")
myfunc(c=3,b=4,a=2)

# 同时使用位置参数和关键字参数时,位置参数必须在关键字参数前
def myfunc(a,b,c):
    print(f"a:{a},b:{b},c:{c}")
myfunc(3,c=4,b=2)

默认参数(缺省参数):默认参数就是在声明函数的时候使用一些包含默认值的参数,函数声明时,普通参数在前,默认参数在后

# 函数调用时,若没有给默认参数传递参数,则该形参直接取默认参数值,如果调用时给默认参数传递了参数,那么该形参的值应该等于外部传递的参数
def func(x,y,z=1,w=3):
    return x+y+z+w
test1 = func(1,2,3)
test2 = func(1,4,w=4)

# 例1:
def print_info(name,gender=True):
    gender_text = "男生"
    if not gender:
        gender_text = "女生"
    print("{}是{}".format(name,gender_text))
print_info("小明")
print_info("小美",False)

默认参数必须指向不变对象,可以参考这篇文章

# 使用help()函数查看函数文档的时候,经常会发现在函数的原型中,会看到一个斜杠,该斜杠表示,其左边的参数必须传递位置参数而不能是关键字参数
In [10]: help(abs)
Help on built-in function abs in module builtins:
abs(x, /)
    Return the absolute value of the argument.

In [11]: help(sum)
Help on built-in function sum in module builtins:
sum(iterable, /, start=0)
    Return the sum of a 'start' value (default: 0) plus an iterable of numbers
    When the iterable is empty, return the start value.
    This function is intended specifically for use with numeric values and may
    reject non-numeric types.

# 上面help(abs)之后,我们看到里面的形参为x,我们调用abs(x=-1.5),Python会报错
In [12]: abs(-1.5) #只能以位置参数传入
Out[12]: 1.5

# 上面help(sum)之后,我们看到里面斜杠右边有个start,从而start参数可以选择以位置参数或者关键字参数传入
In [14]: sum([1,2,4,5],start=2)
Out[14]: 14

In [15]: sum([1,2,4,5],2)
Out[15]: 14

# 同样我们自己创建函数时,也可以利用这个"/"号
def myfunc(a,b,/,c,d):
    print(f"a:{a},b:{b},c:{c},d:{d}")
myfunc(3,3,4,d=2)

# 上面我们知道使用"/"可以限制左边的参数只能以位置参数传入,当我们使用"*"时,就可以限制右边的参数只能以关键字参数传入
def myfunc(a,b,*,c,d):
    print(f"a:{a},b:{b},c:{c},d:{d}")
myfunc(3,c=4,b=3,d=2)

( 2 )收集参数

       收集参数就是说只指定一个参数,然后允许调用函数时传入任意数量的参数。

       元组参数:在某个参数前加一个 * 号,将前面必须赋值的参数赋值完之后,剩下的打包成一个元组接收(可以接收空元组)。

# 函数定义时,*参数收集所有未匹配的位置参数组成一个tuple对象,局部变量tup指向此tuple对象,局部变量tup指向该tuple对象
def myfunc(d,*tup):
    print(f'必须参数:{d}')
    print(f'非必须参数:{tup}')
myfunc(10)
myfunc(10,20,30,'test')

必须参数:10
非必须参数:()
必须参数:10
非必须参数:(20, 30, 'test')

# 函数调用时,*参数用来解包tuple对象中的每个元素,作为一个个位置参数传入到函数中
def myfunc(name,age,*interest):
    print('name:{},age:{},interest:{}'.format(name,age,interest))
tuple1 = ('football','tourist','eating')
myfunc('xiyangyang','17',*tuple1)

tuple2 = ('meiyangyang','15','eating','swimming','sleeping')
myfunc(*tuple2)

# 如果在收集参数后面还需要指定其他参数,那么在调用函数的时候,就应该使用关键字参数来指定后面的参数,否则Python就会把实参纳入收集参数中
def myfunc(*arg,x,y):
    print(f"arg:{arg},x:{x},y:{y}")
myfunc(3,4,3,2)
TypeError: myfunc() missing 2 required keyword-only arguments: 'x' and 'y' #报错信息

def myfunc(*arg,x,y):
    print(f"arg:{arg},x:{x},y:{y}")
myfunc(3,4,y=3,x=2)
arg:(3, 4),x:2,y:3

字典参数:元组参数允许你传入0个或者任意个参数,这些可变参数在函数调用时会自动组装成为一个tuple,而关键字参数允许你传入0个或者任意个关键字参数,这些关键字参数会在函数内部自动组装成为一个dict

# 函数定义时,**参数收集所有未匹配的关键字参数组成一个dict对象,局部变量dict_interest指向此dict对象
def student(name,age,**dict_interest):
    print('name:{},age:{},interest:{}'.format(name,age,dict_interest))
student('luxiaofeng',18,sport = 'basketball',food = 'humberger')
name:luxiaofeng,age:18,interest:{'sport': 'basketball', 'food': 'humberger'}

# 函数调用时,**参数用于解包dict对象的每个元素,作为一个一个的关键字参数传入到函数中
def student(name,age,**dict_interest):
    print('name:{},age:{},interest:{}'.format(name,age,dict_interest))
dict1 = {'sports':'football','food':'humberger'}
student('zouhongwei',19,**dict1)

在来看一个例子:

def demo(*args,**kwargs):
    print(args)
    print(kwargs)
gl_nums = (1,2,3)
gl_dict = {"name":"小明","age":18}
demo(*gl_nums,**gl_dict)

(1, 2, 3)
{'name': '小明', 'age': 18}
  • 函数返回多个值

前面我们讲过元组的打包:

tuple = "a","b","c","d" # 这样创建元组的方式叫做元组打包

利用这个,我们可以在函数中同时返回多个值:

def measure():
    temperature = 23
    wetness = 20
    return temperature,wetness
a = measure()  # 这里的a就是一个元组

再利用元组解包,就能单独拿到每个值了:

def measure():
    temperature = 23
    wetness = 20
    return temperature,wetness
temperature,wetness = measure()

练习题1:定义一个函数 sum_numbers ,能够接收一个 num 的整数参数,计算 1~num的整数和

# 递归
def sum_numbers(num):
    if num == 1:
        return 1    # 设定一个出口
    temp = num + sum_numbers(num-1)
    return temp
print(sum_numbers(100))

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

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

相关文章

C#科学绘图库ScottPlot

文章目录 安装和准备初步使用简单的设置 安装和准备 ScottPlot是基于.Net的一款开源免费的交互式可视化库&#xff0c;支持Winform和WPF等UI框架&#xff0c;本文示例在WPF环境中运行。在VS的菜单栏->工具->NuGet包管理器->管理解决方案的NuGet程序包->在浏览选项…

JS基础面试题之手写bind

JS基础面试题之手写bind 手写bind返回函数的模拟实现传参的模拟实现构造函数效果的模拟实现构造函数效果的优化实现最终版 手写bind bind()方法会创建一个新的函数。当这个函数被调用时&#xff0c;bind()的第一个参数将作为它的运行时的this&#xff0c;之后的一序列参数将会在…

在vue中深度选择器的使用

一、为什么要使用深度选择器 在vue中&#xff0c;当我们使用了第三方库中的组件时&#xff0c;想要更改一些样式&#xff0c;达到我们想要的效果&#xff0c;由于scoped的影响直接编写同名样式时&#xff0c;是覆盖不了组件内的样式的。 为了达到我们想要的效果&#xff0c;…

JavaSE基础50题:12. 编写代码模拟三次密码输入的场景。

概述 编写代码模拟三次输入的场景&#xff0c;最多能输入三次密码&#xff0c;密码正确&#xff0c;提示 “登录成功” &#xff0c;密码错误&#xff0c;可重新输入&#xff0c;最多输入三次&#xff0c;三次均错&#xff0c;则提示退出程序。 代码 import java.util.Scann…

读者和写者问题

它可以解决的问题&#xff1a; 可以支持多个读者访问&#xff0c;通过count计数 来实现多个读者访问的时候是互斥的&#xff0c;不会出现不符合进程同步的问题&#xff1a;设置mutex互斥锁&#xff0c;保证count或count--和if Pv(mutex)是一气呵成的 读写公平&#xff0c;通过…

“分割“安卓用户,对标iOS,鸿蒙崛起~

近期关于**“华为于明年推出不兼容安卓的鸿蒙版本”**的消息传出&#xff0c;引起了业界的热议关注。自从2019年8月&#xff0c;美国制裁下&#xff0c;华为不再能够获得谷歌安卓操作系统相关付费服务&#xff0c;如此情况下&#xff0c;华为“备胎”鸿蒙操作系统一夜转正。 华…

如何掌握构建 LMS 网站的艺术

目录 什么是学习管理系统 (LMS) 在线课程和 LMS 网站的好处 为什么 WordPress 对于 LMS 网站很重要 统一学习中心 多功能性和可扩展性 提高教育参与度 简化管理和监控 节省时间和费用 技能评估和绩效监督 持续学习和技能提升 使用 WordPress 插件构建成功的 LMS 课程 专注于您的…

PyQt6 QDateEdit日期控件

​锋哥原创的PyQt6视频教程&#xff1a; 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计39条视频&#xff0c;包括&#xff1a;2024版 PyQt6 Python桌面开发 视频教程(无废话…

拨号连接bat命令和拨号错误623,系统无法找到此连接的电话簿项的解决方法

一、拨号bat命令 1、首先创建一个拨号连接&#xff0c;注意连接名称要使用英文 2、创建一个bat文件&#xff0c;里面内容 echo off chcp 65001rem 定义连接参数&#xff0c;第一个是用户名&#xff0c;第二个是密码 set usernameS11111111111 set passwords11111111111 set…

ORA-600 kcbzib_kcrsds_1一键恢复

一个19c库由于某种原因redo损坏强制打开库报ORA-600 kcbzib_kcrsds_1错误 SQL> startup mount pfile?/database/pfile.txt; ORACLE instance started. Total System Global Area 859830696 bytes Fixed Size 9034152 bytes Variable Size 5…

QT----Visual Studio打开.ui文件报错无法打开

问题 在我安装完qt后将它嵌入vs&#xff0c;后新建的文件无法打开ui文件 解决方法 右击ui文件打开方式,添加,程序找到你qt的安装目录里的designer.exe。点击确定再次双击就能够打开。

ES6中的继承,String类型方法的拓展

ES6中的继承&#xff1a; 主要是依赖extends关键字来实现继承&#xff0c;使用了extends实现继承不一定要constructor和super&#xff0c;因为没有的话会默认产生并调用它们。 在实现继承时&#xff0c;如果子类中有constructor函数&#xff0c;必须得在constructor中调用一下s…

linux搭建nacos集群

准备 检查是否安装jdk [roothao /usr/local/software/elk/logstash]# java -version java version "1.8.0_341" Java(TM) SE Runtime Environment (build 1.8.0_341-b10) Java HotSpot(TM) 64-Bit Server VM (build 25.341-b10, mixed mode)配置nacos 去github下载…

单片机语言--C51语言数据类型与存储类型以及C51的基本运算

单片机语言——C51语言 文章目录 单片机语言——C51语言一、 C51与标准C的比较二、 C51语言中的数据类型与存储类型2.1、C51的扩展数据类型2.2、数据存储类型 三、 C51的基本运算3.1 算术运算符3.2 逻辑运算符3.3 关系运算符3.4 位运算3.5 指针和取地址运算符 一、 C51与标准C的…

freeRtos队列的使用

一.队列的特性 队列是一个环形缓冲区 很多生产者生产很多数据&#xff0c;很多消费者读数据&#xff0c;唤醒之后首先是执行高优先级的&#xff0c;同等优先级先执行等待时间长的。 无论是写数据还是读数据都会有一个超时时间&#xff0c;写数据当队列已经满了就等待一会&…

HMMER学习——(待完善)

HMMER profile HMM files A HMMER profile file looks like this, with …’s marking elisions made for clarity and space: 1.全基因组基因家族的分析系列之HMMER3.1使用 2. hmmalign - align sequences to an HMM profile

vue3日常知识点学习归纳

1&#xff0c;父子组件传递&#xff1a; 父组件传递参数 <template><div><!-- 子组件 参数&#xff1a;num 、nums --><child :num"nums.num" :doubleNum"nums.doubleNum" increase"handleIncrease"></child>&l…

螺旋集污排气阀 微米级微泡排气除污装置螺旋除污器工作原理选型

​ 1&#xff1a;螺旋集污排气阀设备介绍 螺旋除污器&#xff0c;也被称为微泡排气除污装置&#xff0c;是一种有效的水处理设备&#xff0c;其主要功能是净化工作系统中的水。它的主要部分是螺旋管&#xff0c;能够脱除系统中的游离气体和微气泡。 螺旋管是由铜丝焊接制成的…

人工智能企业引入S-SDLC,推动安全能力大跃升,保障AI技术体系深化落地

某人工智能公司是国际知名的上市企业&#xff0c;核心技术处于世界前沿水平。多年来&#xff0c;该企业在智慧教育、智慧医疗、智慧城市、智慧司法、金融科技、智能汽车、运营商、消费者等领域进行深度技术赋能&#xff0c;深入推进各个行业的智能化、数字化转型建设。 人工智能…

解决思维题的一些自我总结

目录 常见思维题类型 排序 区间问题 01串串 字符串串 位运算 gcd 与 lcm 质数相关 二元组 常见思维题类型 思维题很多都可以说是贪心、但贪心种类很多&#xff0c;具体怎么贪&#xff0c;重要的还是在于积累经验吧...有些东西也很难总结&#xff0c;以下算是我的碎碎念…