4.Python 进阶知识
大约 18 分钟约 5505 字
4.Python 进阶知识
1,编码相关
1.1 指定默认的读文件的解码格式保证不乱码
这不是注释,第一行是固定格式 #coding:用什么编码格式读文件
# coding:utg-8 (如果写代码时指定则就是用什么方式编码,如果读文件时指定,则以什么格式解码)
# 代码内容
#Python3里的str类型默认直接存成Unicode所以不存在乱码
#·若要保证Python2的str类型也不乱码
x = u"艾尼你好" # 前面加上u,意思就是Unicode编码注:Python3 默认用 utf-8 解码; Python2 用 ASCII 码解码
2, 读写文件
2.1 控制文件读写内容的模式:t 和 b
# 强调:读写不能单独使用,必须跟r/w/a连用
open()方法,with 语法
1,t模式(默认的模式)
# 读写都以str(Unicode)为单位
# 必须指定encoding="utf-8"
# 必须是文本文件才可以指定编码
2,b模式
# 是对字节进行操作
# 不用指定编码
#文件操作基本流程
1,打开文件
# window系统路径分割问题
# 解决方案一:推荐
f = open(r'C:\a\b\c\aini.txt')
# 解决方案二:open这函数已经解决好了,右斜杠也可以
f = open('C:/a/b/c/aini.txt)
2,操作文件
f = open('./aini.txt',mode='r',encoding='utf-8')
res = f.read()
# 指针会停在最后,所以第二次读的时候没内容,需要重新打开文件,重新读取
# 会读取所有内容
3,关闭文件
f.close() #回收操作系统资源2.2 文件操作的模式
# 文件操作模式
# r w a 默认都是t模式,对文本进行操作(rt,wt,at)
# rb wb ab 对字节进行操作
# a 是追加模式,会往文件末尾开始写,w会把源文件清空掉
# rt+ 可读可写,文件不存在直接报错
# wt+ 可读可写,
# 指针移动
# 指针移动的单位都是bytes字节为单位
# 只有一种特殊情况
# t模式下的read(n),n代表的是字符个数
with open('./aini.txt',mode='rt',encoding='utf-8') as f:
f.read(4) # 四个字符
### 注意: 只有0模式在t模式下使用
f.seek(n,模式) # n值得是指针移动的字节个数,n可以是负数,可以倒着移动
# 模式
# 0 参照的是文件开头位置
# 1 参照的是当前指针的所造位置
# 2 参照物是文件末尾
f.tell ## 获取指针当前位置3,函数参数详解
3.1 位置参数--------关键字参数---------混合使用
1,位置实参:在函数调用阶段, 按照从左到有的顺序依次传入的值
# 特点:按照顺序与形参一一对应
2 关键字参数
# 关键字实参:在函数调用阶段,按照key=value的形式传入的值
# 特点:指名道姓给某个形参传值,可以完全不参照顺序
def func(x,y):
print(x,y)
func(y=2,x=1) # 关键字参数
func(1,2) # 位置参数
3,混合使用,强调
# 1、位置实参必须放在关键字实参前
def func(x,y):
print(x,y)
func(1,y=2)
func(y=2,1)
# 2、不能能为同一个形参重复传值
def func(x,y):
print(x,y)
func(1,y=2,x=3)
func(1,2,x=3,y=4)3.2 默认参数------位置参数与默认参数混用
4,默认参数
# 默认形参:在定义函数阶段,就已经被赋值的形参,称之为默认参数
# 特点:在定义阶段就已经被赋值,意味着在调用阶段可以不用为其赋值
def func(x,y=3):
print(x,y)
func(x=1)
func(x=1,y=44444)
def register(name,age,gender='男'):
print(name,age,gender)
register('三炮',18)
register('二炮',19)
register('大炮',19)
register('没炮',19,'女')
5,位置形参与默认形参混用,强调:
# 1、位置形参必须在默认形参的左边
def func(y=2,x): # 错误写法
pass
# 2、默认参数的值是在函数定义阶段被赋值的,准确地说被赋予的是值的内存地址
# 示范1:
m=2
def func(x,y=m): # y=>2的内存地址
print(x,y)
m=3333333333333333333
func(1)
# 3、虽然默认值可以被指定为任意数据类型,但是不推荐使用可变类型
# 函数最理想的状态:函数的调用只跟函数本身有关系,不外界代码的影响
m = [111111, ]
def func(x, y=m):
print(x, y)
m.append(3333333)
m.append(444444)
m.append(5555)
func(1)
func(2)
func(3)
def func(x,y,z,l=None):
if l is None:
l=[]
l.append(x)
l.append(y)
l.append(z)
print(l)
func(1,2,3)
func(4,5,6)
new_l=[111,222]
func(1,2,3,new_l)3.3 可变长度的参数
6,可变长度的参数(*与**的用法)
# 可变长度指的是在调用函数时,传入的值(实参)的个数不固定
# 而实参是用来为形参赋值的,所以对应着,针对溢出的实参必须有对应的形参来接收
6.1 可变长度的位置参数
# I:*形参名:用来接收溢出的位置实参,溢出的位置实参会被*保存成元组的格式然后赋值紧跟其后的形参名
# *后跟的可以是任意名字,但是约定俗成应该是args
def func(x,y,*z): # z =(3,4,5,6)
print(x,y,z)
func(1,2,3,4,5,6)
def my_sum(*args):
res=0
for item in args:
res+=item
return res
res=my_sum(1,2,3,4,)
print(res)
# II: *可以用在实参中,实参中带*,先*后的值打散成位置实参
def func(x,y,z):
print(x,y,z)
func(*[11,22,33]) # func(11,22,33)
func(*[11,22]) # func(11,22)
l=[11,22,33]
func(*l)
# III: 形参与实参中都带*
def func(x,y,*args): # args=(3,4,5,6)
print(x,y,args)
func(1,2,[3,4,5,6])
func(1,2,*[3,4,5,6]) # func(1,2,3,4,5,6)
func(*'hello') # func('h','e','l','l','o')
6.2 可变长度的关键字参数
# I:**形参名:用来接收溢出的关键字实参,**会将溢出的关键字实参保存成字典格式,然后赋值给紧跟其后的形参名
# **后跟的可以是任意名字,但是约定俗成应该是kwargs
def func(x,y,**kwargs):
print(x,y,kwargs)
func(1,y=2,a=1,b=2,c=3)
# II: **可以用在实参中(**后跟的只能是字典),实参中带**,先**后的值打散成关键字实参
def func(x,y,z):
print(x,y,z)
func(*{'x':1,'y':2,'z':3}) # func('x','y','z')
func(**{'x':1,'y':2,'z':3}) # func(x=1,y=2,z=3)
# 错误
func(**{'x':1,'y':2,}) # func(x=1,y=2)
func(**{'x':1,'a':2,'z':3}) # func(x=1,a=2,z=3)
# III: 形参与实参中都带**
def func(x,y,**kwargs):
print(x,y,kwargs)
func(y=222,x=111,a=333,b=444)
func(**{'y':222,'x':111,'a':333,'b':4444})
# 混用*与**:*args必须在**kwargs之前
def func(x,*args,**kwargs):
print(args)
print(kwargs)
func(1,2,3,4,5,6,7,8,x=1,y=2,z=3)
def index(x,y,z):
print('index=>>> ',x,y,z)
def wrapper(*args,**kwargs): #args=(1,) kwargs={'z':3,'y':2}
index(*args,**kwargs)
# index(*(1,),**{'z':3,'y':2})
# index(1,z=3,y=2)
wrapper(1,z=3,y=2) # 为wrapper传递的参数是给index用的3.4 函数的类型提示
## : 后面是提示信息,可以随意写
def regidter(name:"不能写艾尼",age:"至少18岁"):
print(name)
print(age)
def register(name:str,age:int,hobbies:tuple)->int: # 返回值类型为 int
print(name)
print(age)
print(hobbies)
# 添加提示功能的同时,再添加默认值
def register(name:str = 'aini',age:int = 18 ,hobbies:tuple)->int: # 返回值类型为 int
print(name)
print(age)
print(hobbies)4,装饰器
4.1 装饰器的一步步实现
## 装饰器:装饰器定义一个函数,该函数是用来为其他函数添加额外的工能
## 装饰器就是不修改源代码以及调用方式的基础上增加新功能
## 开放封闭原则
# 开放:指的是对拓展工能是开放的
# 封闭: 指的是对修改源代码是封闭的
## 添加一个计算代码运行时间的工能(修改了源代码)
import time
def index(name,age):
start = time.time()
time.sleep(3)
print('我叫%s,今年%s岁'%(name,age))
end = time.time()
print(end - start)
index(age = 18,name = 'aini')
# --------------------------------------------------------------------------
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def wrapper():
start = time.time()
index1(name="aini", age=18)
time.sleep(3)
end = time.time()
print(end - start)
wrapper()
# 解决了修改原函数,但是也改变了函数调用方式
# --------------------------------------------------------------------------------------
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def wrapper(name,age):
start = time.time()
index1(name, age)
time.sleep(3)
end = time.time()
print(end - start)
wrapper('aini',18)
# -----------------------------------------------------------------------------------
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def wrapper(*args,**kwargs):
start = time.time()
index1(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
wrapper('aini',age = 18)
# ------------------------------------------------------------------------------------
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def outer():
func = index
def wrapper(*args,**kwargs):
start = time.time()
fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return wrapper
f = outer() # f本质就是wrapper函数
### 继续改进
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def outer(fun):
def wrapper(*args,**kwargs):
start = time.time()
fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return wrapper
f = outer(index1) # f本质就是wrapper函数
f(name='aini',age=22)
# 继续改进,偷梁换柱
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
def outer(fun):
def wrapper(*args,**kwargs):
start = time.time()
fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return wrapper
index1 = outer(index1) # f本质就是wrapper函数
index1(name='aini',age=22) # 新功能加上了,也没有修改函数的调用方式
# ---------------------------------------------------------4.2 装饰器最终版本
# 被装饰函数有返回值
########### 装饰器最终版本
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
return [name,age] # 有返回值
def outer(fun):
def wrapper(*args,**kwargs):
start = time.time()
arg = fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return arg # 返回index1 的返回值
return wrapper
index1 = outer(index1) # f本质就是wrapper函数
res = index1(name='aini',age=22) # 新功能加上了,也没有修改函数的调用方式,把原函数的返回值也拿到了
# --------------------------------------------------------------------------------------------------4.3 装饰器语法糖
def outer(fun):
def wrapper(*args,**kwargs):
start = time.time()
arg = fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return arg # 返回index1 的返回值
return wrapper
@outer
def index1(name,age):
print('我叫%s,今年%s岁' % (name, age))
return [name,age] # 有返回值
# -----------------------------------------------
# 与原函数伪装的更像一点
from functools import wraps # 用于把原函数的属性特征赋值给另一个函数
def outer(fun):
@wraps(fun) # 可以把fun函数的所有属性特征加到wrapper函数身上
def wrapper(*args,**kwargs):
# wrapper.__name__ = fun.__name__
# wrapper.__doc__ = fun.__doc__
# 手动赋值麻烦
start = time.time()
arg = fun(*args,**kwargs)
time.sleep(3)
end = time.time()
print(end - start)
return arg # 返回index1 的返回值
return wrapper
@outer
def index1(name,age):
'''我是index1''' # 通过help(index)函数来查看 文档信息,可以通过index.__doc__ = 'xxxxx' 来给某个函数赋值文档信息
# 通过 index__name__ 可以获得函数的名字,也可以对其进行赋值
print('我叫%s,今年%s岁' % (name, age))
return [name,age] # 有返回值4.4 有参装饰器
4.4.1 不用语法糖
### 不用语法糖
def auth(func,db_type):
def wrapper(*args,**kwargs):
name = input('your name:').strip()
pwd = input('your password:').strip()
if db_type == 'file':
print('基于文件验证')
if name == 'aini' and pwd == 'aini123':
print('login success')
res = func(*args,**kwargs)
return res
else:
print('用户名或者密码错误!!')
elif db_type == 'mysql':
print('基于mysql验证')
elif db_type == 'ldap':
print('基于ldap验证')
else:
print('基于其他途径验证')
return wrapper
def index(x,y):
print('index->>%s:%s'%(x,y))
index = auth(index,'file')
index('aini',22)4.4.2 语法糖 01
#---------------------------------------------------------------------
# 语法糖01
def auth(db_type = "file"):
def deco(func):
def wrapper(*args,**kwargs):
name = input('your name:').strip()
pwd = input('your password:').strip()
if db_type == 'file':
print('基于文件验证')
if name == 'aini' and pwd == 'aini123':
print('login success')
res = func(*args,**kwargs)
return res
else:
print('用户名或者密码错误!!')
elif db_type == 'mysql':
print('基于mysql验证')
elif db_type == 'ldap':
print('基于ldap验证')
else:
print('基于其他途径验证')
return wrapper
return deco
deco = auth(db_type = 'file')
@deco
def index(x,y):
print('index->>%s:%s'%(x,y))
index('aini',22)
deco = auth(db_type = 'mysql')
@deco
def index(x,y):
print('index->>%s:%s'%(x,y))
index('aini',22)4.4.3 标准语法糖
# ---------------------------------------------------------------------------------
# 标准语法糖模板
def auth(外界传递的参数):
def deco(func):
def wrapper(*args,**kwargs):
'''自己扩展的功能'''
res = func(*args,**kwargs)
return res
return wrapper
return deco
@auth(外界传递的参数)
def index(x,y):
print(x,y)
return(x,y)
# 标准语法糖02(例子)
def auth(db_type = "file"):
def deco(func):
def wrapper(*args,**kwargs):
name = input('your name:').strip()
pwd = input('your password:').strip()
if db_type == 'file':
print('基于文件验证')
if name == 'aini' and pwd == 'aini123':
print('login success')
res = func(*args,**kwargs)
return res
else:
print('用户名或者密码错误!!')
elif db_type == 'mysql':
print('基于mysql验证')
elif db_type == 'ldap':
print('基于ldap验证')
else:
print('基于其他途径验证')
return wrapper
return deco
@auth(db_type = 'file')
def index(x,y):
print('index->>%s:%s'%(x,y))
index('aini',22)
@auth(db_type = 'file')
def index(x,y):
print('index->>%s:%s'%(x,y))
index('aini',22)5, 迭代器
5.1 基础知识
1,迭代器:迭代取值的工具,迭代是重复的过程,每一次重复都是基于上次的结果而继续的,单纯的重复不是迭代
# 可迭代对象: 但凡内置有__iter__()方法的都称之为可迭代对象
# 字符串---列表---元祖---字典---集合---文件操作 都是可迭代对象
# 调用可迭代对象下的__iter__方法将其转换为可迭代对象
d = {'a':1, 'b':2, 'c':3}
d_iter = d.__iter__() # 把字典d转换成了可迭代对象
# d_iter.__next__() # 通过__next__()方法可以取值
print(d_iter.__next__()) # a
print(d_iter.__next__()) # b
print(d_iter.__next__()) # c
# 没值了以后就会报错, 抛出异常StopIteration
#-----------------------------------------------
d = {'a':1, 'b':2, 'c':3}
d_iter = d.__iter__()
while True:
try:
print(d_iter.__next__())
except StopIteration:
break
# 对同一个迭代器对象,取值取干净的情况下第二次取值的时候去不了,没值,只能造新的迭代器5.2 迭代器与 for 循环工作原理
#可迭代对象与迭代器详解
#可迭代对象:内置有__iter__() 方法对象
# 可迭代对象.__iter__(): 得到可迭代对象
#迭代器对象:内置有__next__() 方法
# 迭代器对象.__next__():得到迭代器的下一个值
# 迭代器对象.__iter__(): 得到的值迭代器对象的本身(调跟没调一个样)-----------> 为了保证for循环的工作
# for循环工作原理
d = {'a':1, 'b':2, 'c':3}
d_iter = d.__iter__()
# 1,d.__iter__() 方法得到一个跌倒器对象
# 2,迭代器对象的__next__()方法拿到返回值,将该返回值赋值给k
# 3,循环往复步骤2,直到抛出异常,for循环会捕捉异常并结束循坏
for k in d:
print(k)
# 可迭代器对象不一定是迭代器对象------------迭代器对象一定是可迭代对象
# 字符串---列表---元祖---字典---集合只是可迭代对象,不是迭代器对象、
# 文件操作时迭代器对象也是可迭代对象6,生成器(本质就是迭代器)
# 函数里包含yield,并且调用函数以后就能得到一个可迭代对象
def test():
print('第一次')
yield 1
print('第二次')
yield 2
print('第三次')
yield 3
print('第四次')
g = test()
print(g) # <generator object test at 0x0000014C809A27A0>
g_iter = g.__iter__()
res1 = g_iter.__next__() # 第一次
print(res1) # 1
res2 = g_iter.__next__() # 第二次
print(res2) # 2
res3 = g_iter.__next__() # 第三次
print(res3) # 3
# 补充
len(s) -------> s.__len__()
next(s) ------> s.__next__()
iter(d) -------> d.__iter__()1,yield 表达式
def person(name):
print("%s吃东西啦!!"%name)
while True:
x = yield None
print('%s吃东西啦---%s'%(name,x))
g = person('aini')
# next(g) =============== g.send(None)
next(g)
next(g)
# send()方法可以给yield传值
# 不能在第一次运行时用g.send()来传值,需要用g.send(None)或者next(g) 来初始化,第二次开始可以用g.send("值")来传值
g.send("雪糕") # aini吃东西啦---雪糕
g.send("西瓜") # aini吃东西啦---西瓜2, 三元表达式
x = 10
y = 20
res = x if x > y else y
# 格式
条件成立时返回的值 if 条件 else 条件不成立时返回的值3,列表生成式
l = ['aini_aaa','dilnur_aaa','donghua_aaa','egon']
res = [name for name in l if name.endswith('aaa')]
print(res)
# 语法: [结果 for 元素 in 可迭代对象 if 条件]
l = ['aini_aaa','dilnur_aaa','donghua_aaa','egon']
l = [name.upper() for name in l]
print(l)
l = ['aini_aaa','dilnur_aaa','donghua_aaa','egon']
l = [name.replace('_aaa','') for name in l if name.endswith('_aaa')]
print(l)4,其他生成器(——没有元祖生成式——)
### 字典生成器
keys = ['name','age','gender']
res = {key: None for key in keys}
print(res) # {'name': None, 'age': None, 'gender': None}
items = [('name','aini'),('age',22),('gender','man')]
res = {k:v for k,v in items}
print(res)
## 集合生成器
keys = ['name','age','gender']
set1 = {key for key in keys}
## 没有元祖生成器
g = (i for i in range(10) if i % 4 == 0 ) ## 得到的是一个迭代器
#### 统计文件字符个数
with open('aini.txt', mode='rt', encoding= 'utf-8') as f:
res = sum(len(line) for line in f)
print(res)5,二分法
l = [-10,-6,-3,0,1,10,56,134,222,234,532,642,743,852,1431]
def search_num(num,list):
mid_index = len(list) // 2
if len(list) == 0:
print("没找到")
return False
if num > list[mid_index]:
list = list[mid_index + 1 :]
search_num(num,list)
elif num < list[mid_index]:
list = list[:mid_index]
search_num(num, list)
else:
print('找到了' , list[mid_index])
search_num(743,l)6,匿名函数与 lambdaj
## 定义
res = lambda x,y : x+y
## 调用
(lambda x,y : x+y)(10,20) # 第一种方法
res(10,20) ## 第二种方法
##应用场景
salary = {
'aini':20000,
'aili':50000,
'dilnur':15000,
'hahhaha':42568,
'fdafdaf':7854
}
res = max(salary ,key= lambda x : salary[x])
print(res)7,模块
## 内置模块
## 第三方模块
## 自定义模块
## 模块的四种形式
1, 使用Python编写的py文件
2, 已被编译为共享库或DLL的C或C++扩展
3, 把一系列模块组织到一起的文件夹(文件夹下面有个__init__.py 该文件夹称为包)
3, 使用C编写并链接到Python解释器的内置模块
import foo
## 首次导入模块会发生什么?
1,执行foo.py
2, 产生foo.py的命名空间
3,在当前文件中产生的有一个名字foo,改名字指向2中产生的命名空间
## 无论是调用还是修改与源模块为准,与调用位置无关
## 导入模块规范
1 Python内置模块
2,Python第三方模块
3,自定义模块
## 起别名
import foo as f
## 自定义模块命名应该纯小写+下划线
## 可以在函数内导入模块7.1 写模块时测试
# 每个Python文件内置了__name__,指向Python文件名
# 当foo.py 被运行时,
__name__ = "__main__"
# 当foo.py 被当做模块导入时,
__name__ != "__main__"
##### 测试时可以if判断,在foo.py文件中写以下判断
if __name__ == "__main__" :
## 你的测试代码7.2 from xxx import xxx
# from foo import x 发生什么事情
1, 产生一个模块的命名空间
2, 运行foo.py 产生,将运行过程中产生的名字都丢到命名空间去
3, 在当前命名空间拿到一个名字,改名字指向模块命名空间7.3 从一个模块导入所有
#不太推荐使用
form foo import *
# 被导入模块有个 __all__ = []
__all__ = [] # 存放导入模块里的所有变量和函数, 默认放所有的变量和函数,也可以手动修改
foo.py
__all__ = ['x','change']
x = 10
def change():
global x
x = 20
a = 20
b = 30
run.py
from foo import * ## * 导入的是foo.py里的 __all__ 列表里的变量和函数
print(x)
change()
print(a) # 会报错,因为foo.py 里的 __all__ 列表里没有a变量7.4 sys.path 模块搜索路径优先级
1, 内存(内置模块)
2, 从硬盘查找
import sys
# 值为一个列表,存放了一系列的文件夹
# 其中第一个文件夹是当前执行所在的文件夹
# 第二个文件夹当不存在,因为这不是解释器存放的,是pycharm添加的
print(sys.path)
# sys.path 里放的就是模块的存放路径查找顺序
[
'E:\\Desktop\\python全栈\\模块', 'E:\\Desktop\\python全栈', 'D:\\软件\\pycharm\\PyCharm 2021.3.1\\plugins\\python\\helpers\\pycharm_display', 'D:\\软件\\python\\python310.zip', 'D:\\软件\\python\\DLLs', 'D:\\软件\\python\\lib', 'D:\\软件\\python', 'C:\\Users\\艾尼-aini\\AppData\\Roaming\\Python\\Python310\\site-packages', 'D:\\软件\\python\\lib\\site-packages', 'D:\\软件\\python\\lib\\site-packages\\win32', 'D:\\软件\\python\\lib\\site-packages\\win32\\lib', 'D:\\软件\\python\\lib\\site-packages\\Pythonwin', 'D:\\软件\\pycharm\\PyCharm 2021.3.1\\plugins\\python\\helpers\\pycharm_matplotlib_backend'
]7.5 sys.modules 查看内存中的模块
import sys
print(sys.module) # 是一个字典,存放导入的模块
## 可以判断一个模块是否已经在内存中
print('foo' in sys.module)7.6 编写规范的模块
"this module is used to ......" # 第一行文档注释
import sys # 导入需要用到的包
x = 1 # 定义全局变量
class foo: # 定义类
pass
def test(): #定义函数
pass
if __name__ == "__main__":
pass8,包(包本身就是模块)
### 包就是一个包含__init__.py的文件夹,包的本质是模块的一种形式,包用来被当做模块导入
### 导入包运行时运行__inti__.py文件里的代码
### 环境变量是以执行文件为准备的,所有的被导入的模块或者说后续的其他的sys.path都是参照执行文件的sys.path9, 软件开发的目录规范
ATM --------------------------------- # 项目跟目录
bin
start.py ---------------------# 启动程序
config ------------------------- # 项目配置文件
setting.py
db ------------------------------- # 数据库相关的文件夹
db_handle.py
lib ------------------------------ # 共享库(包)
common.py
core ------------------------------# 核心代码逻辑
src.py
api -------------------------------# API有关的文件夹
api.py
log -------------------------------# 记录日志的文件夹
user.log
README --------------------------- # 对软件的解释说明
__file__ # 当前文件的绝对路径
# 在start.py中运行 print(__file__) ---------------------- E:\Desktop\python全栈\ATM\bin\start.py
import os
import sys
BASE_DIR = os.path.dirname(os.path.dirname(__file__)) ## 这样可以动态拿到根目录
sys.path.append(BASE_DIR) # 把项目根目录加到环境变量了,这样可以很好的导包了
## 如果把运行文件 start.py 直接放在跟文件的目录下,就不需要处理环境变量了10,反射
10.1 什么是反射
## 反射---------------> 程序运行过程当中,动态的获取对象的信息。10.2 如何实现反射
# 通过dir:查看某一个对象可以.出来那些属性来
# 可以通过字符串反射到真正的属性上,得到熟悉值
## 四个内置函数的使用
hasattr() ## 判断属性是否存在
getattr() ## 得到属性
setattr() ## 设置属性
delattr() ## 删除属性
hasattr(obj,'name') ## 判断对象 obj 有没有 name 属性
getattr(obj,;'name',None) ## 得到对象 obj 的 name 属性,如果没有返回 None
setattr(obj,'name','aini') ## 设置对象 obj 的 name 属性为 "aini"
delattr(obj,'name') ## 删除对象 obj 的 name 属性