python语言基础-1语法基础-1.8 函数

声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。

1.8 函数

1.8.1 定义函数

定义一个函数的基本格式如下:

'''
def 函数名([参数,参数,...])
    函数体(复用的代码)

定义函数的注意事项:1.必须使用关键字def;2.函数体注意缩进;3.函数名与():必须有
'''
# 定义函数,产生随机数
import random


def generate_random():
    for i in range(10):
        ran = random.randint(1, 20)
        print(ran)

generate_random() # 调用函数

# 查看函数的内存地址
print(generate_random)  # 打印函数名。打印结果为:<function generate_random at 0x000001F032CCC3A0> 英文部分为函数名,后面的16进制数为内存地址

python函数返回值的类型由return后的表达式决定,如果没有返回则函数没有return。

def add(x, y):
    result = x + y
    print(result)  # 函数中用print可以让结果在控制台显示,但在函数体外部则不能打印结果,该结果没有从函数体中输出
    return result  # 返回值是可以将结果传递出去的,这个结果是可以被后续调用的


x = add(2, 3)  # 函数调用的返回结果赋给一个变量,然后打印可以看到结果

# return返回值可以是多个,并且多个返回值可以用一个变量去接收,将以元组的形式赋给变量
# return有多个返回结果,也可以用多个变量去接收

python是弱类型的,参数和返回值都没有直接的类型限制,这增加了灵活性,但也导致可读性不好,因此python中制定了专门的类型暗示(type hint)。如下:

def add(a:int, b:int) -> int:  # a:int,用于提示参数的类型; -> int,用于提示函数返回值的类型
    return a+b

# 这种语法只起提示作用,并没有强制限制类型

1.8.2 参数传递

C、java、python的函数(或方法)参数传递都满足基本数据类型是值传递,组合(或引用)数据类型是地址传递。

如以下示例中,实参如果是基本数据类型,则经过函数(或方法)处理后实参变量的值是不变的;实参如果是组合(或引用)数据类型,则经过函数(或方法)处理后实参变量的值会发生改变。

def sum1(num):
    num += 1
    return num

def sum2(nums):
    i = 0
    while(i<len(nums)):
        nums[i] += 1
        i += 1

a = 10
sum1(a)
print(a)

b = [1, 2, 3, 4, 5]
sum2(b)
print(b)

# python中的组合数据类型删除引用的方式是用del variablename;

调用函数时传递参数的方式有两种:位置传递和名称传递。如下:

def fact(n, m):
    s=1
    for i in range(1, n+1):
        s *= i
    return s//m

# 使用以下两种方式调用都是可以将n赋为10且将m赋为5的
fact(10, 5)
fact(m=5, n=10)

1.8.3 可选参数函数

python中定义函数时,可以设置一些非必填的参数,当不传递这些参数时,它们可以取默认值。如下:

'''
定义一个可选参数函数
'''
def fact(n, m=1):
    s=1
    for i in range(1, n+1):
        s *= i
    return s//m

# 调用时,以下两种形式都是可以的
fact(3,2)
fact(3)

注意,定义可选参数函数时,所可选的参数一定要定义在必选参数后面。

1.8.4 可变参数函数

java与C中的可变参数类似于语言中的数组类型。而python中没有数组这个类型,取而代之的是各种序列(列表、元组、字符串、字典、集合)。

'''
元组型可变参数:
'''
# 可变参数的类型(元组型参数)
def add(*x):
    s = 0
    for i in x:
        s+=i
    print(s)
    print(x)  # 打印结果为一个空元组
# 可变参数的赋值类似于 a,*b = 1,2,3,4 的过程。当定义可变参数时,系统会默认准备一个元组接受传参。
# 可变参数与不可变参数同时使用时,要放在后面。
# 要将一个元组整体传参给add的做法:
t1 = (1,1,2,3,4)
add(*t1)  # 采用此方式可以将元组传参给可变参数函数。*会执行一个拆包动作将实参元组中的元素释放,执行时重新装包到形参元组中
add(1, 2, 3, 4)


'''
字典型可变参数:
'''
# 关键字参数(字典型参数)
# 关键字参数:def add(a,b=10),其中b即为关键字参数
# 对关键字参数进行传值后会覆盖其默认值
# 赋值时可以直接指明形参,则实参就会赋给指定的形参。
# 当关键字参数的个数不确定时,函数可以作如下定义:
def func(**x):  # 形参**x的形式即为多个关键字参数
    print(a, b, c)

# **X的参数一量定义,则系统会默认准备一个字典,因此接受赋值时必须按key=value的形式进行。如下:
func(a=1, b=2, c=3)  # 多个关键字参数的调用须按关键字参数的形式调用

# 要将一个字典整体传参给func的做法:
dict1 = {'a': 1, 'b': 3, 'c': 5, 'd': 7}
func(**dict1)  # 采用此方式可以将字典传参给一个多关键字参数函数。**会执行一个拆包动作将实参字典中的元素释放,执行时重新装包到形参字典中

#关键字参数的预定义值即为关键字形式的默认值,重新赋值默认值将被覆盖


'''
列表类型可变参数:
'''
# 列表类参数
def func(a, *args):
    print(a, args)


func(2, [1, 2, 3, 4])  # 输出结果:2 ([1,2,3,4],),此时整个列表将被当成一个元组中的元素
# 列表型参数的拆包与元组型参数是相同的,即:
l = [1, 2, 3, 4]
func(2, *l)  # 输出结果:2 (1,2,3,4)


'''
各种类型参数混合使用的情况:
'''
# 混合参数使用示例:
def bb(a, *b, **c):
    print(a, b, c)


bb(1)  # 输出结果:1 () {}
bb(1, 2, 3)  # 输出结果:1 (2,3) {}
bb(1, x=100, y=2)  # 输出结果:1 () {'x':100,'y':2}
bb(1, 2, x=100)  # 输出结果:1 (2) {'x':100}
bb(1, x=100, 3, 4)  # 会报错,因为3,4的传递没有按定义的顺序

1.8.5 匿名函数(lambda函数)

python中可以使用lambda函数实现匿名函数。如下:

# 匿名函数:lambda函数
# 格式:lambda 参数1,参数2,... :表达式

s = lambda a, b: a + b
print(s)  #打印结果表明:lambda式赋予的变量即为函数名

#调用
result = s(1,2)  # 将1,2赋给a,b,将返回值赋给result
print(result)
print(s(1, 2))

匿名函数可以用于传参:

# 匿名函数作参数
def func(x,y,func):
    print(x,y)
    print(func)
    s = func(x,y)
    print(s)

# 调用
func(1, 2, lambda a,b: a + b)

使用匿名函数可以使代码更简洁。下面是使用匿名函数的例子:

'''
max()函数用于列表元素比较大小:
'''
list1 = [3,6,5,9,7,8]
m = max(list1)
print(m)
# 但当列表中元素为字典时,max应如下使用:
list2 = [{'a': 3, 'b': 6, 'c': 7}, {'a': 5, 'b': 9, 'c': 2}, {'a': 7, 'b': 4, 'c': 1}]
m = max(list2, key=lambda x: x['a'])
# key是内置函数max的参数之一,它可以指定比较大小所采用的方式,这里我们指定取出字典中键a的值比较大小


'''
lambda函数与内置函数map实现列表中元素增值:
'''
list3 = [2,5,4,3,6,9,7,1]
result = map(lambda x: x + 2, list3)
print(result)  # 直接输出返回一个map类型的对象
print(list(result))  # 可以通过list将map类型的对象转为list类型


'''
lambda函数与内置函数map实现奇数元素增值:
'''
result = map(lambda x: x if x % 2 == 0 else x + 1, list3)
print(list(result))


'''
lambda函数与reduce()结合对列表中元素进行加减乘除运算
'''
tuple1 = (3, 5, 7, 8, 9, 1)
result = reduce(lambda x, y: x + y, tuple1)  # 将元组中所有的元素相加
# reduce函数的执行逻辑是:将3,5分别赋给x,y,相加的和作为x,又将下一个元素7作为y,依次进行直到结束
print(result)
tuple2 = (1,)
result = reduce(lambda x, y: x + y, tuple2)  # 元组中只有一个元素也可以正常使用
# 以上将+号换成-*/也可以同样使用


'''
lambda函数与filter结合筛选数据
'''
list4 = [12, 6, 8, 98, 34, 36, 2, 0]
result = filter(lambda x: x > 10, list4)
print(list(result))


'''
lambda函数与内置排序函数sorted()结合:同样可以依照max函数那样依照指定方式排序
''' 
list2 = [{'a': 3, 'b': 6, 'c': 7}, {'a': 5, 'b': 9, 'c': 2}, {'a': 7, 'b': 4, 'c': 1}]
stu = sorted(list2, key=lambda x: x['a'], reverse=True)
print(stu)

1.8.5内部函数(嵌套函数)

# 嵌套函数(内部函数):在函数体内再定义一个函数
a = 9
def func():
    n = 100
    list1 = [1, 2, 3, 4]

    def inner_func():  # 作为内部定义的函数,其与func的局部变量是同一级的,可以对其进行操作
        global a
        nonlocal n
        for index, i in enumerate(list1):  # 单纯的遍历无法对列表中的元素作出更改,但用enumerate函数的遍历就可以
            list1[index] = i + 5
        n += 101
        list1.sort()
        a += 1

    # 调用内部函数
    inner_func()
    print(list1)
    print(n)

    print(locals())  # locals可以查看当前函数声明的内容有哪些,以字典形式打印。即查看其所在函数体中所有的定义内容(包括变量与内部函数)
# 调用外部函数
func()

内部函数的特点:

  • 内部函数可以访问外部函数的变量;
  • 内部函数可以修改外部函数可变类型的变量;
  • 内部函数要修改外部函数的局部变量,要通过nonlocal进行声明;内部函数修改全局变量,需要在内部函数的函数体中进行global声明;
  • 内部函数只能在外部函数的内层进行调用;
  • 不调用外部函数的情况下,内部函数在外部函数内层的调用不会生效。

函数嵌套的情况下,可能会涉及很多作用层次不同的变量。关于局部变量与全局变量、内部函数变量与外部函数变量的具体例子如下:

# 局部变量仅限于在函数内部使用
# 当一个局部变量与全局变量同名时,函数内部优先使用局部变量
# 局部变量可以在函数内部重赋值,但全局变量不能在函数内部随意作修改赋值

name = 'yueyue'

def func1():
    global name  #如果不作全局变量声明,则不能在函数内部对全局变量作赋值修改
    print(name)
    name += '会弹吉他'

def func2():
    name = 'xiaoyueyue'
    name += '弹吉他的小美女'  #局部变量可以在函数内部作随意修改
    print(name)

# 当全局变量为可变类型时无须声明全局变量
name = 'yueyue'
list1 = [1,2,3]

def func3():
    global name  # 如果不作全局变量声明,则不能在函数内部对全局变量作赋值修改
    print(name)
    name += '会弹吉他'

    list1.append(8)  #修改的list1为可变类型无须声明全局变量
    print(list1)

# 同名的全局变量与局部变量不能同时在一个函数体内使用
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值