【python第五章——函数】

第五章——函数

5.1函数概述

快速入门:

#定义函数
def func():
print('123')
 
#调用函数
func()

加小括号是调用函数,不加小括号可能是进行值的传递

(1)函数定义:实现某一项特定功能的代码块
(2)函数分类:内置VS自定义

1)内置函数:Python解释器已经写好的函数,无需对象访问,直接调用即可
内置函数
2)自定义函数:
定义方式:def关键字
调用方式:就是直接写函数名()
注意:函数只有被调用的时候,才会执行里面的代码块

3)函数参数:
形参:形式上的参数,你传递的是啥,我就是啥
实参:实际传过去的参数

def func(a,b): # a,b就是形参
print(a+b)
 
func('hello','world')        # 拼接(实参)
func(100,566)        # 运算(实参)
 
#helloworld
#666

注意:形参和实参要一一对应

4)函数返回值:
关键字:return
说明:所有函数都有返回值,函数是去执行一项功能,执行完必然有反馈
作用:将结果返回给调用处,并结束当前代码
总结:学习一个函数,首先要知道它的功能,其次就是要知道它的参数和返回值

Structure里显示定义的函数
在这里插入图片描述

两种加法器实现方式:

# 加法器1
def fun1(a,b):
print(a+b)
# 加法器2
def fun2(a,b):
return a+b    # 更灵活
 
fun1(10,20)
sum = fun2(30,40)
print(sum)

python这么写会报错:

fun()    # 调用动作必须在声明函数之后
def fun():
print('hello')

从函数中返回函数:
其实并不需要在一个函数里去执行另一个函数,我们也可以将其作为输出返回出来:

def greeting(name="hello"):
    def hello():
        return "now you are in the hello() function"
    def world():
        return "now you are in the world() function"
    if name == "hello":
        return hello
    else:
        return world
 
a = greeting()
print(a)    # <function greeting.<locals>.hello at 0x0000018EE2AD7268>
print(a())  # now you are in the hello() function
b= greeting(name="world")
print(b())  # now you are in the world() function
print(greeting()()) # now you are in the hello() function

注:加小括号是调用函数,不加小括号是进行值的传递,为了在函数中执行另一个函数,在 if/else 语句中我们返回 hello 和 world,而不是 hello() 和 world()
将函数作为参数传给另一个函数:

def world():
    return "world!"
 
def hello(func):
    print(func())
    
hello(world)    # world!

练习题:
(1)定义一个函数,传递整数n,返回1-n之间的偶数和
(2)定义一个函数,使其能够将信息(数字密码)转成暗语输出

def fun1(n):
# 1.验证
import re
if not re.match(r'^-?\d+$',n):
return '非法输入'
# 2.求和
n = int(n)        # 负数不会报错
# 3.负数(这里将负数正常处理了,实际上负数是不能这样做的)
step = 1 if n>=0 else -1
sum=0
for i in range(1,n+step,step):
if i%2==0:
sum+=i
return sum
 
num = input('请输入一个整数:')
print(fun1(num))

(2)定义一个函数,使其能够将信息(数字密码)转成暗语输出
暗语规则:19004546 -> IPOOYSYG
数字	0	1	2	3	4	5	6	7	8	9
暗语	O	I	Z	E	Y	S	G	L	B	P
两种实现方式:

def fun2(sr):
dt = {'0':'O','1':'I','2':'Z','3':'E','4':'Y','5':'S','6':'G','7':'L','8':'B','9':'P'}
ans = ''
for i in sr:
ans += dt[i]
return ans
 
print(fun2("123456789"))
def filter(pwd):        # 123
res = str(pwd)
if not res.isdecimal():
return '非法输入'
p = 'OIZEYSGLBP'
con = ''
for i in res:                # 传进来的每一个数就是p的索引值
con += p[int(i)]
return con
 
pwd = input('请输入您的密码:')
print(filter(pwd))

5.2 函数进阶

1.pass空语句(用在测试):

# pass可以写在所有的冒号场景
# if/while/for/def/……
def fun1():
pass

2.关键字参数:

# 可以给形参和实参都设置关键字
def fun2(a='hello',b='world'):        # 形参关键字
print(a+b)
fun2()                # helloworld
fun2('123')                # 123world
fun2('123','456')                # 123456
# 实参关键字
fun2(a='python')                # pythonworld
fun2(b='java')                # hellojava
fun2(b='css',a='html')        # htmlcss 关键字参数可以不按顺序

3.可变参数:可变参数就是传入的参数个数是可变的,可以是1个、2个到任意个,还可以是0个

# 1)元组写法:
def fun3(*hobby):
print(hobby)
print('我的爱好是:')
for i in hobby:
print(i)
fun3('吃饭','睡觉','打游戏')
 
'''
('吃饭', '睡觉', '打游戏')
我的爱好是:
吃饭
睡觉
打游戏
'''
 
# 2)字典写法:
def fun4(**kwargs):    # 两个星号表示空字典
print(kwargs)

# 关键字参数传值
fun4(id=10,user='root',pwd='123456')        # 键不加引号 {'id': 10, 'user': 'root', 'pwd': '123456'}
# 直接传字典本身,必须加**
fun4(**{'a':10,'b':20})    # {'a': 10, 'b': 20}

关键字参数与可变参数的综合应用:

def fun5(a,b=10,*res):
print(a,b,res)
fun5('hello')                # hello 10()
fun5('hello',123)                # hello 123()
fun5('hello',123,456,789)                # hello 123 (456, 789)
# a是普通参数放最左边,b是关键字参数,*res是可变参数(元组)必须放最后
 
# 接收任意参数(顺序)
def fun6(*args,**kwargs):
print(args)
print(kwargs)
 
fun6()                # {}
'''
()
{}
'''
fun6(a='hello')
'''
()
{'a': 'hello'}
'''
fun6(1,2,3,4,5)
'''
(1, 2, 3, 4, 5)
{}
 
'''
fun6(1,2,3,b='xxx')                # 注意顺序
'''
(1, 2, 3)
{'b': 'xxx'}
'''

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

4.作用域:
局部:函数内部
全局:函数外部

# 写法(1)
a = 10      # 全局
def fun():
    a = 20      # 局部
fun()
print(a)    # 10
 
# 写法(2)
b = 10
def fun2():
    # 结论:当局部变量在当前作用域找不到的时候,向上寻找
    # 注意:只能向上寻找,不能向下寻找
    print(b)
fun2()      # 10
 
# 写法(3)
# 需求:在函数内部修改全局变量
c = 10
def fun3():
    global  c       #注意:一定要先声明
    c = 20
fun3()
print(c)        # 20
 
 
d = None      # 相当于java或c中的声明变量且没赋值
def fun4():
    global d
    d = 10
fun4()
print(d)        # 10
 
# 写法(4)
def fun5(pwd):      # pwd形参(局部变量)
    print(pwd)
pwd = '123456'
fun5(pwd)       # 123456 pwd实参(全局变量)

推荐看一下其他人的文章以熟悉一下global()函数的其他用法

5.匿名函数:lambda表达式
说明:匿名就是函数没有名字

# 正常写法:
def fun(x,y):
    return x+y
print(fun(1,3))
 
# 匿名写法
sum = lambda x,y:x+y

lambda表达式就是匿名函数,没有名称的函数,但返回的变量可以看成lambda的名称.正常调用函数的写法就是调用该变量的写法
说明:lambda只是一个表达式,不能单独存储,且函数体比直接def定义的函数要简单
说明:lambda主体是一个表达式,而不是一个代码块,所以在lambda表达式中封装的逻辑很有限

关于sort()排序:

(1)reverse场景

ls=[1,45,6,2,33,78,11]
ls.sort(reverse=True)
print(ls)   # [78, 45, 33, 11, 6, 2, 1]
ls.sort(reverse=False)
print(ls)   # [1, 2, 6, 11, 33, 45, 78]

(2)key的场景

def fun(con):
    return int(re.search('\d+',con).group())    # 每一句开头的数字 group()用来提出分组截获的字符串,()用来分组
 
import re
 
sr = "12.一代天骄成吉思汗,只识弯弓射大雕。9.须晴日,看红装素裹,分外妖娆。2.千里冰封,5.惟余莽莽;3.万里雪飘,4.望长城内外,6.大河上下,1.北国风光,7.顿失滔滔。8.山舞银蛇,原驰蜡象,欲与天公试比高。11.惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。13.俱往矣,数风流人物,还看今朝。10.江山如此多娇,引无数英雄竞折腰。"
ls = re.findall(r'\d+\D+',sr)
ls.sort(key=fun)        # 注意:key是函数,不能写括号,写括号是调用
for i in ls:
    i = re.findall(r'[\u4e00-\u9fa5]\D+', i)  # 去掉序号
    i = (' '.join(i))  # 去掉元组的括号
    print(i)

(3)lambda表达式

import re

sr = "12.一代天骄成吉思汗,只识弯弓射大雕。9.须晴日,看红装素裹,分外妖娆。2.千里冰封,5.惟余莽莽;3.万里雪飘,4.望长城内外,6.大河上下,1.北国风光,7.顿失滔滔。8.山舞银蛇,原驰蜡象,欲与天公试比高。11.惜秦皇汉武,略输文采;唐宗宋祖,稍逊风骚。13.俱往矣,数风流人物,还看今朝。10.江山如此多娇,引无数英雄竞折腰。"
ls = re.findall(r'\d+\D+',sr)
ls.sort(key=lambda con:int(re.search('\d+',con).group()))
 
for i in ls:
    i=re.findall(r'[\u4e00-\u9fa5]\D+',i)   # 去掉序号
    i=(' '.join(i)) # 去掉元组的括号
    print(i)

lambda练习题:制作键为1-20的字典,值为50-100之间的随机分数
1)将字典随机打乱顺序(返回新字典){19:59,2:87,13:66,…}
2)按分数倒序构建新的字典{5:99,14:98,13:90,…}

from random import randint
from random import shuffle
 
def dt_shuffle(dt):
    ls = list(dt.keys())
    shuffle(ls)
    return {key:dt[key] for key in ls}
 
def dt_sorted(dt):
 
# 思路:lambda表达式
# 思路:列表
#    ls = []
# 1)for循环:[(1,'aa'),(2,'bb'),(3,'cc')]
#    for key,value in dt.items():
#        ls.append((key,value))
# 2)以上思路用一个zip函数即可实现:[(1,'aa'),(2,'bb'),(3,'cc')]
    ls = list(zip(dt.keys(),dt.values()))
    ls.sort(reverse=True,key=lambda tp:tp[1])
# 新字典
    dt_new = {}
    dt_new.update(ls)
 
    return dt_new
 
if __name__ == '__main__':
    # 1.制作字典
    dt = {x:randint(50,100) for x in range(1,21)}
    # 2.随机打乱
    # sorted() 内置函数 sorted(ls,key=lambda i:randint(0,9999))
    # shuffle() 随机数模块的方法
    dt = dt_shuffle(dt) # 随机打乱
    print(dt)
    # 3.值的排序
    dt = dt_sorted(dt)
    print(dt)

6.冒号与箭头:Python3.5新功能
说明:参数中的冒号指参数的类型建议符,告诉开发人员希望传入的实参类型(不是强制,类型不符也不报错)
说明:函数后面的箭头指函数的返回值建议符,用来说明函数返回值

def func(x:int,y:int) -> int:   # -> int表示建议返回值的类型是int
    sum = x+y
    return sum
 
res1 = func('hello','world')
res2 = func(123,456)
print(res1)     # helloworld
print(res2)     # 579
print(res1,res2)    # helloworld 579

7.编程中的经典错误:列表引用问题

def fun(a,b):
    a+=b
    return a
# 1
x=1
y=2
print(fun(x,y))     # 3
print(x)        # 1
print(y)        # 2
 
# 2
x=(1,2)
y=(3,4)
print(fun(x,y))     # (1, 2, 3, 4)
print(x)        # (1, 2)
print(y)        # (3, 4)
 
# 3
x=[1,2]
y=[3,4]
print(fun(x,y))     # [1, 2, 3, 4]
print(x)        # [1, 2, 3, 4] 变了,因为列表可变
print(y)        # [3, 4]
 # 结论:列表是引用传递(指针)在编程中应当注意此种问题,避免得到错误的列表
# 字典
def fun(dt):
    dt['id']='hello'
    return dt
 
dt = {'user':'root'}
print(fun(dt))      # {'user': 'root', 'id': 'hello'}
print(dt)       # {'user': 'root', 'id': 'hello'}
 
#列表
def func(ls):
    ls.append('hello')
    return dt
 
dt={'user':'root'}
print(fun(dt))  # {'user': 'root', 'id': 'hello'}
print(dt)   # {'user': 'root', 'id': 'hello'}
 
# 列表
def func(ls):
    ls.append('hello')
    return ls
    
ls = [1,2,3]
print(func(ls)) # [1, 2, 3, 'hello']
print(ls)   # [1, 2, 3, 'hello']

8.函数递归:递归就是自己调用自己
注意:递归的效率很低,只是有些场景下,递归写法很简单,代码可读性很高
注意:递归相当于死循环,必须有停止的点

# 嵌套调用(不是递归)
def fun1():
    fun2()
def fun2():
    fun3()
def fun3():
    print('hello')
fun1()      # hello
 
# 递归
import time
def func(i):
    print('world')
    i += 1
    time.sleep(0.5)
    if i<=3:
        func(i)
func(0)
 
'''
world
world
world
world
'''

9.函数闭包
语法:函数的闭包,通俗地讲,就是函数内部再写一个函数
作用:可以保持程序上一次运行后的状态,然后继续执行

# 正常传参
def fun(res):
    print(res)
 
# 闭包传参
def func():
    num = 1
    def add(n):
        nonlocal num        # nonlocal只能在内嵌函数中使用,使用前提是外部函数必须先声明nonlocal声明的变量
                            # nonlocal作用:内外共享一个变量
        num += n
        return num
    return add      # 返回的是内嵌函数的名字
 
# 调用
f = func()
print(f(1))     # 2
print(f(2))     # 4 把上一行注释掉再运行一遍的话,就输出3
print(f(3))     # 7 把上一行注释掉再运行一遍的话,就输出4

注意:闭包必须满足一下3个条件,才会产生闭包
1)必须是函数嵌套
2)内部函数必须引用外部函数里的变量
3)外部函数必须返回内嵌函数

10.函数装饰器:

函数装饰器这里仅仅简单的介绍。详细了解可以看看作者“攻城狮白玉”的文章,写的非常透彻

说明:装饰器就是用于拓展原来函数功能的一种函数
实质:装饰器的本质就是闭包函数
场景:在不改变原函数名的情况下,给被装饰对象添加新的功能
原则:函数装饰器有开放封闭原则,即开放是对扩展进行开放,封闭是对修改封闭
1)不改变被装饰对象的源代码(因为容易影响之前的功能)
2)不改变被装饰对象的调用方式(因为调用处多的时候很麻烦)

需求:想要给func升级:获取计算时间

def func():
    sum = 0
    for i in range(101):
        sum+=i
    print(sum)
func()

需求实现1:改变源码

import time
def func():
    start = time.time()
    sum = 0
    for i in range(101):
        sum += i
        time.sleep(0.01)
    print(sum)
    end = time.time()
    print(end-start)
func()

需求实现2:改变调用方式

import time
def func():
    sum = 0
    for i in range(101):
        time.sleep(0.01)        
        sum += i
    print(sum)
def fn():
    start = time.time()
    func()
    end = time.time()
    print(end-start)
 
fn()

需求实现3:闭包写法(避免违背开闭原则)

import time
def func():
    sum = 0
    for i in range(101):
        time.sleep(0.01)
        sum += i
    print(sum)
 
def timer(fn):      # fn就是函数名
    def test():
        start = time.time()
        fn()        # 调用
        end = time.time()
        print(end-start)
    return test
 
a=timer(func)
a()

需求实现4:装饰器写法

import time
# 装饰器构建
def timer(fn):      # fn就是函数名
    def test():
        start = time.time()
        fn()        # 调用
        end = time.time()
        print(end-start)
    return test
# 装饰器写法
@timer      # 注解
def func():
    sum = 0
    for i in range(101):
        time.sleep(0.01)
        sum+=i
    print(sum)
# 调用
func()

多个装饰器

# 装饰器1
def fn01(func):
    def inner():
        print('fn01')
        func()
        print('fn01')
    return inner
 
def fn02(func):
    def inner():
        print('fn02')
        func()
        print('fn02')
    return inner
 
def fn03(func):
    def inner():
        print('fn03')
        func()
        print('fn03')
    return inner
 
@fn03
@fn02
@fn01
def func():
    print('hello123')
 
# 调用
func()
# 输出结果:
#fn03
#fn02
#fn01
#hello123
#fn01
#fn02
#fn03

下面部分之后再写

装饰器习题:
(1)为一个列表推导式函数增加一个验证纯数字的功能
(2)星座问题


5.3函数习题(一些小例子)


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值