当前位置:   article > 正文

10.【Python编程】函数的定义、调用、参数传递及其应用_查找或者自编一个关于函数调用或者函数应用的python程序

查找或者自编一个关于函数调用或者函数应用的python程序

10.【Python编程】函数的定义、调用、参数传递及其应用

备注: 本教程主要使用Python3.6在jupyter notebook上编程实现。Python环境配置参考《【Python学习】Windows10开始你的Anaconda安装与Python环境管理》或者《【Python学习】纯终端命令开始你的Anaconda安装与Python环境管理》

10.1 函数的定义与调用

数学上的定义

在数学上,函数被定义为:给定一个数集A,假设其中的元素为x,对A中的元素x施加对应法则f,记作f(x),得到另一数集B,假设B中的元素为y,则yx之间的等量关系可以用y=f(x)表示。
函数概念含有三个要素:定义域A、值域B和对应法则f。其中核心是对应法则f,它是函数关系的本质特征。
在我们初中、高中当中,出现的一元一次函数、一元二次函数、三角函数、指数函数、对数函数,便是如此。

编程上的定义

而在计算机科学里面,函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。函数能提高应用的模块性,和代码的重复利用率。

无论是数学上还是计算机科学上,函数都包含了输入(自变量)、处理代码(处理法则)、输出(因变量)。

在python当中,你可以定义一个由自己想要功能的函数,以下是简单的规则:

  • 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
  • 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
  • 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
  • 函数内容以冒号 : 起始,并且缩进。
  • return [表达式] 结束函数,选择性地返回一个值给调用方,不带表达式的 return 相当于返回 None。
  • 默认情况下,参数值和参数名称是按函数声明中定义的顺序匹配起来的。

它的格式为:

def 函数名(参数列表):
    函数体
    return 返回结果
  • 1
  • 2
  • 3

例如:

  • 使用python实现数学上的一元函数
# y = 2x+1
def f1(x):
    y = 2*x + 1
    return y
# 尝试使用该函数计算当x=5时的y值:
print("f1(5)=", f1(5)) # 调用f1函数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
'
运行
f1(5)= 11
  • 1
  • 使用python实现数学上的一元二次函数
# y=2x^2+3x-9
def f2(x):
    y=2*x**2+3*x-9
    return y
# 尝试使用该函数计算当x=5时的y值:
print("f2(5)=", f2(5)) # 调用f2函数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
'
运行
f2(5)= 56
  • 1
  • 使用python实现输入半径计算圆的面积、圆的周长
import math
# 计算圆的面积
def cal_area_of_circle(r):
    s = math.pi*r*r
    return s
# 计算圆的周长
def cal_circumference_of_circle(r):
    c = 2*math.pi*r
    return c

# 测试函数
r = float(input("请输入圆的半径(cm):"))
print("圆的半径是:", r)
print("圆的面积是:", cal_area_of_circle(r))
print("圆的周长是:", cal_circumference_of_circle(r))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
'
运行
请输入圆的半径(cm):5
圆的半径是: 5.0
圆的面积是: 78.53981633974483
圆的周长是: 31.41592653589793
  • 1
  • 2
  • 3
  • 4

10.2 参数及参数传递

在python当中,函数的参数,严格来说,是没有类型的,也就是,可以传给函数的参数任意类型的对象。通常可以约束要求传入的对象的类型,或者在函数内部判断对象的类型。

在 python 中,类型属于对象,变量是没有类型的。Python3 的六个标准数据类型中:

  • 不可变类型(3 个):Number(数字)、String(字符串)、Tuple(元组)
  • 可变类型(3 个):List(列表)、Dictionary(字典)、Set(集合)

解释:python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

python 传不可变对象实例

  • 不可变类型:类似于 C++ 的值传递,变量赋值 x=5 后再赋值 x=10,这里实际是新生成一个 int 值对象 10,再让 x 指向它,而 5 被丢弃,不是改变 x 的值,相当于新生成了 x。
    在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。
# 验证不可变类型变量的赋值
x = 5
id1 = id(x)
print(id1)
x = 10
id2 = id(x)
print(id2)
print(id1 == id2)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
'
运行
94347800181568
94347800181728
False
  • 1
  • 2
  • 3
# python传不可变对象,在函数内修改,并不会影响函数外的对象值
def change(x):
    # 函数内部的符号x表示形参
    print("函数内部的形参x的id=", id(x))   # 形参和实参指向的是同一个对象
    x=2022
    print("函数内部重新赋值后的形参x的id=", id(x))  # 形参指向一个新的对象

print("-----------当x为数字类型时------------------")
x=2021
print("x的类型为:",type(x))
print("实参x的取值=", x)
print("传入函数的实参x的id=", id(x))
change(x)
print("实参x的取值=", x)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
'
运行
-----------当x为数字类型时------------------
x的类型为: <class 'int'>
实参x的取值= 2021
传入函数的实参x的id= 140642597090288
函数内部的形参x的id= 140642597090288
函数内部重新赋值后的形参x的id= 140642597089840
实参x的取值= 2021
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

python 传可变对象实例

  • 可变类型:类似于 C++ 的引用传递,变量赋值 list1=[1,2,3,4] 后再赋值 list1[2]=5 则是将 list1 的第三个元素值更改,本身list1没有动,只是其内部的一部分值被修改了。
# 验证可变类型变量的赋值
list1=[1,2,3,4]
id3 = id(list1)
print(id3)
list1[2] = 5
id4 = id(list1)
print(id4)
print(id3 == id4)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
'
运行
140642597025800
140642597025800
True
  • 1
  • 2
  • 3
# python传可变对象,在函数内修改,会影响函数外的对象值
def change(x):
    # 函数内部的符号x表示形参
    print("函数内部的形参x的id=", id(x))   # 形参和实参指向的是同一个对象
    x.append(2022) # 传入函数的和在列表末尾添加新内容的对象用的是同一个引用。
    print("函数内部修改列表后的形参x的id=", id(x))  # 形参指向一个新的对象

print("-----------当x为列表类型时------------------")
x=[2019,2020,2021]
print("x的类型为:",type(x))
print("实参x的取值=", x)
print("传入函数的实参x的id=", id(x))
change(x)
print("实参x的取值=", x)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
'
运行
-----------当x为列表类型时------------------
x的类型为: <class 'list'>
实参x的取值= [2019, 2020, 2021]
传入函数的实参x的id= 140642614321416
函数内部的形参x的id= 140642614321416
函数内部修改列表后的形参x的id= 140642614321416
实参x的取值= [2019, 2020, 2021, 2022]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

参数类型

以下是调用函数时可使用的正式参数类型:

  • 必需参数:必需参数须以正确的顺序传入函数。调用时的数量必须和声明时的一样。
  • 关键字参数:函数调用使用关键字参数来确定传入的参数值。使用关键字参数允许函数调用时参数的顺序与声明时不一致,因为 Python 解释器能够用参数名匹配参数值。
  • 默认参数:调用函数时,如果没有传递参数,则会使用默认参数。
  • 不定长参数:你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,声明时不会命名。
  • 加了星号 *的参数会以元组(tuple)的形式导入,存放所有未命名的变量参数。
def functionname([formal_args,] *var_args_tuple ):
    "函数_文档字符串"
    function_suite
    return [expression]
  • 1
  • 2
  • 3
  • 4
  • 加了两个星号 ** 的参数会以字典的形式导入。
def functionname([formal_args,] **var_args_dict ):
    "函数_文档字符串"
    function_suite
    return [expression]
  • 1
  • 2
  • 3
  • 4
  • 声明函数时,参数中星号 *可以单独出现,如果单独出现星号 * 后的参数必须用关键字传入。
# 下面的例子的r就是必需参数
def cal_area_of_circle(r):
    s = math.pi*r*r
    return s
# 下面的例子的a,b就是必需参数
def cal_area(a,b):
    '''计算矩阵的面积
    '''
    s = a*b
    return s
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
'
运行
print(cal_area(1,3))
#print(cal_area(1))
'''
执行cal_area(1)
报错:TypeError: cal_area() missing 1 required positional argument: 'b'
'''
# 下面的形式为关键字参数,函数调用使用关键字参数来确定传入的参数值。
print(cal_area(a=1,b=3))
print(cal_area(b=3,a=3))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
3
3
9
  • 1
  • 2
  • 3
# 下面的例子的a,b指定了默认参数
def cal_area_v2(a=7,b=8):
    '''计算矩阵的面积
    '''
    s = a*b
    return s
# 实例中如果没有传入a、b参数,就使用默认参数
print(cal_area_v2())
print(cal_area_v2(3))
print(cal_area_v2(5))
print(cal_area_v2(b=3))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
'
运行
56
24
40
21
  • 1
  • 2
  • 3
  • 4
# 下面的例子为不定长参数
def printinfo(exp_name, *vartuple):
    "打印任何传入的参数"
    print("输出: ")
    print(exp_name)
    print(vartuple)
    
printinfo('exp1', [1,2,3,4], 50,"Hello world!")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
'
运行
输出: 
exp1
([1, 2, 3, 4], 50, 'Hello world!')
  • 1
  • 2
  • 3
# 下面的例子为不定长参数
def printinfo( arg1, **vardict ):
    "打印任何传入的参数"
    print("输出: ")
    print(arg1)
    print(vardict)

# 调用printinfo 函数
printinfo(1,a=2,b=3)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
'
运行
输出: 
1
{'a': 2, 'b': 3}
  • 1
  • 2
  • 3
def f(a,b,*,c):
    return a*b*c

print(f(1,2,c=3)) # 正确调用方式

#print(f(1,2,3))
'''
print(f(1,2,3))
报错:TypeError: f() takes 2 positional arguments but 3 were given
'''
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
'
运行
6





'\nprint(f(1,2,3))\n报错:TypeError: f() takes 2 positional arguments but 3 were given\n'
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

10.3 lambda表达式创建匿名函数

所谓匿名,也就是不再使用def语句这样标准的形式定义一个函数。它的格式为:

lambda [arg1 [,arg2,.....argn]]:expression
  • 1

说明

  • lambda只是一个表达式,函数体比 def 简单很多。
  • lambda的主体是一个表达式,而不是一个代码块。仅仅能在lambda表达式中封装有限的逻辑进去。
  • lambda函数拥有自己的命名空间,且不能访问自己参数列表之外或全局命名空间里的参数。
  • 虽然lambda函数看起来只能写一行,却不等同于C或C++的内联函数,后者的目的是调用小函数时不占用栈内存从而增加运行效率。

lambda函数的应用场景:

  • lambda函数赋值给一个变量,通过这个变量间接调用该lambda函数。
  • lambda函数赋值给其他函数,从而将其他函数用该lambda函数替换。
  • lambda函数作为参数传递给其他函数。部分Python内置函数接受函数作为参数,典型的此类内置函数有这些:filter函数、sorted函数、map函数、reduce函数。
# lambda能将函数描述简化为一行代码
def f(x):
    return x**2
print(f(4))

g = lambda x:x**2
print(g(4))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
'
运行
16
16
  • 1
  • 2
# 将列表按照其绝对值大小升序排序
list1 = [9,-2,6,-5]
list2 = sorted(list1,key=lambda x:abs(x))
print(list2)
  • 1
  • 2
  • 3
  • 4
'
运行
[-2, -5, 6, 9]
  • 1
# 过滤掉列表中的偶数值
list3 = [1,2,3,4,5,6,7,8,9]
list4 = [i for i in filter(lambda x: x % 2 == 0, list3)]
print(list4)
  • 1
  • 2
  • 3
  • 4
'
运行
[2, 4, 6, 8]
  • 1
# 将列表中的元素加1
list5 = [1,2,3,4,5]
list6 = [i for i in map(lambda x: x+1, list5)]
print(list6)
  • 1
  • 2
  • 3
  • 4
'
运行
[2, 3, 4, 5, 6]
  • 1
# 将匿名函数保存在字典的value位置上
func_dict={'2':(lambda x: x * 2),
           '3':(lambda x: x * 3),
           '4':(lambda x: x * 4)
          }
print(func_dict["2"](3)) # 计算3的2次方
print(func_dict["3"](3)) # 计算3的3次方
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
'
运行
6
9
  • 1
  • 2
声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号