目录
1.函数的创建与使用
"""
* _oo0oo_
* o8888888o
* 88" . "88
* (| -_- |)
* 0\ = /0
* ___/`---'\___
* .' \\| |// '.
* / \\||| : |||// \
* / _||||| -:- |||||- \
* | | \\\ - /// | |
* | \_| ''\---/'' |_/ |
* \ .-\__ '-' ___/-. /
* ___'. .' /--.--\ `. .'___
* ."" '< `.___\_<|>_/___.' >' "".
* | | : `- \`.;`\ _ /`;.`/ - ` : | |
* \ \ `_. \_ __\ /__ _/ .-` / /
* =====`-.____`.___ \_____/___.-`___.-'=====
* `=---='
*
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* 佛祖保佑 永不宕机 永无BUG
*
* @Author : gyp
* @Date : 2024-10-2 14.48.52
* @LastEditTime : 2023-10-2 15:12:41
* @LastEditors : gyp
* @Description :
* @FilePath : \C\SString.c
* 自学之用,欢迎讨论.13438784965
*/
"""
我们举个例子,我们拿一家公司的工资结算问题来探讨一下函数的概念。
这家公司的正常工资为每天200元,如果当月工作的天数大于等于20天,多出的天数每天按300元来结算,并且加1000全勤奖金,如果工作天数少于10天,那么所有工资按每天150元来结算,并扣除200缺勤工资。
假设该公司有4个员工,ABCD 4个员工的工作天数分别为30、25、15、5,我们来看一下它的代码。
1 2 3 4 5 6 7 8 9 10 11 12 |
|
这种方式不仅需要我们手动去判断,代码方式也是单一使用代码,当我们再次使用的时候还需要再次计算,当员工数量为1000的时候,我们肯定不能使用这种方式,因此我们来借助函数来解决这个问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
输出结果为:
1 2 3 4 |
|
通过上面这个例子,在解决相同问题不同变量的时候,我们只需要定义好一个函数,然后将这些变量反复使用这些函数即可解决问题,不需要我们去手动计算,计算机会帮助我们更准确迅速的解决问题。
函数可以帮助我们完成更简洁的代码、减少代码的重复、易于测试、快速开发、便于团队合作,因此在后面的学习过程中,函数是必不可少的一环。
1. 函数的创建
从上面的例子中我们可以看到函数的定义使用的关键字是def,定义函数的一般形式为:
1 2 |
|
在定义函数名字的时候我们需要注意几点:
1) 关键字不能作为函数名字。
2) 函数名中不能存在空格。
3) 函数名的首字母必须是大小写字母或者下划线。
4) 函数名的其余字母可以使用字母、数字以及下划线。
5) 不同函数名大小写不同的时候为不同函数。
我们来定义创建几个函数:
1 2 3 4 5 6 |
|
采用字母+下划线+字母的形式为常用的命名方式。
2. 调用函数
当我们创建好函数之后,如果不调用的话,不管函数中有多少print都不会执行的,因为函数就像我们买了一些工具放在仓库里,只有当我们拿出来的时候才能去使用,因此我们需要调用函数。
调用函数的时候,解释器会跳到函数体内,执行函数内的语句,当执行完毕之后回到调用的位置继续执行后续语句。
我们来看一下函数的调用过程。
1 2 3 4 5 6 |
|
输出结果为:
1 2 3 4 |
|
2.函数的参数传递
我们在调用函数的时候,主函数和调用函数之间总是离不开数据的传递,有了数据的传递,也就是参数的传递。参数的作用是用来传递数据给函数使用。
打个比方来说,我们买来了一个榨汁机,当我们加入苹果的时候会出来苹果汁,加入西瓜的时候会出来西瓜汁,参数就起到这样一个作用,参数通过主函数传递到被调用函数,然后被调用函数会返回给我们一个结果。
下面我们来学习参数的传递。
2.1. 形式参数和实际参数
要学习函数的参数传递,我们首先要了解什么是形式参数和实际参数。我们继续拿上面的例子来说,我们在榨汁机中有一个容器来装水果,我们将水果放在这个容器里,然后榨汁器开始运转,形式参数和实际参数也类似这样的关系。
形式参数为我们定义函数的时候再括号中定义的参数,我们在函数的内部会使用这个参数进行代码的编写,而实际参数为函数调用的时候传进来的参数,函数返回的结果是根据这个实际参数来代替形式参数。
看下面的例子:
1 2 3 4 5 6 7 |
|
在这上面这个例子中,函数在创建的时候使用的参数days为形式参数,在我们调用函数的时候,A即为实际参数,实际要带入到函数中使用的参数。
2.2. 位置参数
我们在创建函数的时候可以在括号中定义多个形式参数,我们在调用的时候,参数的数量和位置需要和创建的保持一致。
1) 参数的数量不一致
如果我们创建的函数中有2个形式参数,而我们调用的时候只使用了1个实际参数,会是什么样的结果呢,看下面的例子。
1 2 3 4 5 6 7 |
|
我们可以发现当实际参数的数量不等于形式参数的数量时候,会抛出异常,具体的意思为缺少一个必要位置的参数number。
2) 参数的位置不一致
当参数的位置不一致的时候会导致出现两种错误,一种是直接报错,因为我们在传参的时候会根据参数的性质而定义不同的类型,因此数据类型的错误会抛出异常。
另外一种错误是传入的参数的数据类型是对的,但是位置是错的,这样会出现错误的输出结果。
2.3. 关键字参数
为了提高程序的可读性,在函数调用的时候还可以使用关键字参数调用。
我们通过计算容器的体积来了解关键字参数。
1 2 3 4 5 6 |
|
使用关键字参数可以省去定义变量的过程,直接在函数调用的时候给参数进行赋值,然后传递到函数当中,最后返回结果。在这种传递方式中,参数位置的不同是不影响输出结果的。
2.4. 参数默认值
当我们定义一个函数的时候,可以给函数的参数定义一个初始值,这样在我们调用函数的时候如果没有给出实际参数,那么函数会使用默认参数。
看下面的例子:
1 2 3 4 5 6 7 |
|
通过上面的例子,如果我们在创建函数的时候已经给出了默认值,那么我们在使用函数的时候如果不给出实际参数则会自动使用默认参数。
2.5. 可变参数
在Python中函数的参数个数是可以变化的,也就是说参数的数量可以是不确定的,这种参数被称为可变参数。可变参数分为两种,一种是参数前加*,这种方式的可变参数在传递的时候是以元组的形式传递,一种是参数前加**,这种方式的可变参数在传递的时候以字典的形式传递,我们主要介绍一下第一种方式。
看下面的例子:
1 2 3 4 5 6 7 8 |
|
使用可变参数的时候,这些参数会被存放在一个元组中传递到函数里,因此我们要使用这些参数的时候可以使用遍历或者索引值进行使用。
3.函数的返回值
我们在使用函数的过程中通常是调用函数,然后被调用的函数中的内容会依次被执行,但是我们有的时候需要的不只是执行的步骤,我们还需要获取到函数中的一些变量,因此我们在使用函数的时候还可以增添一个返回值来获取函数中的一些数据。
3.1. 语法结构
Python中关于返回值需要使用return语句,它的语法结构为:
1 |
|
我们来举个例子来了解一下返回值,假如我们要使用函数来求解变量a和变量b的值,然后我们要在主函数中来输出他们的和,我们看一下代码:
1 2 3 4 |
|
如果我们把函数写成上面的模式然后输出是不会有输出结果的,因为我们返回了sum,等同于get_sum(1,2)这一部分的值是sum,但是并没有对它进行操作,如果我们修改一下代码:
1 2 3 4 5 6 7 |
|
输出结果为:
1 2 |
|
使用这种方式理解一下,在语句s = get_sum(1,2)中,先是调用了这个函数,然后函数顺序往下执行,到了return语句之后,把函数的值等同于sum,然后返回之后后面的语句就不再执行。返回值之后s就可以进行赋值操作,把函数的返回值赋给s,然后输出就可以看到我们的输出结果。
我们来看一下示意图:
3.2. 多值返回
我们在使用函数返回值的时候,有的时候不仅会只返回一个值,也可能要返回多个值,我们来看一下多个值的时候该怎么返回。
其实我们在返回多个值的时候原理和一个值的时候类似,我们需要注意的一点是当我们返回的是多个值的时候,多个值是被存储在元组当中的。
我们来看下面的例子:
1 2 3 4 5 6 7 8 |
|
输出结果:
1 2 |
|
我们可以看到返回多个值的时候是被存放在了一个元组之中,存放在了元组之中,我们想要使用这些数据的方式就有很多了。
我们接着上面返回的数据直接进行使用,我们可以使用4个变量直接进行定义,
1 2 |
|
输出结果为:
1 |
|
我们还可以通过循环的方式来打印出返回值:
1 2 |
|
输出结果为:
1 2 3 4 |
|
关于返回值就讲到这里,返回值是函数结构中十分重要,本节中以简单的例子来介绍了函数的返回值,大家在后续的学习中要加强对返回值的使用。
4.变量的作用域
变量的作用域指的是一个变量能够有效的区域,因为我们在使用函数的时候,有的变量是在主程序中定义的,有的是在调用的函数中定义的,当我们的主程序使用函数中定义的变量时,就会出现异常。下面来介绍一下局部变量和全局变量。
4.1. 局部变量
局部变量,顾名思义,就是作用在局部区域的变量,如果是在函数中定义的变量,那么就只在函数中起作用,如果在函数外部使用函数内部的变量,就会出现异常。
看下面的例子:
1 2 3 4 5 |
|
输出结果为:
1 2 3 4 5 |
|
由于变量data是在函数内部定义的,我们在主程序中使用变量data则会出现访问的变量不存在的问题,所以我们要注意在函数内部定义的变量为局部变量,未作特别声明的话是不可以在函数外使用的。
4.2. 全局变量
全局变量我们也可以从字面意思中理解到它就是作用在全局的变量,有的同学可能自然而然的认为那么全局变量一定是定义在主程序中的变量了,其实全局变量也是可以作用在函数中的,在这里我们来介绍两种全局变量的使用方式:
1) 在主程序中定义全局变量
我们在主程序中定义的变量的作用域是全局的,我们在定义的函数中也是可以直接使用这些变量,看下面的例子:
1 2 3 4 5 |
|
输出结果:
1 2 |
|
这种方式就是我们通常情况下使用的全局变量,我们在主程序中定义的变量可以在函数内部直接的进行使用。
2) 使用global关键字
我们在函数内定义的变量也可以编程全局变量,这时候我们就要使用到global关键字。
首先我们先看一下当全局变量和局部变量的名字相同的时候会是一个怎么样的情况,看下面的例子:
1 2 3 4 5 6 7 |
|
输出结果为:
1 2 3 |
|
通过这里例子我们可以看出全局变量和局部变量的命名相同的时候是不影响全局变量的内容的,但是如果我们想要在函数中修改全局变量的值,那么我们就要使用global关键字。
再看下面的例子:
1 2 3 4 5 6 7 8 |
|
输出结果为:
1 2 3 |
|
通过global关键字,在局部中声明告诉这个函数global是一个全局变量,那么修改了之后,全局中的变量都做了修改,global关键字就是可以使一个变量变成全局变量。
当全局中没有声明变量的时候,我们在局部中也可以使用global关键字直接来声明一个变量是全局变量,那么我们在函数中定义的变量在主程序中也是可以使用的,看下面的例子:
1 2 3 4 5 6 |
|
输出为:
1 2 |
|
4.3. 总结
通过上面的例子我们可以了解到global关键字在控制全局变量时候的作用,另外要注意在写程序的时候尽量避免全局变量和局部变量的名字一致,尽管他们作用于不同的区域,但是会影响对代码的理解。本节就讲到这里,下一节我们来学习匿名函数。
5.匿名函数
想必大家都知道匿名是什么含义,匿名就是指没有名字,我们在写程序的过程中有时不需要给函数命名,这时候就可以使用匿名函数,我们在Python中使用lambda表达式来使用匿名函数。
5.1. 匿名函数的定义
我们通过一个例子来介绍一下lambda函数的简单使用,变量m为我们输入的值,我们需要采用匿名函数来返回m的平方和,也就是输入2要返回值为4。
代码如下:
1 2 3 |
|
输出结果为:
1 2 |
|
我们通过下图再来看一下它的结构:
下面再通过一个例子来使用一下匿名函数:
1 2 3 |
|
输出结果为:
1 2 |
|
通过上面两个例子我们可以了解到lambda表达式等同于把函数压缩为一行代码,然后通过变量的定义直接来调用这个函数,这种方式可以简化我们的代码。
5.2. 序列调用匿名方法
我们在序列中同样可以使用匿名函数,使用匿名函数可以帮助我们进行很快的数据筛选,看下面的例子:
已知一个列表为[1,4,6,9,12,23,25,28,36,38,41,56,63,77,88,99],我们需要返回它里面的偶数并存放在列表当中。
我们可以使用filter函数来进行过滤。
代码如下:
1 2 |
|
输出结果为:
1 |
|
我们从里到外依次来分析这个表达式,filter()函数中的对象前者为我们的筛选方式,后者为我们要筛选的对象,然后我们把这些数据使用list()函数存放在了列表当中,最后打印出来,这种方式可以帮助我们很快的进行数据的整合。
我们在进行排序的时候也可以通过匿名函数来制定规则。
首先我们已知一组列表为[('元组甲',15,33),('元组乙',25,26),('元组丙',7,7)],列表中每个元素中的元组中包含每个元组的名字和最小值以及最大值,我们要根据每个人的元组最大值和最小值的差值来将列表进行排序,看下面代码:
1 2 3 |
|
输出结构为:
1 |
|
我们可以先简单的计算一下,他们的差值分别为18、1、0,所以他们的排列顺序应该为丙、乙、甲,通过lambda表达式中的返回结果x[2]-x[1],我们获得了他们的差值,然后根据差值进行排序。
5.3. 总结
匿名函数在数据筛选的时候显得尤为重要,它能够很快的帮助我们来解决数据复杂繁琐的问题,同时它可以优化我们的代码,使得代码的整体更为简洁,本章节我们就讲到这里,下一节我们来学习函数中的三大基础函数。
6.三大基本函数
在Python中有三个基础函数,分别是filter()、map()和reduce(),他们分别为我们提供过滤、映射和聚合的功能。上一节我们简单的使用了filter()函数结合匿名函数,下面我们会详细介绍它的用法。
6.1. filter()函数
在数据筛选和过滤的时候我们通常会采用filter()函数帮助我们快速的解决问题,它的语法格式为:
1 |
|
在filter函数中,前面放我们的过滤或筛选方式,即函数名,后面存放可迭代的对象,我们看下面的例子:
1 2 3 4 5 |
|
输出结果:
1 |
|
关于这个例子,我们首先定义了一个test()函数,如果x是偶数则返回其值,然后通过filter()函数使用test()函数来过滤my_list列表,但是输出结果却是<filter object at 0x034C2DD8>,在这里我们需要注意filter()函数的返回值为一个可迭代的对象,我们需要通过迭代的方式访问其中的值,或者使用列表list()函数强制类型转换。
1 2 3 4 5 6 7 8 |
|
输出结果为:
1 2 3 4 |
|
6.2. map()函数
在前面我们曾多次使用到过map()函数,例如我们在输入多个值的时候,我们会采用map()函数,我们需要输入四个值的时候:
1 2 |
|
map()函数的语法格式为:
1 |
|
在使用map()函数的时候,我们大多用于对数据的处理,把可迭代对象中的数据经过函数处理之后存储,我们在存储的时候继续采用list()函数进行存储。
我们先看上面输入四个值的例子,int为函数,input().splite输入的值为可迭代的对象,经过int函数的处理后存放在map对象当中。
我们可以通过map()函数将一个序列中的所有数据通过一个函数进行处理,看下面的例子:
我们在一个列表中存放了一下字母,如果存在小写字母,那么将它变成大写字母。
代码如下:
1 2 3 4 5 6 7 |
|
输出结果为:
1 |
|
test()函数中会先对x进行判断,如果是小写字母就返回它的大写字母,如果不是小写字母就返回它的值。
6.3. reduce()函数
reduce()函数用于把可迭代的对象通过函数方法进行聚合。
语法格式为:
1 |
|
举个例子,我们已知一个列表为[1,2,3,4],我们需要求列表里所有项依次相乘的和,我们可以使用reduce()函数。
1 2 3 4 5 |
|
输出结果为:
第一行代码为引入这种方法,后面会对模块进行讲解,test()函数返回了两个数据相乘,然后通过reduce()函数将my_list列表处理。
处理过程如下图:
先执行第一步,然后得到一个结果再和后一项相乘,依次到最后一位。
7.递归函数
有过编程学习经验的人对于递归函数一定不陌生,我们经常使用递归的方式来解决一系列复杂的问题,递归算法对于大多数问题都是很有效的,而且它也可以优化我们的代码,我们在使用递归的时候有几点需要注意:
1) 递归是在函数本身调用函数本身。
2) 递归的效率比较低,如果有时间限制不建议使用。
3) 递归过程中需要有一个明确的结束条件,即递归出口。
下面我们就来详细的讲解一下递归函数。
7.1. 递归函数
我们先通过例子来看一下递归的简单使用:
1 2 3 4 5 6 7 8 |
|
输出结果为:
1 2 |
|
我们来分析一下这个例子,首先第一行代码我们输入了一个整数,最后一行把m作为实际参数传递到test()方法,在test()方法中,会先把x进行加2处理,然后进行一个判断,如果x的值小于100,那么就再次调用这个函数,调用的时候当前x的值作为实际参数参加调用,直到满足x>=100的时候结束递归。
看下面示意图:
即如果不满足条件就回到了最外层来调用了这个函数。
7.2. 斐波那契数列
谈起递归算法中经典的问题,总是离不开斐波那契数列和汉诺塔,我们在这里来讲解一下如果使用递归去求解斐波那契数列。
首先我们要知道斐波那契数列的递推公式为F(n)=F(n-1)+F(n-2),F(1)、和F(2)为1,我们可以通过递归来求解斐波那契数列中的某一项的值为多少。
求解斐波那契数列问题的时候我们可以采用多种方式。
首先我们使用常用的递归方式来解决这个问题:
1 2 3 4 5 6 7 |
|
输出结果为:
1 2 |
|
对于这种递归的调用方式,当我们输入的值4的时候,会在递归中执行下面的操作:
1 |
|
然后我们可以看出第四项的值为1+1+1=3。
其实这种方式的求解是比较浪费时间的,因为需要进行迭代的次数太多,我们还可以采用空间替代时间的方式来求解这个问题。
代码如下:
1 2 3 4 5 |
|
输出结果为:
1 2 |
|
这种方式我们首先给列表规定了前2项的值,然后对于我们要求解的项数n,我们直接通过公式把这个斐波那契数列的列表填充到我们需要的那一项,最后根据索引值直接找到对应项输出结果。
7.3. 总结
关于递归函数就讲到这里,上面所讲到需要注意的几点大家要尤为注意递归出口和时间限制,出口是递归结束的关键,在很多时候,我们使用递归的方法会导致程序超出规定的时间,这时候我们就需要更换思路来求解问题,上面讲的第二种方式可以帮助大家解决问题。
8.内置函数
这一节我们来总结并简述一下Python中常用的内置函数。
函数名 | 方法简介 |
abs() |
返回绝对值 |
bin() |
返回二进制 |
bool() |
返回布尔值 |
chr() |
用一个范围在256内的整数作参数,返回一个对应的字符 |
cmp(x,y) |
用于比较,前者大于后者返回1,相等返回0,小于后者返回-1 |
compile() |
将字符串便以为字节代码 |
complex() |
创建一个复数 |
dict() |
创建字典 |
divmod(x,y) |
返回一组值,前者为x和y的商,后者为余数 |
enumerate() |
返回序列中元素及其索引值,使用for循环可依次输出。 |
eval() |
返回字符串表达式的值 |
file() |
创建一个 file 对象 |
filter() |
过滤函数 |
float() |
把整数和字符串转换成浮点数 |
format() |
格式化函数 |
getattr() |
返回一个对象属性值 |
globals() |
全局变量 |
hash() |
返回一个对象的哈希值 |
help() |
查看函数或者模块的功能 |
hex() |
将10进制整数转换成16进制 |
id() |
返回一个对象在内存中的地址 |
input() |
标准输入 |
isinstance() |
判断一个对象是否为已知的类型 |
int() |
把字符串或数字转换为整型 |
len() |
返回序列的长度 |
list() |
把其他数据类型转换为列表 |
locals() |
返回当前位置的所有局部变量 |
long() |
把一个数字或字符串转换为长整型 |
map() |
映射函数 |
max() |
返回最大值 |
min() |
返回最小值 |
next() |
返回迭代对象的下一项 |
oct() |
整数转换八进制数 |
pow(x,y) |
返回x的y次方 |
print() |
输出 |
range() |
创建整数序列 |
reduce() |
聚合函数 |
reload() |
重载模块 |
reverse() |
逆序 |
round() |
对浮点数四舍五入 |
set() |
创建集合 |
sorted() |
排序 |
sum() |
求和 |
zip() |
将可迭代的多个对象中根据对应关系组合在一个元组中 |
上面都是这些函数的简单说明,如果需要详细的了解可以在自己的IDLE中去查询它的用法,查询方式,进入IDLE,中文输入法输入help并回车进入下页面。
然后在指示框中输入内容即可进行详细的了解。
9.习题
9.1[编程入门]自定义函数处理素数
def is_prime(n):
if n==1 or n<=0:
print("not prime")
elif n==2:
print("prime")
else:
for i in range(2,n):
if n%i==0:
print("not prime")
break
n=int(input())
is_prime(n)
9.2[编程入门]自定义函数之字符串反转
def reverse_string(s):
return s[::-1]
print(reverse_string(input("Enter a string: ")) )# Output: "olleh"
9.3[编程入门]自定义函数之数字后移
n=int(input())
lis=list(map(int,input().strip().split())) #输入数组
x=int(input()) #移动的位数
lis.extend(lis[:n-x])
for i in lis[n-x:]:
print(i,end=' ')
9.4[编程入门]结构体之成绩记录
def grade_in_pri(n):
num=[]
name=[]
gra1=[]
gra2=[]
gra3=[]
for i in range(n):
a,b,c,d,e=input().strip().split()
num.append(a)
name.append(b)
gra1.append(c)
gra2.append(d)
gra3.append(e)
for i in range(n):
print('%s,%s,%s,%s,%s'%(num[i],name[i],gra1[i],gra2[i],gra3[i]))
n=int(input())
grade_in_pri(n)