要求: 1、增加文件文件操作,让所有增加、修改、删除操作后的结果保存在文件里面。 2、增加用户登录系统,不同用户只能管理自己所对应的学生系统 ``` “"”author=Deathfeeling”””
补充:按住Ctrl同时点击模块名,可以查看模块内的方法(实现内容大多数被加密)。
对变量、函数、类进行封装,每一个py文件就是一个模块。
通过 “模块.内容” 的形式去使用模块中的内容(全局变量、函数、类)
import my_list
my_list.count([1, 2, 3, 4, 5])
from my_list import count
count([1, 2, 3, 4, 5])
#这样导入可以直接使用模块中的内容。
导入模块中的所有内容
import 模块 as 新名字 import 模块 import 内容 as 新名字
#将不希望被别的模块导入(执行)的代码放在这个if语句中。
if __name__ == '__main__':
原理:每个模块都有一个__name __属性。 a、这个属性的默认值就是当前模块的文件名(别人导入的情况)。 b、当当前模块正在被执行(直接在当前模块中点击run)的时候,__name __属性的值是__main __。 所以当别人导入这个模块的时候,名字变成了当前模块的文件名,if条件不成立,便不会执行之后的代码。
程序中不管操作任何文件,不管怎么操作,过程都是一样的。
程序中通过变量、列表、字典等保存的数据,在程序结束后都会销毁。
数据持久化、本地化,都要使用文件来保存数据(数据库文件、txt文档、json文件、plist文件、xml文件、二进制文件(图片、音频、视频等))
open(文件地址,打开方式,encoding=编码方式)
文件地址:填文件路径(绝对路径和相对路径) 相对路径: ./ 相对路径(相对于当前文件所在的目录) ../相对路径(相对于当前文件目录的上一个目录) …/相对路径(相对于当前文件目录的上两个目录)
打开方式:读和写的方式 ‘r’ –> 读(默认值),读出来的文字以文本形式返回 ‘rb’ / ‘br’ –> 读,读出来的内容以二进制(bytes)的形式返回 ‘w’ –> 写,写文本到文件中 ‘wb’ / ‘bw’ –> 写,以二进制数据(bytes)到文件中 ‘a’ –> 写,追加
编码方式:以文本的形式读和写的时候才需要设置编码方式。 utf-8:万国码 gbk:只支持中文
返回值:open函数的返回值是被打开的文件对象
a、读文件 关闭文件之前,因为指针问题,每次读操作接着上次指针的位置继续读取。
f.readline(): 每次读一行
f = open('../1111.txt','r')
content = f.readline()
while content:
print(content)
content = f.readline()
f.close
b、写操作 打开方式是‘w’,操作会覆盖原文件;打开方式是‘a’,操作是在文件后追加。
#会覆盖原来的文件
f = open('../1111.txt','w')
f.write('程序员的诗')
f.close
f.close()
当以读的形式打开文件,文件不存在会报错。 当以写的形式(w、a)打开文件,文件会自动创建。
补充:按住Ctrl同时点击模块名,可以查看模块内的方法(实现内容大多数被加密)。
对变量、函数、类进行封装,每一个py文件就是一个模块。
通过 “模块.内容” 的形式去使用模块中的内容(全局变量、函数、类)
import my_list
my_list.count([1, 2, 3, 4, 5])
from my_list import count
count([1, 2, 3, 4, 5])
#这样导入可以直接使用模块中的内容。
导入模块中的所有内容
import 模块 as 新名字 import 模块 import 内容 as 新名字
#将不希望被别的模块导入(执行)的代码放在这个if语句中。
if __name__ == '__main__':
原理:每个模块都有一个__name __属性。 a、这个属性的默认值就是当前模块的文件名(别人导入的情况)。 b、当当前模块正在被执行(直接在当前模块中点击run)的时候,__name __属性的值是__main __。 所以当别人导入这个模块的时候,名字变成了当前模块的文件名,if条件不成立,便不会执行之后的代码。
程序中不管操作任何文件,不管怎么操作,过程都是一样的。
程序中通过变量、列表、字典等保存的数据,在程序结束后都会销毁。
数据持久化、本地化,都要使用文件来保存数据(数据库文件、txt文档、json文件、plist文件、xml文件、二进制文件(图片、音频、视频等))
open(文件地址,打开方式,encoding=编码方式)
文件地址:填文件路径(绝对路径和相对路径) 相对路径: ./ 相对路径(相对于当前文件所在的目录) ../相对路径(相对于当前文件目录的上一个目录) …/相对路径(相对于当前文件目录的上两个目录)
打开方式:读和写的方式 ‘r’ –> 读(默认值),读出来的文字以文本形式返回 ‘rb’ / ‘br’ –> 读,读出来的内容以二进制(bytes)的形式返回 ‘w’ –> 写,写文本到文件中 ‘wb’ / ‘bw’ –> 写,以二进制数据(bytes)到文件中 ‘a’ –> 写,追加
编码方式:以文本的形式读和写的时候才需要设置编码方式。 utf-8:万国码 gbk:只支持中文
返回值:open函数的返回值是被打开的文件对象
a、读文件 关闭文件之前,因为指针问题,每次读操作接着上次指针的位置继续读取。
f.readline(): 每次读一行
f = open('../1111.txt','r')
content = f.readline()
while content:
print(content)
content = f.readline()
f.close
b、写操作 打开方式是‘w’,操作会覆盖原文件;打开方式是‘a’,操作是在文件后追加。
#会覆盖原来的文件
f = open('../1111.txt','w')
f.write('程序员的诗')
f.close
f.close()
当以读的形式打开文件,文件不存在会报错。 当以写的形式(w、a)打开文件,文件会自动创建。
``` ef clean_floor(time): print(‘%s,做地板清洁服务’%time) print(‘收费100’) return 100 def clean_kitchen(time): print(‘%s,做厨房清洁服务’%time) print(‘收费200’) return 200 def call_service(time:str,service): service(time)
#将函数作为参数,传给其他函数 call_service(‘上午十点’,clean_floor) call_service(‘下午五点’,clean_kitchen)
结果: 上午十点,做地板清洁服务 收费100 下午五点,做厨房清洁服务 收费200
##### 2、函数作为函数的返回值
def operation(operator:str): if operator == ‘+’: def my_sum(nums): sum = 0 for num in nums: sum += num print(sum) elif operator == ‘’: def my_sum(*nums): sum1 = 1 for num in nums: sum1 *= num print(sum1)
#将函数返回
return my_sum #返回内部函数作为外部函数的返回值
operation(‘+’)(1,2) operation(‘*’)(2,3,4)
结果: 3 24
### 二、生成器和迭代器
- **生成器就是来生成迭代器,可以把迭代器看成一个容器,类似列表。**
- **生成式--产生一个迭代器的表达式(下面等号右边的式子)**
#通过将生成式产生的迭代器转换成了一个列表 a = (x for x in range(10))
说明:把等号右边全部保存给 a ,每次调用next(a)取一个值,并且保存已经调用的位置,下次调用next(a)时继续调用后面的值。
**生成器和迭代器都是通过 next()来获取里面的数据。不管通过什么方式取出数据,取出数据的位置不会返回。**
`print(next(a))`
###### 1、把生成式的结果转换成一个列表([生成式]):
a = [x for x in range(10)] print(a) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
###### 2、把生成式的结果转换成一个字典:
条件:生成式生成的结果是一个元组,并且元组的元素个数必须是 2
dict1 = dict((x,x*2) for x in range(10)) print(dict1) {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}
#用生成式交换字典key和value dict1 = dict((value,key) for key,value in {‘a’:1,’b’:2}.items()) print(dict1) {1: ‘a’, 2: ‘b’}
### 三、生成器
##### yield 关键字
只要函数中有 yield 关键字,不管执行yield语句与否,这个函数都会变成一个生成器。
a、有 yield 的函数,在调用函数的时候不再是获取返回值,而是产生一个生成器对象,生成器对象中保留的是函数体。
b、当通过 next 获取生成器中的数据的时候,才会去执行函数体,执行到 yield 为止,并且将 yiled 后面的结果作为生成的数据返回,同时记录结束的位置,下次再调用 next 的时候,从上次结束的位置接着往后执行。
练习:写一个生成器,可以产生一个斐波那契数列
def fib(): yield 1 yield 1 x = 1 y = 1 while True: x,y = x+y,x yield x n = fib() #必须保存一下,不然直接next会产生多个生成器,每次取第一个值,结果全为 1 print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) 结果: 1 1 2 3 5 8
### 四、迭代器 -- iter
生成器和生成式产生的对象就是迭代器。
将列表转换成迭代器对象
iter1 = iter([1, 2, 3, 4]) print(iter1) print(next(iter1)) print(next(iter1)) print(next(iter1)) 1 2 3
利用 iter 把其他类型转换成迭代器,取出时候都是用 next 取出,和生成器一样,只是产生方式不同。
### 五、装饰器
装饰器函数:用一个函数装饰另一个函数,装饰器函数的参数是被装饰的函数,返回一个装饰后的函数,当调用被装饰的函数时,其实执行的是装饰器中返回的函数,给他增加额外的功能,凡是需要这个额外的功能的地方,只需要加上装饰器即可,而不需要书写额外的代码。
给函数添加装饰器的语法,就是在函数前添加@函数
import time def record(fn): def wrapper(args, **kwargs): start = time.time() ret_value = fn(args, **kwargs) end = time.time() print(f’{end - start}s’) return ret_value return wrapper
@record def fac(num): result = 1 for n in range(1, num + 1): result *= n return result
if name == ‘main’: for num in range(1, 5): print(fac(num))
结果: 0.0s 1 0.0s 2 0.0s 6 0.0s 24 ```
``` ef clean_floor(time): print(‘%s,做地板清洁服务’%time) print(‘收费100’) return 100 def clean_kitchen(time): print(‘%s,做厨房清洁服务’%time) print(‘收费200’) return 200 def call_service(time:str,service): service(time)
#将函数作为参数,传给其他函数 call_service(‘上午十点’,clean_floor) call_service(‘下午五点’,clean_kitchen)
结果: 上午十点,做地板清洁服务 收费100 下午五点,做厨房清洁服务 收费200
##### 2、函数作为函数的返回值
def operation(operator:str): if operator == ‘+’: def my_sum(nums): sum = 0 for num in nums: sum += num print(sum) elif operator == ‘’: def my_sum(*nums): sum1 = 1 for num in nums: sum1 *= num print(sum1)
#将函数返回
return my_sum #返回内部函数作为外部函数的返回值
operation(‘+’)(1,2) operation(‘*’)(2,3,4)
结果: 3 24
### 二、生成器和迭代器
- **生成器就是来生成迭代器,可以把迭代器看成一个容器,类似列表。**
- **生成式--产生一个迭代器的表达式(下面等号右边的式子)**
#通过将生成式产生的迭代器转换成了一个列表 a = (x for x in range(10))
说明:把等号右边全部保存给 a ,每次调用next(a)取一个值,并且保存已经调用的位置,下次调用next(a)时继续调用后面的值。
**生成器和迭代器都是通过 next()来获取里面的数据。不管通过什么方式取出数据,取出数据的位置不会返回。**
`print(next(a))`
###### 1、把生成式的结果转换成一个列表([生成式]):
a = [x for x in range(10)] print(a) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
###### 2、把生成式的结果转换成一个字典:
条件:生成式生成的结果是一个元组,并且元组的元素个数必须是 2
dict1 = dict((x,x*2) for x in range(10)) print(dict1) {0: 0, 1: 2, 2: 4, 3: 6, 4: 8, 5: 10, 6: 12, 7: 14, 8: 16, 9: 18}
#用生成式交换字典key和value dict1 = dict((value,key) for key,value in {‘a’:1,’b’:2}.items()) print(dict1) {1: ‘a’, 2: ‘b’}
### 三、生成器
##### yield 关键字
只要函数中有 yield 关键字,不管执行yield语句与否,这个函数都会变成一个生成器。
a、有 yield 的函数,在调用函数的时候不再是获取返回值,而是产生一个生成器对象,生成器对象中保留的是函数体。
b、当通过 next 获取生成器中的数据的时候,才会去执行函数体,执行到 yield 为止,并且将 yiled 后面的结果作为生成的数据返回,同时记录结束的位置,下次再调用 next 的时候,从上次结束的位置接着往后执行。
练习:写一个生成器,可以产生一个斐波那契数列
def fib(): yield 1 yield 1 x = 1 y = 1 while True: x,y = x+y,x yield x n = fib() #必须保存一下,不然直接next会产生多个生成器,每次取第一个值,结果全为 1 print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) print(next(n),end=’ ‘) 结果: 1 1 2 3 5 8
### 四、迭代器 -- iter
生成器和生成式产生的对象就是迭代器。
将列表转换成迭代器对象
iter1 = iter([1, 2, 3, 4]) print(iter1) print(next(iter1)) print(next(iter1)) print(next(iter1)) 1 2 3
利用 iter 把其他类型转换成迭代器,取出时候都是用 next 取出,和生成器一样,只是产生方式不同。
### 五、装饰器
装饰器函数:用一个函数装饰另一个函数,装饰器函数的参数是被装饰的函数,返回一个装饰后的函数,当调用被装饰的函数时,其实执行的是装饰器中返回的函数,给他增加额外的功能,凡是需要这个额外的功能的地方,只需要加上装饰器即可,而不需要书写额外的代码。
给函数添加装饰器的语法,就是在函数前添加@函数
import time def record(fn): def wrapper(args, **kwargs): start = time.time() ret_value = fn(args, **kwargs) end = time.time() print(f’{end - start}s’) return ret_value return wrapper
@record def fac(num): result = 1 for n in range(1, num + 1): result *= n return result
if name == ‘main’: for num in range(1, 5): print(fac(num))
结果: 0.0s 1 0.0s 2 0.0s 6 0.0s 24 ```
匿名函数本质还是函数,之前函数的所有内容仍然适用。
函数名 = lambda 参数列表:返回值
函数名:本质是一个变量存储右边的函数。(可无) lambda:声明匿名函数的关键字。 参数列表:参数名1,参数名2,…… 冒号:固定写法。 返回值:表达式的值就是返回值。
#用匿名函数计算两个数的和
my_sum = lambda x, y: x + y
print(my_sum(1,2))
3
匿名函数的调用和普通函数一样:函数名(实参)
#1、写一个匿名函数,获取指定数字列表,指定下标的值得1/2
x = lambda list1,index:list1[index]/2
print(x([1,2,3,4,5],3))
# 2、获取一个列表所有元素的和和平均值(sum函数可以计算一个序列的和)
x = lambda list2 : (sum(list2), sum(list2)/len(list2))
sum,average = x([1,2,3,4,5,6])
print(sum,average)
#或者这样取值
#print(x([1,2,3,4,5,6])[0])
函数的调用过程是一个压栈的过程: 每次调用一个函数,系统就会在内存区域中的栈区间取开辟空间,保存函数调用产生的数据。当函数调用完成后,对应的栈区间会自动销毁。 函数调用时产生的栈区间中保存的数据有:形参、函数中声明变量
作用域:指的是一个变量能够使用的范围
# x, y, z都是局部变量
def func3(x, y):
z = 'ab'
c = 100
def func1():
global c #修改全局变量
c = 200
func1()
print(c)
func6 20 func5 20
### 三、递归函数
**递归函数**:在函数的函数体中调用函数本身,这样的函数就是递归函数。
**注意**:尽量不使用,递归函数反复调用函数,开辟空间,消耗内存。
##### 怎么写递归函数?
(1)、找临界值。(找到让循环结束的值/ 找到能够确定函数结果值)
(2)、假设函数的功能已经实现的前提下,找关系 f(n)和 f(n-1)/ 当次循环和上次循环的关系。
(3)、根据 f(n)和 f(n-1)的关系,来通过 f(n-1)实现 f(n)的效果。
练习:
#练习一 #1+2+3+…+100 def my_sum(n): #在临界值的位置一定要让函数结束 if n == 1: return 1 return my_sum(n-1) + n print(my_sum(100))
结果: 5050
#练习二:计算斐波那契数列1,1,2,3,5,8…第n个数 def fib(n): if n == 1 or n == 2: return 1 return fib(n-1) + fib(n-2) print(fib(5))
结果: 5
#练习三:使用递归完成以下效果 n = 3 #* #
def xxx(n): if n == 1 : print(‘’) return print(‘‘*n) xxx(n-1) xxx(3)
结果: *** ** *
思考一下程序结果和运行过程:
def func(): a = [] for i in range(5): a.append(lambda x:x*i) #先把匿名函数存进去,没有计算返回值。 return a #返回func()值时,开始计算列表内的数,此时 i = 4,所以列表内所有匿名函数 i值都为4 aa = func() print(aa0, aa2, aa3)
结果: 8 8 8 ```