Python学习9

python学习9

函数(进阶)

1. 函数的概念

函数的命名,和变量名规则相同

def func():
    pass    #pass是空语句,占位作用
    print("函数被调用了")

# 函数调用
func()

print(id(func),type(func))  #函数名本身也查看地址(Hash值),以及类型

函数名也可以作为变量进行赋值\传递\存储

def func1():
    print("func1...")

def func2():
    print("func2...")

def func3():
    print("func3...")

res = func1     #函数名本身也是引用类型,保存的是函数体所在地址空间的内存地址(hash值)

print(id(res),id(func1))

res()           #指向函数体的变量名,可以通过追加小括号,实现函数的调用

myfuncs = [func1,func2,func3]   #函数名可以作为元素,存储在列表中等容器类型中

for f in myfuncs:   #可以进行迭代
    f()             #通过括号实现列表中函数逐一调用的效果

2. 参数

标准参数

(定义时)默认的形式参数,与调用时的位置,逐一对应赋值。
(调用时)标准参数:主要分为”位置参数“和”默认参数“两种方式。
位置参数:

def printInfo(a,b):
    print(a,b)
    
#printInfo(10)      #报错
printInfo(10,20,30) #使用位置参数时,参赛、形参数量要一致;否则报错

默认参数:
(定义时)形式参数指定默认值。
(调用时)可以和位置参数一样进行赋值,也可以不进行赋值;不赋新值,则为默认值。

def prinfInfo(name,age=18):
    print(f"姓名:{name},年龄:{age}")

prinfInfo("张三",20)
prinfInfo("李四")     #调用时,默认参数可以不赋值

def printInfo(name="王五",age):   #SyntaxError: non-default argument follows default argument
    print(f"姓名:{name},年龄:{age}")

printInfo(20)

注意:”默认参数“只能在”位置参数“后,进行定义。
指定参数名赋值
指的是函数调用时, 根据参数名,进行针对性赋值

def prinfInfo(name="王五",age=18,gender="男"):
    print(f"姓名:{name},年龄:{age},性别:{gender}")

# prinfInfo(name="张三",age=20)
prinfInfo(age=20,name="张三")   # 因为制定了形参变量名,所以可以不按照位置循序传递参数

prinfInfo("小红",gender="女",age=18)
#prinfInfo(gender="女",age=18,"小红") #如果 关键字实参 和 位置实参 混合使用,位置实参在前面。否则报错。
可变(个数的)参数

可变参数: *args :将多个参数存储为元组对象
关键字参数: **kwargs:将多个参数存储为字典对象

可变参数

函数定义时*args可以接受任意多个实际参数,args可以替换为任意变量名,符合变量名命名规则就可以

def prinfInfo(name,age,gender,*args):
    print(f"姓名:{name},年龄:{age},性别:{gender}")
    #print(args,type(args))
    print("作品评分自高到低为:",args)

#他参与的电影评分
prinfInfo("张三",25,"男",9.5,8.0,8.6)
"""
姓名:张三,年龄:25,性别:男
作品评分自高到低为: (9.5, 8.0, 8.6)
"""
关键字参数

函数定义时, **kwargs可以接受任意多个键值对形式的实际参数。

def prinfInfo(name,age,gender,**kwargs):
    print(f"姓名:{name},年龄:{age},性别:{gender}")
    #print(args,type(args))
    print(kwargs,type(kwargs))

#身高,国籍,出生地,学历
prinfInfo("张三",25,"男",身高=1.80,国籍="中国",出生地="江苏",学历="硕士")

"""
姓名:张三,年龄:25,性别:男
{'身高': 1.8, '国籍': '中国', '出生地': '江苏', '学历': '硕士'} <class 'dict'>
"""
参数解包

在”函数调用“时,*和**的作用是:”解包“。

  • 符号 * 将传进来的字符串、元组、列表、集合转化为多个标准参数
  • 符号 ** 将传进来的字典,转化为多个关键字参数
def prinfInfo(name,age,gender,*args):
    print(f"姓名:{name},年龄:{age},性别:{gender}")
    print("作品评分自高到低为:",args)

rate = [8.5,8.3,9.0]
rate = (8.5,8.3,9.0)
rate = {8.5,8.3,9.0}    #无序

prinfInfo("张三",25,"男",*rate)

"""
姓名:张三,年龄:25,性别:男
作品评分自高到低为: (8.5, 8.3, 9.0)
"""
参数传递顺序

函数调用时,参数传递的顺序:
(调用时) 实际参数:位置参数、关键字参数
(定义时) 匹配形式参数顺序:args、*args、**kwargs

def testArgs(a,b,c=10,d=20,*args,**kwargs):
    print(f"a={a},b={b},c={c},d={d},args={args},kwargs={kwargs}")

testArgs(1,2,3,c=4,5,6,7,x=100,y=200)   #SyntaxError: positional argument follows keyword argument
#关键字参数之后不能再使用位置参数(只能使用关键字参数)


def testArgs(*args,a,b,c=10,d=20,**kwargs):#可变参数在最前面时,匹配到关键字赋值的其他实际参数
    print(f"a={a},b={b},c={c},d={d},args={args},kwargs={kwargs}")

testArgs(1,2,3,4,5,a=6,c=100,b=8,x=100,y=200)
"""
a=6,b=8,c=100,d=20,args=(1, 2, 3, 4, 5),kwargs={'x': 100, 'y': 200}
"""
命名关键字参数

*后面的参数,被称为“命名关键字参数”

def testStar(a,b,c,*,name,age):
    print(f"a={a},b={b},c={c},name={name},age={age}")

testStar(1,2,3,name="张三",age=30)    # *的作用,表示*后面的参数必须使用命名的方式来进行参数赋值
#name 和 age要使用命名的方式来赋值
"""
a=1,b=2,c=3,name=张三,age=30
"""

3. 返回值

返回值类型

函数可以返回全部数据类型,没有返回值时,默认返回为None

def test():
    pass
    # return "abc"
    # return 2.0
    # return True
    # return 200
    # return ["abc"]
    # return {"a":3}
    # return (3,5)
    # return {1,2,3}
    # return None     #没有返回值时,默认返回为None

res = test()
print(res,type(res))
返回多个值

返回多个值的函数,将需要返回的多个值,封装在列表、字典、元组容器中。
注意: set会改变数据的顺序

def divid(a,b):
    shang = a//b
    yushu = a%b
    return shang,yushu

res = divid(5,2)
print(f"商:{res[0]},余数:{res[1]}")
print(res,type(res))

print(divid(5,2),type(divid(5,2)))
sh,yu = divid(5,2)
print(f"商:{sh},余数:{yu}")

"""
商:2,余数:1
(2, 1) <class 'tuple'>
(2, 1) <class 'tuple'>
商:2,余数:1
"""

4. 局部变量和全局变量

局部变量
def test1():
    a = 100
    print("test1----修改前:",a,id(a))
    a = 300
    print("test1----修改后:",a,id(a))


def test2():
    a = 100     #不同的函数可以定义相同名字的变量,彼此无关
    print("test2---------:", a, id(a))

test1()
test2()
#print(a)   #报错,局部变量只在函数内部有效

"""
test1----修改前: 100 1190271473104
test1----修改后: 300 1190272768592
test2---------: 100 1190271473104
"""

注意:上面id打印的hash值每次运行都会不同,但是test1修改前和test2输出的a的id值是相同的

全局变量

全局变量:在文件内有效,能在多个函数中使用的变量。

a = 100         #定义全局变量

def test1():
    print(a)    #获取全局变量a,输出:100
    
def test2():
    print(a)    #输出:100
    
test1()
test2()
print(a)        #输出:100

在test1和test2的函数中,访问到的a都是100

全局变量和局部变量的作用域

全局变量和局部变量名字相同时,优先使用最近定义的变量。
有局部变量时,优先使用局部变量;没有局部变量时,看是否有全局变量。

a = 100
def test1():
    a = 300             #局部变量优先使用
    print("修改前,获取到局部的a:", a)
    a = 500             #修改局部变量的数值
    print("修改后,获取到局部的a:", a)


def test2():
    #a = 1000
    print("test2获取到全局的a:",a)    #没有局部变量,默认使用全局变量
    
print("全局的a:",a)
test1()
test2()
print("test2执行后的全局的a:",a)

"""
全局的a: 100
修改前,获取到局部的a: 300
修改后,获取到局部的a: 500
test2获取到全局的a: 100
test2执行后的全局的a: 100
"""
在函数中修改全局变量

在函数中修改全局变量前,需要在函数中声明变量为global被修改的全局变量,在其他函数中访问时数据也会跟着改变。

a = 100

def test1():
    global a    #在函数中声明全局变量的关键字:global
    a = 200
    print("test1.....",a)

def test2():
    print("test2中的全局变量:",a)

print("全局的:",a)
test1()
print("test1执行后全局的:",a)
test2()

"""
全局的: 100
test1..... 200
test1执行后全局的: 200
test2中的全局变量: 200
"""
形式参数和局部变量
  • 对于不可变参数,在函数内,每次都是让局部变量指向新的地址值所以a = 10,是局部变量a 指向了新数值的新地址,不影响外部的x。
  • 对于可变参数,在函数内,是传递进来的(原有的)地址值上修改数据内容所以b.append(“bbb”),是修改了(和y相同的)地址空间的列表内容,所以外部参数内容会受影响。
def test(a,b):
    print(f"test函数中的变量值,初始,a={a},b={b}",id(b))
    a = 10
    b.append("bbb")
    print(f"test函数中的变量值,修改后,a={a},b={b}",id(y))

x = 20
y = ["aaa"]
print(f"调用函数前,x={x},y={y}",id(y))
test(x,y)
print(f"调用函数后,x={x},y={y}",id(y))

"""
调用函数前,x=20,y=['aaa'] 1937237600896
test函数中的变量值,初始,a=20,b=['aaa'] 1937237600896
test函数中的变量值,修改后,a=10,b=['aaa', 'bbb'] 1937237600896
调用函数后,x=20,y=['aaa', 'bbb'] 1937237600896
"""

5. 递归函数

1. 递归的概念

递归函数:

#递归函数:
#形式:自己调用自己的函数
"""
本质:循环
    通过循环运行相同的运算过程,每次改变输入参数获取返回值参与下一次循环
    [递]:递进、放入
    [归]:返回
"""
#打印从100到1的整数
for i in range(100,0,-1):
    print(i)

def printNum(n):
    print(n)        #执行的运算
    if n == 1:      #最终结束条件
        return      #返回的数值
    printNum(n-1)   #printNum(99)   #调用自身函数

printNum(100)

递归的写法:

  1. 编写函数体(功能)
  2. 确定结束条件和返回值
  3. 调用函数自身,修改参数
2. 递归的运算过程
阶乘的概念:n! = n * (n-1)!
分析为函数表达式:
f(1) = 1			n <= 1
f(n) = f(n-1) * n	n > 1
def fac(n):
    if n <= 1:
        return 1
    return fac(n-1) * n
                # 5*4*3*2*1
print(fac(5))   #120

请添加图片描述
使用递归,根据用户指定的项数,计算斐波那契数列对应位置的值。

斐波那契数列 (Fibonacci sequence)
0,1,1,2,3,5,8,13,21,34,55,89,144……
f(n) = n        			n<=1
f(n) = f(n-1) + f(n-2)  	n>1
def feb(n):
    if n == 0:
        return 0
    if n == 1:
        return 1
    return feb(n - 1) + feb(n - 2)
print(feb(9))	#34
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值