函数递归,匿名、内置行数,模块和包,开发规范
一、递归与二分法
一)递归
1、递归调用的定义
递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身
2、递归分为两类:直接与间接
#直接 def func():print('from func')func()func() # 间接 def foo():print('from foo')bar()def bar():print('from bar')foo()
3、递归调用的特点和使用的注意点
递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身 python中的递归效率低,需要在进入下一次递归时保留当前的状态 在其他语言中可以有解决方法:尾递归优化,即在函数的最后一步(而非最后一行)调用自己,尾递归优化:http://egon09.blog.51cto.com/9161406/1842475;但是python又没有尾递归,且对递归层级做了限制#总结递归的使用: 1. 必须有一个明确的结束条件 2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少 3. 递归效率不高,递归层次过多会导致栈溢出 在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出
4、递归的执行分为两个阶段:递推(询问的过程)和回溯(回答的过程)
1 #获知age(5)的值2 # age(5)=age(4)+23 # age(4)=age(3)+24 # age(3)=age(2)+25 # age(2)=age(1)+26 # age(1)=187 #8 # age(n)=age(n-1)+2 #n>19 # age(1)=18 #n=1 10 11 def age(n): 12 if n == 1: 13 return 18 14 return age(n-1)+2 15 16 print(age(5))
5、可以递归的最大深度
1 #虽然可以设置,但是因为不是尾递归,仍然要保存栈,内存大小一定,不可能无限递归2 import sys3 sys.getrecursionlimit() ##获取目前默认递归的最大深度,默认深度是10004 sys.setrecursionlimit(500) ##更改默认递归的最大深度5 n=16 def test():7 global n8 print(n)9 n+=1 10 test() 11 test()
6、应用场景:有许多层的列表,要取出所有元素——设置结束条件使用递归
l =[1, 2,'list' ,[3, [4, 5, 6, [7, 8, [9, 10, [11, 12, 13, [14, 15,[16,[17,]],19]]]]]]] def search(l):for item in l:# if type(item) is list:if isinstance(item,list): ##判断数据类型是否是列表search(item)else:print(item)search(l)
二)二分法
1、二分法的产生
一个按照从小到大排列的数字列表中找到指定的数字,遍历的效率太低,用二分法(算法的一种,算法是解决问题的方法)可以极大低缩小问题规模
2、 二分法的作用:不断将列表切分成两份,减小压力
1 l = [1,2,5,6,77,1001,1165,2340]2 def search(l,num):3 print(l)4 if len(l) > 1:5 mid_index = len(l) // 2 #相除取整6 if num > l[mid_index]:7 #in the right8 l = l[mid_index+1:]9 elif num < l[mid_index]: 10 #in the left 11 l = l[:mid_index] 12 else: 13 print('find it') 14 return 15 else: 16 if l[0] == num: 17 print('find it') 18 else: 19 print('not exists') 20 return 21 search(l,num) #重复的可以放在if里面 22 search(l,77)
二、匿名函数
一)什么是匿名函数
# 有名函数 def f1(m): print(f1(3)) # 匿名函数 lambda n:n*2
二)匿名函数的应用场景
匿名函数自带return,只能使用一次 #匿名函数即没有绑定名字的函数,意味着只能使用一次就会回收 应用场景:只使用一次的功能
三)匿名函数的使用
salaries={'egon':3000,'alex':10000000,'wupeiqi':10000,'yuanhao':2000 }def f1(k):return salaries[k]
1、max、min与 lambda结合
print(max(salaries,key=lambda k:salaries[k])) print(min(salaries,key=lambda k:salaries[k]))
2、sorted与lambda结合
print(sorted(salaries,key=lambda k:salaries[k])) print(sorted(salaries,key=lambda k:salaries[k],reverse=True))
3、map(映射)与lambda结合
将原来的元素进行处理后,重新赋值给原变量
l=['alex','egon','wzs','yuanhao'] print(list(map(lambda x:x+'123',l)))
4、reduce(合并)与lambda结合
计算0到100数字的和
1 from functools import reduce 2 # reduce(lambda 表达式,计算范围,计算的初始值) 3 res=reduce(lambda x,y:x+y,range(1,100),100) 4 print(res)
5、filter(过滤)与lambda结合
过滤出列表中以123结尾的元素
l=['alex123','egon123','wzs123','yuanhao'] print(list(filter(lambda name:name.endswith('123'),l)))
6、扩展: 拉链函数
l1=[1,2,3] s1='hello' res = zip(l1,s1) print(list(res))res=zip(salaries.values(),salaries.keys()) print(max(res)[1])
元素比较大小:从左到右比较元素的大小
1 t1=(111,'a')
2 t2=(11,'b',123,'c')
3 print(t1 < t2)
三、内置函数
一)什么是内置函数
内置函数:python将简单的功能内置到语言中,使用者不用定义,可以直接使用 内置函数链接:https://docs.python.org/3/library/functions.html?highlight=built#ascii
二)常用的内置函数
1、优先掌握的函数
max min sorted map filter sum bool chr divmod enumerate id input print isinstance iter len open pow type zip from _functools import reduce
2、数学运算
abs(-5) # 取绝对值,也就是5 round(2.6) # 四舍五入取整,也就是3.0 pow(2, 3) # 相当于2**3,如果是pow(2, 3, 5),相当于2**3 % 5 cmp(2.3, 3.2) # 比较两个数的大小 divmod(9,2) # 返回除法结果和余数,分页显示内容,计算页数 max([1,5,2,9]) # 求最大值 min([9,2,-4,2]) # 求最小值 sum([2,-1,9,12]) # 求和
3、类型转换
int("5") # 转换为整数 integer float(2) # 转换为浮点数 float long("23") # 转换为长整数 long integer str(2.3) # 转换为字符串 string complex(3, 9) # 返回复数 3 + 9i bytes() # 字节 list((1,2,3)) # 转换为表 list tuple([2,3,4]) # 转换为定值表 tuple dict(a=1,b="hello",c=[1,2,3]) # 构建词典 dictionary set() # 转换成集合 slice(5,2,-1) # 切片操作
python str与bytes之间的转换
1 # bytes object2 b = b"example"3 # str object4 s = "example"5 # str to bytes6 sc = bytes(s, encoding = "utf8")7 print(type(sb))8 # bytes to str9 bs = str(b, encoding = "utf8")
10 # an alternative(可替代的方法) method
11 # str to bytes
12 sc2 = str.encode(s)
13 # bytes to str
14 bs2 = bytes.decode(b)
ASCII表中的字符和序号之间互相转好,应用场景:生成随机验证码
#65-90是大写A-Z print(chr(65)) print(chr(90)) #97-122是小写a-z print(chr(97)) print(chr(122)) print(ord('A')) #48-57是数字0-9 print(chr(48)) print(chr(57))
bool()布尔判断,在python中,为False的情况:空(字符 ‘’,列表 [],元组 (),字典 {}),0,0.0,None
bool(0) # 转换为相应的真假值,在Python中,0相当于False
进制显示
bin(56) # 返回一个字符串,表示56的二进制数 hex(56) # 返回一个字符串,表示56的十六进制数 oct(56) # 返回一个字符串,表示56的八进制数
判断元素是否为True
all([True, 1, "hello!"]) # 是否所有的元素都相当于True值 any(["", 0, False, [], None]) # 是否有任意一个元素相当于True值
排序
sorted([1,5,3]) # 返回正序的序列,也就是[1,3,5] reversed([1,5,3]) # 返回反序的序列,也就是[3,5,1]
4、类、对象、属性
# define class class Me(object):def test(self):print "Hello!" def new_test():print "New Hello!" me = Me()
object() hasattr(me, "test") # 检查me对象是否有test属性 getattr(me, "test") # 返回test属性 setattr(me, "test", new_test) # 将test属性设置为new_test delattr(me, "test") # 删除test属性 isinstance(1,int) # 检查对象是否是类的对象,返回True或False issubclass(Me, object) # Me类是否为object类的子类
5、hash哈希值 :应用——数据校验
hash(object) 如果对象object为哈希表类型,返回对象object的哈希值。哈希值为整数,在字典查找中,哈希值用于快递比价字典的键。 两个数值如果相等,则哈希值也相等。
6、名称空间 局部名称vars()、locals(),全局名称空间global(),显示形式是字典
print(vars() is locals()) print(globals())
7、__import__() 可以导入字符串,import不能导入字符串
# import "time" #不能导入字符串 # import time m=input('>>:') print(type(m)) obj=__import__(m) ##这样就可以导入字符串了 obj.sleep(2) print(m)
8、compile编译,执行exec、eval (了解)
1、compile编译
语法
compile(str,filename,kind) filename:用于追踪str来自于哪个文件,如果不想追踪就可以不定义 kind可以是:single代表一条语句,exec代表一组语句,eval代表一个表达式
应用
s="for i in range(10):print(i)" code=compile(s,'','exec') exec(code) ##有返回结果s1="1+2+3" code1=compile(s1,'','eval') eval(code1) ##没有返回结果
2、eval与exec
eval 提取字符串内的表达式执行,并返回结果(可执行语句会报错)
exec 执行字符串内的表达式或语句,没有返回结果
语法
eval(str,[,globals[,locals]]) exec(str,[,globals[,locals]])
举例
1 s1="1+2+3" 2 # s1="['a','b','c']" 3 s2="for i in range(10):print (i)" 4 print(eval(s1)) 5 print(exec(s1)) 6 print(exec(s2))
四、模块
一)模块介绍
1、什么是模块
一个模块就是一个包含了python定义和声明的文件,文件名就是模块名字加上.py的后缀。
2、为何使用模块
如果你退出python解释器然后重新进入,那么你之前定义的函数或者变量都将丢失,因此我们通常将程序写到文件中以便永久保存下来,需要时就通过python test.py方式去执行,此时test.py被称为脚本script。随着程序的发展,功能越来越多,为了方便管理,我们通常将程序分成一个个的文件,这样做程序的结构更清晰,方便管理。这时我们不仅仅可以把这些文件当做脚本去执行,还可以把他们当做模块来导入到其他的模块中,实现了功能的重复利用
import加载的模块分为四个通用类别
1、使用python编写的代码(.py文件) 2、已被编译为共享库或DLL的C或C++扩展 3、好一组模块的包 4、使用C编写并链接到python解释器的内置模块
3、导入模块都干了哪些事?
1、执行源文件 2、以一个源文件的全局名称空间 3、在当前位置拿到一个模块名,指向2创建的名称空间
4、python文件的两种用途
.py文件的两种用途:1、当做脚本运行 2、当做模块被加载运行文件当做脚本运行时,__name__等于__main__ 文件当做模块被加载运行时,__name__等于模块名
if __name__ == '__main__':# 当做脚本使用func1()func2()func3() # main #回车会导入if __name__ == '__main__':
二)使用import导入模块
模块代码文件:spam.py
#spam.py # print('from the spam.py') # 限制*的导入内容 # _money=1000 #对*隐藏,即*无法调用(from spam import *) # __all__ = ['money','x'] # *只能调用赋予给__all__的名称 (from spam import *) money=10000000000000 def read1():print('spam->read1->money',money)def read2():print('spam->read2 calling read')read1()def change():global moneymoney=0
1、导入模块并执行
test.py
import spam money=100 spam.read1() spam.read2() spam.change() spam.read1() print(money)
2、as取别名
用途:1、模块名非常长; 2、更改模块的功能
测试文件
mysql.py
1 def sqlparse():
2 print('mysql sqlparse')
oracle.py
1 def sqlparse():
2 print('oracle sqlparse')
导入模块,并执行
模块名比较长
1 import spam as s1
2 money = 10000000
3 spam.change()
4 print(spam.money)
传入的内容调用不同的模块
1 sql_type = input('sql_type>>')
2 if sql_type == 'mysql':
3 import mysql as sql ##引用不同的模块,因为实现的功能是相同的,所以可以起相同的别名
4 elif sql_type == 'oracle':
5 import oracle as sql
6 sql.sqlparse()
3、导入多个模块:模块之间用逗号隔开(不建议这么写,还是不同模块分行写为好)
import os,sys,requests
4、模块导入的特点
模块只在第一次导入时才会执行,之后的导入都是直接引用内存已经存在的结果
导入,并验证是否已在内存中
1 import spam2 import spam3 import spam4 import spam5 6 #验证是否已经在内存7 import sys8 # print(sys.modules) #存放的是已经加到内存的模块9 print('spam' in sys.modules) #查看一个模块是否加到内存中
10 import spam
11 print('spam' in sys.modules)
三)from....import...导入模块
1、对比import导入模块,from....import...的优缺点
1 对比import spam,会将源文件的名称空间'spam'带到当前名称空间中,使用时必须是spam.名字的方式 2 而from 语句相当于import,也会创建新的名称空间,但是将spam中的名字直接导入到当前的名称空间中,在当前名称空间中,直接使用名字就可以了 3 优点:使用源文件内的名字时,无需加前缀,使用方便 4 缺点:容易与当前文件的名称空间内的名字混淆,会覆盖原来名字的值
2、语法范例
1 from spam import money,read1,read2 2 money = 10 3 print(money) 4 # g=read1() 5 g=read2() 6 print(g)
3、将模块导入并起别名
# # from spam import read1 as m from spam import money as m # print(m)
4、*的使用 (不建议使用*)
#要引用的源文件里面的内容很多时,可以使用*代替所有(更容易与当前文件的名称空间冲突),但是不建议使用_money=1000 #将调用的名字前面加_,*就无法调用该名字(在源文件修改) __all__ = ['money','x'] # *只能调用赋予给__all__的名称(在源文件修改) from spam import *
四)模块的搜索路径
1、模块查找的顺序
查找顺序:内存---->>内置模块---->>硬盘
范例
import time import importlib import spam time.sleep(30) # import spam # print(spam.money)importlib.reload(spam) ##重启加载spam,可以使用到测试环境 print(spam.money)
2、模块的注意事项
注意:1、Python程序只有重新加载才能生效2、Python自带的模块名不能使用
3、搜索路径和注意事项
当一个命名为spam的模块被导入时解释器首先会从内建模块中寻找该名字找不到,则去sys.path中找该名字 sys.path从以下位置初始化1 执行文件所在的当前目录2 PTYHONPATH(包含一系列目录名,与shell变量PATH语法一样)3 依赖安装时默认指定的 注意:在支持软连接的文件系统中,执行脚本所在的目录是在软连接之后被计算的,换句话说,包含软连接的目录不会被添加到模块的搜索路径中 在初始化后,我们也可以在python程序中修改sys.path,执行文件所在的路径默认是sys.path的第一个目录,在所有标准库路径的前面。这意味着,当前目录是优先于标准库目录的,需要强调的是:我们自定义的模块名不要跟python标准库的模块名重复
4、添加到path环境变量
import sys print(sys.path) # 添加path环境变量 # 加到最后面 sys.path.append(r'G:\data\PyCharm_Project\s19\day5\模块\模块的搜索路径\aaa') # 加到最前面 sys.path.insert(0,r'G:\data\PyCharm_Project\s19\day5\模块\模块的搜索路径\aaa')import spamfrom aaa import #模块的搜索路径
五)模块的重载
考虑到性能的原因,每个模块只被导入一次,放入字典sys.module中,如果你改变了模块的内容,你必须重启程序,python不支持重新加载或卸载之前导入的模块
有的同学可能会想到直接从sys.module中删除一个模块不就可以卸载了吗,注意了,你删了sys.module中的模块对象仍然可能被其他程序的组件所引用,因而不会被清楚。
特别的对于我们引用了这个模块中的一个类,用这个类产生了很多对象,因而这些对象都有关于这个模块的引用。
如果只是你想交互测试的一个模块,使用 importlib.reload(), e.g. import importlib; importlib.reload(modulename),这只能用于测试环境。
aa.py
1 def func1():
2 print('func1')
reload.py
1 import time,importlib
2 import aa
3
4 time.sleep(20)
5 # importlib.reload(aa)
6 aa.func1()
五、包
1、什么是包
##官网的解释 包是一种通过使用‘.模块名’来组织Python模块名称空间的方式 ##详细解释 包就是一个含有__init__.py文件的文件夹,所以我们创建包的目的就是为了用文件/模块组织起来。 1. 无论是import形式还是from...import形式,凡是在导入语句中(而不是在使用时)遇到带点的,都要第一时间提高警觉:这是关于包才有的导入语法 2. 包是目录级的(文件夹级),文件夹是用来组成py文件(包的本质就是一个包含__init__.py文件的目录) 3. import导入文件时,产生名称空间中的名字来源于文件,import 包,产生的名称空间的名字同样来源于文件,即包下的__init__.py,导入包本质就是在导入该文件 ##强调:1. 在python3中,即使包下没有__init__.py文件,import 包仍然不会报错,而在python2中,包下一定要有该文件,否则import 包报错2. 创建包的目的不是为了运行,而是被导入使用,记住,包只是模块的一种形式而已,包即模块 包A和包B下有同名模块也不会冲突,如A.a与B.a来自俩个命名空间
2、为何要使用包
随着功能越写越多,我们无法将所有功能都放到一个文件中,于是我们使用模块去组织功能,而随着模块越来越多,我们需要用文件夹将模块文件组织起来,依次来提供程序的结构性和可维护性
3、注意事项
1.关于包相关的导入语句也分为import和from ... import ...两种,但是无论哪种,无论在什么位置,在导入时都必须遵循一个原则:凡是在导入时带点的,点的左边都必须是一个包,否则非法。可以带有一连串的点,如item.subitem.subsubitem,但都必须遵循这个原则。 2.对于导入后,在使用时就没有这种限制了,点的左边可以是包,模块,函数,类(它们都可以用点的方式调用自己的属性)。 3.对比import item 和from item import name的应用场景: 如果我们想直接使用name那必须使用后者。
4、实战
实验一准备:执行文件为test.py,内容#test.pyimport aaa同级目录下创建目录aaa,然后自建空__init__.py(或者干脆建包)需求:验证导入包就是在导入包下的__init__.py解决:先执行看结果再在__init__.py添加打印信息后,重新执行2、实验二准备:基于上面的结果需求:aaa.xaaa.y解决:在__init__.py中定义名字x和y3、实验三准备:在aaa下建立m1.py和m2.py#m1.pydef f1():print('from 1')#m2.pydef f2():print('from 2')需求:aaa.m1 #进而aaa.m1.func1()aaa.m2 #进而aaa.m2.func2()解决:在__init__.py中定义名字m1和m2,先定义一个普通变量,再引出如何导入模块名,强调:环境变量是以执行文件为准4、实验四准备:在aaa下新建包bbb需求:aaa.bbb解决:在aaa的__init__.py内导入名字bbb5、实验五准备:在bbb下建立模块m3.py#m3.pydef f3():print('from 3')需求:aaa.bbb.m3 #进而aaa.bbb.m3.f3()解决:是bbb下的名字m3,因而要在bbb的__init__.py文件中导入名字m3,from aaa.bbb import m36、实验六准备:基于上面的结果需求:aaa.m1()aaa.m2()aaa.m3()进而实现aaa.f1()aaa.f2()aaa.f3()先用绝对导入,再用相对导入解决:在aaa的__init__.py中拿到名字m1、m2、m3包内模块直接的相对导入,强调包的本质:包内的模块是用来被导入的,而不是被执行的用户无法区分模块是文件还是一个包,我们定义包是为了方便开发者维护7、实验七将包整理当做一个模块,移动到别的目录下,操作sys.path
二)包的使用
1、测试文件:执行文件与测试文件在同级目录下
包 ├── aaa │ ├── bbb │ │ ├── __init__.py │ │ ├── m3.py │ │ └── __pycache__ │ ├── __init__.py │ ├── m1.py │ ├── m2.py │ └── __pycache__ └── run.py
文件内容
##文件内容#m1.py
def func1():print('f1')#m2.py
def func2():print('f2')#m3.py
def func3():print('f3')
2、包的使用之import
单独导入包名称时,不会导入包中的所有包含的所有子模块
#在与aaa同级的run.py import aaa aaa.m1.func1()执行结果会出现如下错误: ModuleNotFoundError: No module named 'm1'
解决方法
#与aaa底下的__init__.py from .m1 import func1#导入模块,执行aaa同级的run.py的结果 import aaaf1
需要注意的:
from后import导入的模块,必须是明确的一个不能带点,否则会有语法错误,如:from a import b.c是错误语法
from aaa.bbb.m3 import func3
3、from aaa.bbb.m3 import * :从一个包中导入所有*
在 Windows 平台上工作的就不是非常好,因为 Windows 是一个不区分大小写的系统。
想从包api中导入所有,实际上该语句只会导入包api下__init__.py文件中定义的名字,我们可以在这个文件中定义__all___:
#在__init__.py中定义 x=10def func():print('from api.__init.py')__all__=['x','func','policy']
4、绝对导入和相对导入
最顶级包是aaa是给用户使用的,然后在aaa内部也会有彼此之间相互导入的需求,这时就有绝对和相对导入两种方式。
绝对导入:以aaa作为起始
相对导入:用.或者..的方式最为起始(只能在一个包中使用,不能用于不同目录内)
例:想在aaa/bbb/func3.py中导入aaa/ccc/func4.py绝对导入在func3.py上写入下面的代码 from aaa.ccc.m4 import func4与run.py同级的__init__.pyd导入相应的模块 from aaa.bbb.m3 import func4在run.py上的写入下面的代码直接调用 aaa.func4()相对导入在func4.py上写入下面的代码 from ..ccc.m4 import func4与run.py同级的__init__.pyd导入相应的模块 from aaa.bbb.m3 import func4在run.py上的写入下面的代码直接调用 aaa.func4()
5、包以及包所包含的模块都是用来被导入的,而不是被直接执行的。而环境变量都是以执行文件为准的
添加环境变量
import sys sys.path.append(r'C:\Users\wz\PycharmProjects\python36\s19\day5\包\xxx\yyy') import aaa
aaa同级的__init__.py内容
1 from .m1 import func1
2 from .m2 import func2
3 from .bbb.m3 import func3
4 from .bbb.m3 import func4
m3.py文件内容
1 from ..ccc.m4 import func4
2 def func3():
3 print('f3')
4 func4()
运行run.py文件内容
1 import sys
2 sys.path.append(r'C:\Users\wz\PycharmProjects\python36\s19\day5\包\xxx\yyy')
3 import aaa
4 aaa.func1()
5 aaa.func2()
6 aaa.func3()
运行文件使用import直接导入所需模块的功能(使用了解目录结构):
导入:import aaa.ccc.m4
调用:aaa.ccc.c4.func4()
6、包的分发(了解)
学习链接网址:Packaging Python Projects - Python Packaging User Guide
六、软件开发规范
一)软件目录规范如下
二)常用模块的使用
常用模块的使用
1 #=============>bin目录:存放执行脚本2 #sos.path.dirname(os.path.dirname(os.path.abspath(__file__)))6 sys.path.append(BASE_DIR)7 8 from core import core9 from conf import my_log_settings10 11 if __name__ == '__main__':12 my_log_settings.load_my_logging_cfg()13 core.run()14 15 #=============>conf目录:存放配置文件16 #config.ini17 [DEFAULT]18 user_timeout = 100019 20 [egon]21 password = 12322 money = 1000000023 24 [alex]25 password = alex371426 money=1000000000027 28 [yuanhao]29 password = ysb12330 money=1031 32 #settings.py33 import os34 config_path=r'%s\%s' %(os.path.dirname(os.path.abspath(__file__)),'config.ini')35 user_timeout=1036 user_db_path=r'%s\%s' %(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),\37 'db')38 39 40 #my_log_settings.py41 """42 logging配置43 """44 45 import os46 import logging.config47 48 # 定义三种日志输出格式 开始49 50 standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \51 '[%(levelname)s][%(message)s]' #其中name为getlogger指定的名字52 53 simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'54 55 id_simple_format = '[%(levelname)s][%(asctime)s] %(message)s'56 57 # 定义日志输出格式 结束58 59 logfile_dir = r'%s\log' %os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # log文件的目录60 61 logfile_name = 'all2.log' # log文件名62 63 # 如果不存在定义的日志目录就创建一个64 if not os.path.isdir(logfile_dir):65 os.mkdir(logfile_dir)66 67 # log文件的全路径68 logfile_path = os.path.join(logfile_dir, logfile_name)69 70 # log配置字典71 LOGGING_DIC = {72 'version': 1,73 'disable_existing_loggers': False,74 'formatters': {75 'standard': {76 'format': standard_format77 },78 'simple': {79 'format': simple_format80 },81 },82 'filters': {},83 'handlers': {84 #打印到终端的日志85 'console': {86 'level': 'DEBUG',87 'class': 'logging.StreamHandler', # 打印到屏幕88 'formatter': 'simple'89 },90 #打印到文件的日志,收集info及以上的日志91 'default': {92 'level': 'DEBUG',93 'class': 'logging.handlers.RotatingFileHandler', # 保存到文件94 'formatter': 'standard',95 'filename': logfile_path, # 日志文件96 'maxBytes': 1024*1024*5, # 日志大小 5M97 'backupCount': 5,98 'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了99 },
100 },
101 'loggers': {
102 #logging.getLogger(__name__)拿到的logger配置
103 '': {
104 'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
105 'level': 'DEBUG',
106 'propagate': True, # 向上(更高level的logger)传递
107 },
108 },
109 }
110
111
112 def load_my_logging_cfg():
113 logging.config.dictConfig(LOGGING_DIC) # 导入上面定义的logging配置
114 logger = logging.getLogger(__name__) # 生成一个log实例
115 logger.info('It works!') # 记录该文件的运行状态
116
117 if __name__ == '__main__':
118 load_my_logging_cfg()
119
120 #=============>core目录:存放核心逻辑
121 #core.py
122 import logging
123 import time
124 from conf import settings
125 from lib import read_ini
126
127 config=read_ini.read(settings.config_path)
128 logger=logging.getLogger(__name__)
129
130 current_user={'user':None,'login_time':None,'timeout':int(settings.user_timeout)}
131 def auth(func):
132 def wrapper(*args,**kwargs):
133 if current_user['user']:
134 interval=time.time()-current_user['login_time']
135 if interval < current_user['timeout']:
136 return func(*args,**kwargs)
137 name = input('name>>: ')
138 password = input('password>>: ')
139 if config.has_section(name):
140 if password == config.get(name,'password'):
141 logger.info('登录成功')
142 current_user['user']=name
143 current_user['login_time']=time.time()
144 return func(*args,**kwargs)
145 else:
146 logger.error('用户名不存在')
147
148 return wrapper
149
150 @auth
151 def buy():
152 print('buy...')
153
154 @auth
155 def run():
156
157 print('''
158 购物
159 查看余额
160 转账
161 ''')
162 while True:
163 choice = input('>>: ').strip()
164 if not choice:continue
165 if choice == '1':
166 buy()
167
168
169
170 if __name__ == '__main__':
171 run()
172
173 #=============>db目录:存放数据库文件
174 #alex_json
175 #egon_json
176
177 #=============>lib目录:存放自定义的模块与包
178 #read_ini.py
179 import configparser
180 def read(config_file):
181 config=configparser.ConfigParser()
182 config.read(config_file)
183 return config
184
185 #=============>log目录:存放日志
186 #all2.log
187 [2017-07-29 00:31:40,272][MainThread:11692][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
188 [2017-07-29 00:31:41,789][MainThread:11692][task_id:core.core][core.py:25][ERROR][用户名不存在]
189 [2017-07-29 00:31:46,394][MainThread:12348][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
190 [2017-07-29 00:31:47,629][MainThread:12348][task_id:core.core][core.py:25][ERROR][用户名不存在]
191 [2017-07-29 00:31:57,912][MainThread:10528][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
192 [2017-07-29 00:32:03,340][MainThread:12744][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
193 [2017-07-29 00:32:05,065][MainThread:12916][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
194 [2017-07-29 00:32:08,181][MainThread:12916][task_id:core.core][core.py:25][ERROR][用户名不存在]
195 [2017-07-29 00:32:13,638][MainThread:7220][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
196 [2017-07-29 00:32:23,005][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
197 [2017-07-29 00:32:40,941][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
198 [2017-07-29 00:32:47,222][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
199 [2017-07-29 00:32:51,949][MainThread:7220][task_id:core.core][core.py:25][ERROR][用户名不存在]
200 [2017-07-29 00:33:00,213][MainThread:7220][task_id:core.core][core.py:20][INFO][登录成功]
201 [2017-07-29 00:33:50,118][MainThread:8500][task_id:conf.my_log_settings][my_log_settings.py:75][INFO][It works!]
202 [2017-07-29 00:33:55,845][MainThread:8500][task_id:core.core][core.py:20][INFO][登录成功]
203 [2017-07-29 00:34:06,837][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
204 [2017-07-29 00:34:09,405][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
205 [2017-07-29 00:34:10,645][MainThread:8500][task_id:core.core][core.py:25][ERROR][用户名不存在]
相关文章:

函数递归,匿名、内置行数,模块和包,开发规范
一、递归与二分法 一)递归 1、递归调用的定义 递归调用:在调用一个函数的过程中,直接或间接地调用了函数本身 2、递归分为两类:直接与间接 #直接 def func():print(from func)func()func() # 间接 def foo():print(from foo)bar…...

Springboot3 整合swagger
一、pom.xml <dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-api</artifactId><version>2.1.0</version></dependency> 二、application.yml # SpringDoc配置 # springdoc:swa…...
查看同一网段内所有设备的ip
使用命令提示符(CMD)进行扫描 查看本机IP地址 首先通过 ipconfig /all 命令查看本机的IP地址,确定你的网段,例如 192.168.1.。 Ping网段内每个IP地址 接着使用循环命令: for /L %i IN (1,1,254) DO ping -w 1 -n …...

Spark MLlib 特征工程(上)
文章目录 Spark MLlib 特征工程(上)特征工程预处理 Encoding:StringIndexer特征构建:VectorAssembler特征选择:ChiSqSelector归一化:MinMaxScaler模型训练总结Spark MLlib 特征工程(上) 前面我们一起构建了一个简单的线性回归模型,来预测美国爱荷华州的房价。从模型效果来…...

《SPSS零基础入门教程》学习笔记——03.变量的统计描述
文章目录 3.1 连续变量(1)集中趋势(2)离散趋势(3)分布特征 3.2 分类变量(1)单个分类变量(2)多个分类变量 3.1 连续变量 (1)集中趋势 …...
2024年杭州市网络与信息安全管理员(网络安全管理员)职业技能竞赛的通知
2024年杭州市网络与信息安全管理员(网络安全管理员)职业技能竞赛的通知 一、组织机构 本次竞赛由杭州市总工会牵头,杭州市人力资源和社会保障局联合主办,杭州市萧山区总工会承办,浙江省北大信息技术高等研究院协办。…...
SpringBoot参数校验详解
前言 在web开发时,对于请求参数,一般上都需要进行参数合法性校验的,原先的写法时一个个字段一个个去判断,这种方式太不通用了,Hibernate Validator 是 Bean Validation 规范的参考实现,用于在 Java 应用中…...
安全基础学习-SHA-1(Secure Hash Algorithm 1)算法
SHA-1(Secure Hash Algorithm 1)是一种密码学哈希函数,用于将任意长度的输入数据(消息)转换成一个固定长度的输出(哈希值或摘要),长度为160位(20字节)。SHA-1的主要用途包括数据完整性验证、数字签名、密码存储等。 1、SHA-1 的特性 定长输出:无论输入数据长度是多…...

leetcode350. 两个数组的交集 II,哈希表
leetcode350. 两个数组的交集 II 给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可…...

基于YOLOv8的缺陷检测任务模型训练
文章目录 一、引言二、环境说明三、缺陷检测任务模型训练详解3.1 PCB数据集3.1.1 数据集简介3.1.2 数据集下载3.1.3 构建yolo格式的数据集 3.2 基于ultralytics训练YOLOv83.2.1 安装依赖包3.2.2 ultralytics的训练规范说明3.2.3 创建训练配置文件3.2.4 下载预训练模型3.2.5 训练…...

【upload]-ini-[SUCTF 2019]CheckIn-笔记
上传图片木马文件后看到,检查的文件内容,包含<? 一句话木马提示 检查的文件格式 用如下图片木马,加上GIF89a绕过图片和<?检查 GIF89a <script languagephp>eval($_POST[cmd])</script> .user.ini实际上就是一个可以由用…...
uniapp条件编译使用教学(#ifdef、#ifndef)
#ifdef //仅在xxx平台使用#ifndef //除了在xxx平台使用#endif // 结束 标识平台APP-PLUSAPPMP微信小程序/支付宝小程序/百度小程序/头条小程序/QQ小程序MP-WEIXIN微信小程序MP-ALIPAY支付宝小程序MP-BAIDU百度小程序MP-TOUTIAO头条小程序MP-QQQQ小程序H5H5APP-PLUS-NVUEApp nv…...

NXP i.MX8系列平台开发讲解 - 4.1.2 GNSS 篇(二) - 卫星导航定位原理
专栏文章目录传送门:返回专栏目录 Hi, 我是你们的老朋友,主要专注于嵌入式软件开发,有兴趣不要忘记点击关注【码思途远】 文章目录 关注星号公众号,不容错过精彩 作者:HywelStar Hi, 我是你们的老朋友HywelStar, 根…...
怎样在 SQL 中对一个包含销售数据的表按照销售额进行降序排序?
在当今数字化商业的浪潮中,数据就是企业的宝贵资产。对于销售数据的有效管理和分析,能够为企业的决策提供关键的支持。而在 SQL 中,对销售数据按照销售额进行降序排序,是一项基础但极其重要的操作。 想象一下,您面前有…...

DIAdem 与 LabVIEW
DIAdem 和 LabVIEW 都是 NI (National Instruments) 公司开发的产品,尽管它们有不同的核心功能和用途,但它们在工程、测试和测量领域中常常一起使用,以形成一个完整的数据采集、分析、处理和报告生成的解决方案。 1. 功能和用途 LabVIEW (Lab…...

UE虚幻引擎可以云渲染吗?应用趋势与挑战了解
虚幻云渲染技术是基于虚幻引擎的云端渲染技术,将虚幻引擎的渲染计算任务通过云计算的方式进行处理和渲染、并将渲染结果传输到终端设备上进行展示。虚幻引擎云渲染技术在近年来得到了迅猛的发展,并在各个领域得到了广泛的应用,包括游戏、电影…...

实战分享:DefenderUI在企业环境中的部署与应用
前言 想象一下,你的电脑就像一座坚固的城堡,但城门却时常被一些不速之客窥探甚至企图入侵;Defender,作为城堡自带的守护者,实力自然不容小觑;但你是否觉得它有时候太过低调,有些隐藏技能还没完…...
中英双语介绍金融经济中的鹰派 (Hawkish)和鸽派 (Dovish)
中文版 在金融和经济政策中,“鹰派”和“鸽派”是两种对货币政策和经济管理有不同立场的群体。 鹰派 (Hawkish) 鹰派倾向于担心通货膨胀的风险,通常支持较高的利率和更紧的货币政策,以防止经济过热和控制物价上涨。具体特征包括࿱…...
Android 开发中常用的布局类型及其选择指南
在 Android 开发过程中,选择正确的布局类型对于构建高效、美观且响应式的用户界面至关重要。本文将介绍 Android 中几种最常用的布局类型,并对比它们的特点和适用场景,帮助开发者们做出明智的选择。 1. LinearLayout - 线性布局 特点: LinearLayout 是最基本的布局类型之一…...

短视频SDK解决方案,降低行业开发门槛
美摄科技匠心打造了一款集前沿技术与极致体验于一体的短视频SDK解决方案,它不仅重新定义了短视频创作的边界,更以行业标杆级的短视频特效,让每一帧画面都闪耀不凡光芒。 【技术赋能,创意无限】 美摄科技的短视频SDK,…...

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility
Cilium动手实验室: 精通之旅---20.Isovalent Enterprise for Cilium: Zero Trust Visibility 1. 实验室环境1.1 实验室环境1.2 小测试 2. The Endor System2.1 部署应用2.2 检查现有策略 3. Cilium 策略实体3.1 创建 allow-all 网络策略3.2 在 Hubble CLI 中验证网络策略源3.3 …...
【算法训练营Day07】字符串part1
文章目录 反转字符串反转字符串II替换数字 反转字符串 题目链接:344. 反转字符串 双指针法,两个指针的元素直接调转即可 class Solution {public void reverseString(char[] s) {int head 0;int end s.length - 1;while(head < end) {char temp …...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存
文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...

2025季度云服务器排行榜
在全球云服务器市场,各厂商的排名和地位并非一成不变,而是由其独特的优势、战略布局和市场适应性共同决定的。以下是根据2025年市场趋势,对主要云服务器厂商在排行榜中占据重要位置的原因和优势进行深度分析: 一、全球“三巨头”…...