函数和变量
1. 变量
1.1 全局变量
# 全局变量
"""
全局变量:
global关键字添加
只有不可变的类型才需要添加global
int float str bool ()
可变的类型不需要添加global
list dist set() 列表、字典、集合
局部变量:
仅限于函数内部
可变和不可变:
可变:
list dist set() 列表、字典、集合
不可变:
当改变变量的值,地址发生改变,就认为此类型不可变:
int float str bool ()
"""
# 不可变 int float str bool ()
a = 1
print(id(a))
a = 2
print(id(a))
a = ''
print(id(a))
a = 'str'
print(id(a))
a = (1, 2, 3)
print(id(a))
a = (1, 2)
print(id(a))
# 可变
a = [1, 2, 3]
print(id(a))
a.remove(3)
print(id(a))
print('局部变量和全局变量'.center(30, '-'))
x = 100
# 局部
def pr():
x = 8
y = 10
print(x)
print(y)
# 全局
def pr2():
print(x)
# 修改全局
def pr3():
global x # 必须声明了才可以动
x = x - 80 # 不能轻易动全局变量
print(x)
pr()
pr2()
pr3()
pr2()
1.2 局部变量,拆装包:*args 、**kwagrs
# 局部变量
"""
可变参数
*args :默认装进一个元组();就是一个容器
*kwargs
argument
一颗星:*
拆装包
装包:
def 函数(*arg): ---------->此时会出现装包操作
pass
拆包:list、tuple、set
函数调用时:函数(*list)|函数(*tuple)|函数(*set)
print(sm(1, *ram_lst)) # 调用加一个* 拆包
拆包过程
两颗星:** #<class 'dict'>
*kwargs:key word 关键字参数
关键字参数赋值才可以;只要不是关键字参数会报错
只有传递参数时key=value形式,才可以装包放进放到字典中
只有** 才会装包
"""
# 多参数:求和
def sm(a, *args):
print(type(args)) # args:是元组 <class 'tuple'>
return a + sum(args)
print(sm(1, 2, 3, 4, 5))
x, *y, z = 1, 2, 3, 4, 5
print(x, y, z) # 默认是放到列表中:1 [2, 3, 4] 5
# 拆包
x, y, z = (7, 8, 9)
print(x, y, z)
# 先拆包、后装包
x, *y, z = (7, 8, 9, 2, 3, 4, 5) # 先拆包、后装包
print(x, y, z)
# 列表中元素的和
ram_lst = [12, 4, 6, 8, 345, 678, 24, 67, 1, 23]
print(sum(ram_lst))
print(sm(1, *ram_lst)) # 调用加一个* 拆包
print("两颗星:**".center(30, "—"))
def show_book(**kwargs): # <class 'dict'> # 关键字参数赋值才可以;只要不是关键字参数会报错
print(type(kwargs))
print(kwargs)
for k, v in kwargs.items():
print(k, v, sep='->')
# 字典装包
show_book(name='张三', age=18, sex='男') # 关键字参数赋值才可以;只要不是关键字参数会报错
# 字典拆包
book = {'name': '西游记', 'author': '曹雪芹', 'number': 5}
show_book(**book) # 拆包
print("单星* 和两颗星:**都存在".center(50, "—"))
def show_all_book(*args, **kwargs):
print(type(args))
print(type(kwargs))
print(args) # ()
print(kwargs) # {}
book = {'name': '红楼梦', 'author': '曹雪芹'}
show_all_book('张三', '李四', **book)
show_all_book('张三', '李四', **{'name': '红楼梦', 'author': '曹雪芹'}) # 只有** 才会装包
print('{}{}{}'.format('AA', 'BB', 'CC'))
print('{name}->{age}'.format(**{'name': '张三', 'age': 18}))
result = '#'.join('A', 'B', 'C')
print(result)
2. 参数(有参、无参)
# 参数:就是在调用函数时,就是向函数中传值的作用
"""
无参:
def 函数名()
pass
有参:
def 函数名(参数1,参数2,参数3)
函数体
pass
带多个参数的函数:
多个参数
默认值、关键字参数
默认值参数:(属于缺省参数,)
def 函数名(参数1,参数2,参数3=值)
pass
def 函数名(参数1,参数2,*args,参数3=值)
pass
调用可以不给默认值参数赋值:
函数名(值1,值2)
注意:
定义函数:普通参数要位于默认参数之前
正确:def 函数名(参数1,参数2,参数3=值)
错误:def 函数名(参数1,参数3=值,参数2)
"""
# 最多登录三次:retry_num:重试次数,默认三次
def login(retry_num=3):
error_num = 1
while error_num <= retry_num:
username = input('请输入用户名:')
password = input('请输入密码:')
if 'admin'.__eq__(username) and '1234'.__eq__(password):
return '登录成功'
else:
if retry_num - error_num > 0:
print('用户名或者密码错误允许错误{}次,还有{}次'.format(retry_num, retry_num - error_num))
error_num += 1 # 每错一次加1
else:
break
return '用户名或者密码错误次数过多,请稍后重试!'
rst = login(4)
print(rst)
'''
求 1-n之间和;但是n必须是参数
'''
def sm(n):
return sum(i for i in range(n + 1))
# 两个数求和
def get_sm(a, b):
if type(a) == type(b) and isinstance(a, int) and isinstance(b, int): # isinstance:类型判断
return a + b
else:
return "类型不一致!"
# 调用
print(sm(100))
print(get_sm(1, 2))
# 借书
3. 函数
1. 什么是函数
# 函数基本操作
import random
"""
函数:复用
定义调用:
def 函数名([参数,...]): # [] 代表可有可无
代码
函数名: get_name() 多个单词下划线分割
search() 单词
代码: 封装重复内容
调用机制:(函数名)
1、先加载导内存
2、使用必须调用
注意:
1. 参数传递:类型属于对象,对象有不同类型的区分,变量是没有类型的:
2. 默认参数的顺序都是固定的,在赋值如果顺序不固定,需要关键字参数:参数名=value 如 login(name, password='1234')
参数:
单参数、多参数
形参、实参
"""
# 函数也是一个变量
def create_verification_code():
code = ''
while len(code) < 4:
result = random.randint(0, 127)
if ord('a') <= result <= ord('z') or ord('A') <= result <= ord('Z'):
code += chr(result)
elif 0 <= result <= 9:
code += str(result)
print(code)
print(create_verification_code) # <function create_verification_code at 0x00000218317180D8>:函数也是一个变量,分配内存空间
# 验证函数是否可用
create_verification_code()
'''
定义一个login函数
admin 1234
输入用户名密码验证正确
'''
# 定义一个登录函数
def login(username, password, is_remember=False): # 默认值参数
if 'admin'.__eq__(username) and '1234'.__eq__(password):
return '登录成功'
else:
return '用户名或者密码错误,登录失败!'
name = input('请输入用户名:')
pwd = input('请输入密码:')
rst = login(name, pwd)
print(rst)
rst = login(name, password='1234') # 默认参数赋值
print(rst)
# 形参、实参
library = ['西游记', '红楼梦', '三国演义', '水浒传']
# 添加书
def add_book(book_name):
library.append(book_name)
# 打印书
def show_book(books):
for book in books:
print(book)
add_book('明清那些事') # 添加书
print(show_book(library))
2. 函数参数注释
# 函数参数说明
"""
函数参数说明:
def 函数名(参数1、参数2、参数3...):
基本注释 ”注释内容“
高级注释:
”“”
参数说明:
:param username: 用户名
:param password: 密码
返回值说明:
:return: 是否登录成功
“”“
"""
def login(username, password):
"""
用户名密码登录
:param username: 用户名
:param password: 密码
:return: 返回成功、失败
"""
if username == 'admin' and password == '1234':
"返回成功后业务逻辑"
print("登录成功!")
else:
"返回失败后业务逻辑"
print("登录失败!")
login("admin", "1234")
练习
# 练习 函数文档注释
"""
局部变量:临时保存数据,函数调用完就回收
全局变量:外侧,(global)
注意:
变量同名问题,局部变量>全局变量
"""
import datetime
lst = ['西游记', '红楼梦', '三国演义', '水浒传']
def show_book(books):
return [book for book in books if book == '三国演义'] # 列表推导式
print(show_book(lst))
num_lst = [1, 4, 90, 35, 79, 34, 89, 12, 90, 34, 89, 26, 90, 99]
# 删除小于50
def remove_element():
[num_lst.remove(n) for n in num_lst[::-1] if n < 50] # 造成遗漏所以反向删除,那样即使下标变化不影响整体结果
print(num_lst)
remove_element() # 删除小于50
print(num_lst)
print('函数使用练习'.center(50, '-'))
'''
需求:
验证时候登录:is_login
自定义一个函数is_login:
参数:username 、password
函数体:
判断用户输入的用户名和密码是否正确,如果正确则返回True,否则返回False
借书:定义一个函数borrow_book
参数:书名:book_name
函数体:
判断是否登录,如何登录则可以借书
如果没有登录则提示:还未登录不能借书
'''
# 是否登录
is_rem = False
def is_login(username, password, is_remember=False):
global is_rem # 使用了全局变量名
if username == 'admin' and password == '1234':
is_rem = is_remember
return True
else:
return False
# 借书
def borrow_book(book_name):
if is_rem or login():
print("登录成功,成功借阅%s!" % book_name)
else:
print("未登录不能借书,请登录!")
n = 3
while n > 0:
if login():
print("登录成功,您可以借书了!")
else:
n -= 1
print("用户名/密码错误,您还有{}次重试机会!".format(n))
def login():
name = input("请输入用户名:")
pwd = input("请输入密码:")
is_remember = bool(input("是否记住用户名密码(True/False):"))
# 登录
return is_login(name, pwd, is_remember)
# 借书
borrow_book('红楼梦!') # 第一次需要登录,可以is_remember 不输入或者输入True
borrow_book('西游记!') # 不需要再登录了
'''
全局变量:
停车费:
1小时4块钱、计算停车费
15分钟一块钱
{车牌:[进入时间,离开时间]}
def enter():
# 键盘输入车牌号
pass
def go_out():
# 键盘输入车牌号
pass
def car_billing():
# 计费
pass
'''
start_time = datetime.datetime.now()
end_time = datetime.datetime.now()
# car_park = [{'陕A1234': [start_time, end_time]}]
car_park = []
def enter():
"""
进入停车场:开始计费
:return: NONE
"""
print("欢迎进入xxx停车场".center(30, '-'))
car_num = input('键盘输入车牌号:')
global start_time
start_time = datetime.datetime.now()
print(start_time)
car_info = {car_num: [start_time, end_time]}
car_park.append(car_info)
print("{}已经进入停车场".format(car_num))
def go_out():
"""
出车计费
:return: 返回计费信息
"""
print("退出xxx停车场".center(30, '-'))
car_num = input('键盘输入车牌号:')
global end_time
global car_park
global end_time
for car in car_park:
if isinstance(car, dict): # 可以替换(字典默认和key 比较): for car_num in car
# 字典默认和key 比较
for key in car.keys():
if car_num == key:
end_time = datetime.datetime.now()
car.update({key: [start_time, end_time]})
print(car_billing(car_num))
def car_billing(car_num):
spend_time = 0
for car in car_park:
if isinstance(car, dict):
car_time = car.get(car_num)
print(car_time)
if isinstance(car_time, list):
print(car_time[1], car_time[0])
spend_time = car_time[1] - (car_time[0])
print("spend_time:", spend_time)
return '停车时常{},总车费{}。'.format(spend_time, spend_time / 60 * 4)
enter()
go_out()
3.1 匿名函数
# 匿名函数 + 高级函数
"""
匿名函数定义:
lambda 参数列表:运算表达式
可以接受任何参数,但是只能返回一个表达式的值
使用场景:高阶函数(一个函数的参数是另一个函数,俗称高阶函数)
1. 匿名函数作为参数使用
2. 系统高阶函数:max min sorted
3. filter(匿名函数要求返回bool类型,且bool 类型为真才是过滤)
4. map:提取、加工数据,组成迭代
5. reduce
6. zip
"""
from functools import reduce
def su(a):
return a + 1
print(su)
print(su(5))
r = lambda b: b + 1
print(r)
print(r(5))
print("匿名函数:使用场景->高级函数".center(30, "-"))
def test(n):
print("-------test----->", n)
def func(a, f):
print("----func---->", a)
f(a)
func(6, test)
print("--------------------------------------------------")
print("-------------匿名函数作为参数使用------------")
def func1(a, f):
print("++++++++++", a)
print("=========>", f(a))
func1(5, lambda x: x ** 2) # 匿名函数作为参数传递
print("-------------系统高阶函数------------")
lst = [("tom", 20), ("Tony", 23), ("rose", 30), ("Lily", 10)]
result = max(lst, key=lambda x: x[1])
print(result)
result = min(lst, key=lambda x: x[1])
print(result)
result = sorted(lst, key=lambda x: x[1])
print(result)
result = sorted(lst, key=lambda x: x[1], reverse=True) # 从达到小
print(result)
result = filter(lambda x: x[1] > 18, lst) # filter过滤
print(list(result))
result = map(lambda x: x[1] + 1, lst) # map 映射,提取出来
print(result)
print(list(result))
result = map(lambda x: x[0].title(), lst) # map 映射,提取,加工出来
print(result)
print(list(result))
resu = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) # 就是一种运算
print(resu)
result = zip(lst)
print(result)
3.2 带返回值函数
# 函数返回值
"""
参数:外界向里面传值
返回值:里面的内容向外界传值
def 函数名(参数名):
函数体
return 返回值
调用:
通告return 向外返回值;只要返回就需要接受数据
注意:Python独有的特性:
返回多个值:会以元组形式返回(a,b)
return:可以结束调用
"""
def get_sum(*args):
return sum(args)
print(get_sum(*[1, 1, 2, 3, 4, 5])) # 解包
lst = [1, 3, 2, 9, 4, 5, 13, 56, 34, 23, 67]
# 求最大最小值:返回两个值:元组()
def get_max_min(num_lst):
return min(num_lst), max(num_lst)
print(get_max_min(lst)) # (1, 9)
a, b = get_max_min(lst)
print(a, b) # (1, 9)
print('冒泡排序'.center(30,'-'))
# 冒泡排序
for i in range(len(lst) - 1):
for j in range(len(lst) - i - 1):
if lst[j] > lst[j + 1]:
lst[j], lst[j + 1] = lst[j + 1], lst[j]
print("升序:", lst)
for i in range(len(lst) - 1):
for j in range(len(lst) - i - 1):
if lst[j] < lst[j + 1]:
lst[j], lst[j + 1] = lst[j + 1], lst[j]
print("降序:", lst)
3.3 递归函数
# 递归函数
"""
文件遍历
"""
# 1-10 数字的累加
def count(n):
if n > 0:
n -= 1
else:
return n # 考虑结束
return n + count(n)
print(count(10 + 1)) # 通过递归求1-10 的和
print(count(100 + 1)) # 通过递归求1-100 的和
print("递归实现斐波那契数列".center(30, '-'))
# 递归实现斐波那契数列,并打印
def fibonacci(n):
if 0 < n <= 2:
return 1
result = fibonacci(n - 1) + fibonacci(n - 2)
return result
for i in range(1, 10):
print("------------>", fibonacci(i))
3.4 闭包+嵌套
# 函数闭包+嵌套
""""
嵌套:
注意:
1. 内部函数可以使用外部函数的变量
2. 内部函数不能修改外部函数的变量,nonlocal a 可以修改外部函数变量需要再内部函数中,添加nolocal
闭包:(函数、变量都是如下顺序)
内层函数-------> 全局函数--------->外层函数-------->系统函数(builtins)
闭包三个特点:
1. 嵌套函数
2. 内部函数引用了外部函数的变量
3. 返回值是内部函数
使用场景:
装饰器使用
"""
def outer():
a = 100
def inner():
nonlocal a # 引用外函数变量
b = 200
b += a
a += b
print("我是内函数!", b)
result = locals() # 局部变量查看,以字典形式返回:{'a': 100, 'inner': <function outer.<locals>.inner at 0x00000247463281F8>}
print(result)
print(a)
print(inner) # <function outer.<locals>.inner at 0x0000017531E381F8>
inner() # 调用
print(a) # a 被 nonlocal 局部函数修改
return inner
r = outer() # <function outer.<locals>.inner at 0x00000236F60381F8>
print(r)
print("闭包".center(30, '*'))
r() # 调用内部函数
3.5 装饰器
# 装饰器
"""
装饰器:
原则:遵循开放封闭原则,在不改变原函数的情况下,扩展了函数功能
特点:
1. 日志、权限校验、缓存
2. 统计
定义:
def aaa(func):
def xxx(参数,...):
....
func()
...
return xxx
装饰:
@aaa
def 原函数():
pass
代参数装饰器:*arg,**kwargs
原函数有参数,装饰器必须也有参数
*arg:可变参数
**kwargs:关键字参数
装饰器修饰有返回值的函数:
原函数有返回值,wrapper中必须有返回值
再入装饰器:
"""
def foo():
print("foo")
def func():
print("func")
foo = func # 函数名仅仅是一个变量,相当于变量赋值,地址发生改变
foo()
print("装饰器".center(20, "#"))
def deco_house(fu):
"""
1. 定义装饰器:装修房子
:param fu : 被装饰着的引用
:return wrapper : 返回被装饰后的对象 的地址 ;相当于house_a 装饰前后的地址发生变化
相当于house_a = house-----地址指向发生改变----->house_a = wrapper
"""
def wrapper():
fu()
print("安装家电----->")
print("安装床沙发----->")
print("精装修完成----->")
return wrapper # 返回内部函数
@deco_house # 就会调用deco_house函数--->house_a = deco_house(house_a)
def house_a():
print("毛坯房A")
@deco_house
def house_b():
print("毛坯房B")
house_a()
house_b()
print("带参数的装饰器".center(30, '*'))
def de_house(fu):
def wrapper(*args, **kwargs): # wrapper() got an unexpected keyword argument 'name':(name="香格里拉大酒店") 修改添加**kwargs
fu(*args, **kwargs) # fu 就是house;元组拆包(带星拆元组):*args
print("安装家电----->")
print("安装床沙发----->")
print("精装修完成----->")
return wrapper # 返回内部函数
@de_house
def house(address):
print("房子的地址在:{},是一个毛坯房".format(address))
@de_house
def chang_fang(address, area):
print("房子的地址在:{},是一个毛坯房。建筑面积是:{}平米".format(address, area))
@de_house
def hotel(name, address, area=40):
print("{}的地址在:{},是一个毛坯房。单间建筑面积是:{}平米".format(name, address, area))
house("西安钟楼")
print("--------------------------")
chang_fang("西安雁塔区", 130)
print("------------默认参数--------------")
hotel("全季大酒店", "西安雁塔区")
print("------------指定默认参数--------------")
hotel("全季大酒店", "西安雁塔区", 80)
print("----------关键字参数----------------")
hotel(name="全季大酒店", address="西安雁塔区", area=80)
print("----------关键字参数:修改顺序----------------")
hotel(address="西安高新区", name="香格里拉大酒店", area=150)
print("装饰器修饰有返回值的函数".center(30, '*'))
def make_house(fu):
def wrapper(*args, **kwargs): # wrapper() got an unexpected keyword argument 'name':(name="香格里拉大酒店") 修改添加**kwargs
r = fu(*args, **kwargs) # fu 就是house;元组拆包(带星拆元组):*args
print("预计装修费用是:{}元".format(r))
print("安装家电----->")
print("安装床沙发----->")
print("精装修完成----->")
return r # 原函数有返回值,wrapper中必须有返回值
return wrapper
@make_house
def new_house():
print("毛坯房....")
return 50000
result = new_house()
print(result)
4. 复习
4.1 函数复习
# 函数复习
import sys
"""
函数返回值 : return
return 返回一个或者多个值,也可以单独使用return关键字
return :表示函数结束调用 类似于break;是不过 break 中断当前循环还会执行循环后面的操作,而return 直接结束函数,后面不执行
return a
return a,b ------------>(a,b)
全局变量和局部变量
全局变量
1. 什么是全局变量、全局变量的位置
全局变量可以直接用,但是不能再函数中修改
2. 全局变量是不可变类型:
不可再函数中修改,如果要修改必须加global 关键字声明
3. 全局变量是可变类型
函数中可以修改
4. globals() 函数:可以查看全局变量
局部变量(函数):
1. 函数内部定义的便令
2. 使用范围仅限函数内部;当函数调用结束就会回收变量(生命周期就在内部)
3. 通络 locals 查看局部变量----> 字典
4. 内部函数也可以看成局部变量
可变参数和不可变参数:
当前的值和地址的关系:
可变:值变了,地址没变; dict list set
不可变:值变了 地址也变了; int str bool tuple float
地址引用:传递一个地址
1. 普通的赋值关系:
调函数也会出现一次引用
2. 函数参数
函数参数类型是什么:可变还是不可变
函数嵌套:
闭包(装饰器):
1. 必须是嵌套函数
2. 内部函数引用外部函数变量
3. 返回值是内部函数
"""
print(globals()) # 查看全局变量:返回格式字典:1.系统的全局变量 2. 自定义的全局变量
lst = [1, 2, 3]
lst1 = lst
print(sys.getrefcount(lst1)) # 因为调用会引用一次,所以结果是3
4.2 总结
# 总结
"""
函数:
作用域:LFGB
L: local 本地 局部变量
F:encloseing 嵌套
G:Global 全局
B:built-in 内置函数
嵌套函数:
闭包:
1. 内层函数
2. 内层函数引用外层函数的变量
3. 返回内层函数
4. 函数作为外层函数的参数
使用装饰器:
@ 装饰器名
def 函数名():
pass
# 总结函数
普通函数
1. 无参数:
def func():
pass
2. 有参数
一般参数:
def func(a,b):
pass
可变参数:
def func(*args,**kwargs): args 单个元素; kwargs:关键字参数
pass
func() 、func(1) 、func(a=1)
默认值:
def func(a=1,b=2):
pass
func(a=100) #关键字参数
func(900) #默认给a赋值
3. 返回值
没有返回值
def func():
pass
x = func() ------->X=None
有返回值:
def func():
return 'a','b' # 返回多个值
x = func() ---------> x= ('a','b')
嵌套函数:------->闭包--------> 装饰器
1.闭包:
def func():
def wrapper():
pass
return wrapper()
2. 装饰器:
单层装饰器:
def decorate(func):
def wrapper(*args,**kwargs): # 有参数和无参数都可以
pass
return wrapper
@decorate
def house():
pass
@decorate()
def new_house(a,b):
多层装饰器:
@deco2()
@deco1()
def func(a,b):
pass
装饰器带参数:
def outer(a):
def decorate(func):
def wrapper(*args,**kwargs):
pass
return wrapper
return decorate
@outer(10)
def house(10):
pass
@outer(100)
def house(10):
pass
匿名函数:lambada 函数:返回值
递归函数:自己调用自己
变量的作用域:
global nonlocal
globals locals
LFGB
"""