python基础
注释 :
单行注释 #
多行注释 “”“ ”“”
输入输出:
input()输入
print()输出
print(“my name is %s my age is %s” % (“梨花”,”18″))
时间:显示当前时间:time.strftime(“%Y-%m-%d %H:%M:%S”)
休眠:time.sleep(n)
time.time()计算时间间隔
- 对象.__class__.__name__当前类的名字
对象.__class__对象的类
类.__name__类的名字
os模块:
- os.path.dirname(__file__)当前文件的上一个文件夹
os.listdir(文件夹路径)------->获取文件夹中所有文件的名字,扔进一个列表
os.remove()删除文件
os.rename()文件改名
枚举:enumerate(good_list)
- 枚举 enumerate(good_list) ----> return (good_list的索引, 索引对应的值)
- str = “[1,2,3]”
eval(str):把引号里的数据拿出来运行
- sys.path.append()添加环境变量
- issubclass() 这个内置函数可以帮我们判断x类是否是y类型的子类
isinstance可以判断x是否是y类的对象,isinstance可以判断该对象是否是家族体系中的(只能往上判断类)
json:
dict—》json.str—–》f.write(json.str)——>json文件中
将字典转化为json字符串,然后再写进json文件中
- user_path = os.path.join(setting.DB_PATH,'%s.json'%username)
#判断当前用户是否存在 os.path.exits(需要判断的文件路径)
if os.path.exists(user_path):
print("用户已存在,请登录")
continue
with open(user_path,'w',encoding="utf-8") as h:
json.dump(user_dic,h)#先将字典转化为json,然后写
json.load()将json字符串转化为python字符串
变量:
字母、数字、下划线组成,数字不能开头
命名风格:
纯小写+下划线 age_of
驼峰体
变量内存地址
1.等号比较的是值
2.is比较的是地址
地址相同,意味着值和类型相同
值相同type肯定也相同,但地址不一定
-
Numbers(数字)
int(整数类型)
long(长整数类型)
float(浮点型)
complex(复数)
-
String(字符串)
从左到右索引默认0开始的,最大范围是字符串长度少1
从右到左索引默认-1开始的,最大范围是字符串开头
- print str # 输出完整字符串
print str[0] # 输出字符串中的第一个字符
print str[2:5] # 输出字符串中第三个至第六个之间的字符串
print str[2:] # 输出从第三个字符开始的字符串
print str * 2 # 输出字符串两次
print str + "TEST" # 输出连接的字符串
-
List(列表)
列表用 [ ] 标识
- list = [ 'runoob', 786 , 2.23, 'john', 70.2 ]
tinylist = [123, 'john']
print list # 输出完整列表
print list[0] # 输出列表的第一个元素
print list[1:3] # 输出第二个至第三个元素
print list[2:] # 输出从第三个开始至列表末尾的所有元素
print tinylist * 2 # 输出列表两次
print list + tinylist # 打印组合的列表
"""
['runoob', 786, 2.23, 'john', 70.2]
runoob
[786, 2.23]
[2.23, 'john', 70.2]
[123, 'john', 123, 'john']
['runoob', 786, 2.23, 'john', 70.2, 123, 'john']
"""
-
Tuple(元组)
元组用 () 标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。
-
Dictionary(字典)
字典用”{ }”标识。字典由索引(key)和它对应的值value组成。
- tinydict = {'name': 'runoob','code':6734, 'dept': 'sales'}
print dict['one'] # 输出键为'one' 的值
print dict[2] # 输出键为 2 的值
print tinydict。items() # 输出完整的字典
print tinydict.keys() # 输出所有键
print tinydict.values() # 输出所有值
可变、不可变类型:
不可变:值发生改变,内存地址也发生改
整型
字符型
元组
可变数据类型:值发生变化,内存地址不变
列表
集合
字典
运算符:
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 – 两个对象相加 | a + b 输出结果 30 |
– | 减 – 得到负数或是一个数减去另一个数 | a – b 输出结果 -10 |
* | 乘 – 两个数相乘或是返回一个被重复若干次的字符串 | a * b 输出结果 200 |
/ | 除 – x除以y | b / a 输出结果 2 |
% | 取模 – 返回除法的余数 | b % a 输出结果 0 |
** | 幂 – 返回x的y次幂 | a**b 为10的20次方, 输出结果 100000000000000000000 |
// | 取整除 – 返回商的整数部分(向下取整) | >>> 9//2 4 >>> -9//2 -5 |
运算符 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | x and y | 布尔”与” – 如果 x 为 False,x and y 返回 False,否则它返回 y 的计算值。 | (a and b) 返回 20。 |
or | x or y | 布尔”或” – 如果 x 是非 0,它返回 x 的计算值,否则它返回 y 的计算值。 | (a or b) 返回 10。 |
not | not x | 布尔”非” – 如果 x 为 True,返回 False 。如果 x 为 False,它返回 True。 | not(a and b) 返回 False |
除了以上的一些运算符之外,Python还支持成员运算符,测试实例中包含了一系列的成员,包括字符串,列表或元组。
运算符 | 描述 | 实例 |
---|---|---|
in | 如果在指定的序列中找到值返回 True,否则返回 False。 | x 在 y 序列中 , 如果 x 在 y 序列中返回 True。 |
not in | 如果在指定的序列中没有找到值返回 True,否则返回 False。 | x 不在 y 序列中 , 如果 x 不在 y 序列中返回 True。 |
条件语句
- if 判断条件:
执行语句……
else:
执行语句……
- if 判断条件1:
执行语句1……
elif 判断条件2:
执行语句2……
elif 判断条件3:
执行语句3……
else:
执行语句4……
循环语句
while循环
- while 判断条件(condition):
执行语句(statements)……
循环使用 else 语句
- count = 0
while count < 5:
print count, " is less than 5"
count = count + 1
else:
print count, " is not less than 5"
for循环
- for letter in 'Python': # 第一个实例
print("当前字母: %s" % letter)
fruits = ['banana', 'apple', 'mango']
for fruit in fruits: # 第二个实例
print ('当前水果: %s'% fruit)
print ("Good bye!")
通过序列索引迭代
- fruits = ['banana', 'apple', 'mango']
for index in range(len(fruits)):
print ('当前水果 : %s' % fruits[index])
print ("Good bye!")
#内置函数 len() 和 range(),函数 len() 返回列表的长度,即元素的个数。 range返回一个序列的数
循环使用 else 语句
- for num in range(10,20): # 迭代 10 到 20 之间的数字
for i in range(2,num): # 根据因子迭代
if num%i == 0: # 确定第一个因子
j=num/i # 计算第二个因子
print ('%d 等于 %d * %d' % (num,i,j))
break # 跳出当前循环
else: # 循环的 else 部分
print ('%d 是一个质数' % num)
break、continue和pass语句
二者都用在while和for循环中
break退出最近的循环
continue跳过本次循环,运行下一次
pass 不做任何事情,一般用做占位语句。
- for letter in 'Python':
if letter == 'h':
pass
print '这是 pass 块'
print '当前字母 :', letter
print "Good bye!"
"""
当前字母 : P
当前字母 : y
当前字母 : t
这是 pass 块
当前字母 : h
当前字母 : o
当前字母 : n
Good bye!
"""
Number数字:
del删除对象
- del var
del var_a, var_b
math 模块、cmath 模块
函数 | 返回值 ( 描述 ) |
---|---|
返回数字的绝对值,如abs(-10) 返回 10 | |
返回数字的上入整数,如math.ceil(4.1) 返回 5 | |
如果 x < y 返回 -1, 如果 x == y 返回 0, 如果 x > y 返回 1 | |
返回e的x次幂(ex),如math.exp(1) 返回2.718281828459045 | |
返回数字的绝对值,如math.fabs(-10) 返回10.0 | |
返回数字的下舍整数,如math.floor(4.9)返回 4 | |
如math.log(math.e)返回1.0,math.log(100,10)返回2.0 | |
返回以10为基数的x的对数,如math.log10(100)返回 2.0 | |
返回给定参数的最大值,参数可以为序列。 | |
返回给定参数的最小值,参数可以为序列。 | |
返回x的整数部分与小数部分,两部分的数值符号与x相同,整数部分以浮点型表示。 | |
x**y 运算后的值。 | |
[round(x | 返回浮点数x的四舍五入值,如给出n值,则代表舍入到小数点后的位数。 |
返回数字x的平方根 |
随机数函数
函数 | 描述 |
---|---|
从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数。 | |
从指定范围内,按指定基数递增的集合中获取一个随机数,基数默认值为 1 | |
随机生成下一个实数,它在[0,1)范围内。 | |
[seed( | 改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。 |
将序列的所有元素随机排序 | |
随机生成下一个实数,它在[x,y]范围内。 |
三角函数
函数 | 描述 |
---|---|
返回x的反余弦弧度值。 | |
返回x的反正弦弧度值。 | |
返回x的反正切弧度值。 | |
返回给定的 X 及 Y 坐标值的反正切值。 | |
返回x的弧度的余弦值。 | |
返回欧几里德范数 sqrt(xx + yy)。 | |
返回的x弧度的正弦值。 | |
返回x弧度的正切值。 | |
将弧度转换为角度,如degrees(math.pi/2) , 返回90.0 | |
将角度转换为弧度 |
数学常量
常量 | 描述 |
---|---|
pi | 数学常量 pi(圆周率,一般以π来表示) |
e | 数学常量 e,e即自然常数(自然常数)。 |
字符串
字符串连接
- var1 = 'Hello World!'
print "输出 :- ", var1[:6] + 'Runoob!'
#输出 :- Hello Runoob!
转义字符
转义字符 | 描述 |
---|---|
(在行尾时) | 续行符 |
\ | 反斜杠符号 将符号变为普通符号 |
‘ | 单引号 |
“ | 双引号 |
\a | 响铃 |
\b | 退格(Backspace) |
\e | 转义 |
\000 | 空 |
\n | 换行 |
\v | 纵向制表符 |
\t | 横向制表符 和table类似 |
\r | 回车 回到当前行的行首 |
\f | 换页 |
\oyy | 八进制数,y 代表 0~7 的字符,例如:\012 代表换行。 |
\xyy | 十六进制数,以 \x 开头,yy代表的字符,例如:\x0a代表换行 |
\other | 其它的字符以普通格式输出 |
字符串运算符
操作符 | 描述 | 实例 |
---|---|---|
+ | 字符串连接 | >>>a + b ‘HelloPython’ |
* | 重复输出字符串 | >>>a * 2 ‘HelloHello’ |
[] | 通过索引获取字符串中字符 | >>>a[1] ‘e’ |
[ : ] | 截取字符串中的一部分 | >>>a[1:4] ‘ell’ |
in | 成员运算符 – 如果字符串中包含给定的字符返回 True | >>>”H” in a True |
not in | 成员运算符 – 如果字符串中不包含给定的字符返回 True | >>>”M” not in a True |
掌握操作
优先:1、索引取值
.find(“n”)和.index(“n”) n的索引位置
2、切片 s[1:6:3] 开始,结束,步长
3、长度len(s)
4、成员运算in、not in
5、切分. split(“ ”,1)空格切分,切分次数 返回值是一个列表
6、移除左右两边空白.strip() .strip(“*”)去除左右两边的
7、“-”.join(list)拼接 “a-b-c”
需要掌握:
1、.lstrip()只去左边
.rstrip()只去右边
2、.lower() .upper()
变小写,变大写
.swapcase()大小写反转
.title() — 各个字符的首字母大写
.capitalize() — 首字母大写
3、.startswitch() .endswitch()
以什么开头,以什么结尾
4、.format() res = “my name is {},my age is {}”.format(name,age)
res = “my name is {0},my age is {1}”.format(name,age)
res = “my name is {x},my age is {y}”.format(x = name,y = age)
res = f“my name is {x},my age is {y}” {}不能有\或者# , %%取消百分号
5、.rsplit()从右边开始切分
6、.replice(“ ”,“-”)-替换空格
7、.isdigit()判断字符串是否是纯数字组成
列表:
用[]创建,=的时候是把地址给另一个了,.copy()的时候是重新复制了一份
查:用下标索引访问值 list[0],和string类型相似
增:使用.append(“abfh”)添加数据
插:使用.insert(1,“ahf”)插入数据
删:del list[0] 指定元素删除:.remove([0,2])
根据索引删:.pop(2)(有返回值)
改:list[1] = 100
统计长度:len(list)
in、not in:多层列表时,就看外层
掌握操作:
全部删除:.clear()
统计元素出现次数:.count(22)
将列表元素取出添加:.extend(list)
索引位置:.index(22)
反转:.reverse()
排序:.sort() (列表中元素是同类型的)
元组:
不可变列表
定义方式:()
元组只有一个元素时,需要加,t =(1,)
掌握方法:
切片:同列表
字典类型:
不可hash的:可变的
可hash的:不可变的
定义方式:{“name”:“哈哈哈”,“age”:15}
key需要用不可变的
掌握方法:
造字典:
{}.fromkeys([“name”,”age”],111)—–>{“name”:1111,”age”:1111}
- # res = {}.fromkeys(['k1','k2','k3'],[])
# # print(res) # {'k1': [], 'k2': [], 'k3': []}
# res.get('k1').append(123)
# print(res)
#{'k1': [], 'k2': [], 'k3': []}
#{'k1': [123], 'k2': [], 'k3': []}
1、.get():通过key获取value
- res = d.get('username', '你搞什么飞机 这个键不存在 去你妹啊')
# print(res) # 键存在还是返回对应的值
# res = d.get('xxx', '你搞什么飞机 这个键不存在 去你妹啊')
# print(res) # 键不存在 返回get方法里面第二个参数
2、新增:
方法1:
- # d['hobby'] = 'study' # 字典的key不存在新增
# print(d)
# d['username'] = 'egon'
# print(d) # 字典的key存在则修改
方法2:
- # d.update(username='jason')
# print(d) # 特点同上
方法3:
键如果存在的情况下 那么不做修改 而是将对应的value取出 键如果不存在的情况下 那么就是新增
- # d.setdefault('xxx',123)
# print(d) # 键不存在是新增
# res = d.setdefault('username',123)
# print(d) # {'username': 'jason', 'password': 123,'xxx',123}
# print(res) # jason
字典方法三剑客
print(d.keys()) # 获取字典所有的key
print(d.values()) # 获取字典所有的value
print(d.items()) # 获取字典所有的key和value组织成小元组
序号 | 函数及描述 |
---|---|
1 | |
2 | |
3 | [dict.fromkeys(seq |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | [pop(key |
12 |
常用操作:
按照key值存取值:
d={”k1“:11}
d[“k2”]=222
len(d)有多少个字典元素
in和not in:判断的是key值
删除:和列表相同
函数 | 描述 |
---|---|
[int(x | 将x转换为一个整数 |
[long(x | 将x转换为一个长整数 |
将x转换到一个浮点数 | |
[complex(real | 创建一个复数 |
将对象 x 转换为字符串 | |
将对象 x 转换为表达式字符串 | |
用来计算在字符串中的有效Python表达式,并返回一个对象 | |
将序列 s 转换为一个元组 | |
将序列 s 转换为一个列表 | |
转换为可变集合 | |
创建一个字典。d 必须是一个序列 (key,value)元组。 | |
转换为不可变集合 | |
将一个整数转换为一个字符 | |
将一个整数转换为Unicode字符 | |
将一个字符转换为它的整数值 | |
将一个整数转换为一个十六进制字符串 | |
将一个整数转换为一个八进制字符串 |
集合set
1、作用:去重,集合内不能出现相同元素,集合内元素会自动去重
2、关系运算:
共同好友,共同关注
交叉并集
集合就是用上面两个功能,如果用不上,就不要用
定义:
s = {1,2,3,4}
1、集合内的元素必须是不可变元素
2、集合内的元素是无序的
3、定义空集合一定要用set关键字
4、能够被for循环的数据类型都能够被转成集合
- # s1 = set('egon is o DSB')
# print(s1)
# s2 = set([1,2,3,4,5,6,7,7,7,7,7])
# print(s2)
# s3 = set({'username':'jason','password':123})
# print(s3) # {'password', 'username'}
集合方法:
添加元素:.add()整个添加
.update([ ])把元素拆分添加
删除元素:.remove()
.pop()删除最后一个元素
关系运算
- # 用户1的好友列表
friends1 = {'jason','tank','tony','jerry'}
# 用户2的好友列表
friends2 = {'jason','tony','owen','oscar'}
# 1 求两个用户的共同好友 交集
# res = friends1 & friends2
# print(res) # {'jason', 'tony'}
# 2 求两个用户所有的好友
# res = friends1 | friends2
# print(res) # {'jerry', 'jason', 'oscar', 'tony', 'tank', 'owen'}
# 3 求用户1独有的好友
# res1 = friends1 - friends2
# res2 = friends2 - friends1
# print(res1,res2) # {'jerry', 'tank'} {'owen', 'oscar'}
# 4 求两个用户各自独有的好友 对称差集
# res = friends1 ^ friends2
# print(res) # {'owen', 'jerry', 'tank', 'oscar'}
# 5 子集 父集
s1 = {12,3,4,5,6}
s2 = {12,6}
print(s1 > s2) # s1是否是s2的父集
print(s2 < s1) # s2是否是s1的子集
编码、解码
万国字符———-》unicode————–》utf-8
中,英字符———-》unicode————–》gbk
屏幕 内存 磁盘
编码:unicode————–》utf-8
解码:utf-8————–》unicode(字符)
python语言中:编码 unicode——–》bytes
解码:bytes———-》unicode
文件操作:
rwa:r(只读),w(只写),a(追加写),+(增加功能):如r+,可读可写
tb:t(以字符串读),b(以bytes读)
.encode()编码,.decode()解码
- f = open(r"D:\PythonWorkspace\study\day01\text\a.txt",mode='rt',encoding='utf-8')
res = f.read()
print(res)
f.close()
相关方法:
读:
.readable()判断是否可读
.readline()读一行
.readlines()所有内容读出来放入一个列表
写:
.writable()判断是否可写
.writlines():相当于for line in f:
lines.write(line)
其他:
.name()取得是文件的路径
.flush()
1、r(默认):只读 文件不存在时,报错;文件存在时文件指针跳到文件开头
2、w:只写 文件不存在时,创建一个空文件;文件存在时文件指针跳到文件开头,写的东西将原文件覆盖
3、a:追加写 文件不存在时,创建一个空文件;文件存在时指针跳到文件末尾,追加写
w与a的异同:
相同:w与a写文件不关的情况下,连续写入,新内容永远跟在老内容之后,
不同:重新打开文件,w会清空老的内容,a模式继续添加
1、t(默认):读写都是字符串为单位,一定要指定encoding
2、b:读写都是字节为单位,一定不能指定encoding
上下文管理:
使用with,不用再关闭了
- with open() as f,open() as f1:
f.read()
f1.write()
控制文件指针移动:
f.seek(移动几个字节,模式)模式:0,参照文件开头开始移动(只有0模式,可以在t模式下使用)
只能在b模式下使用:1,参照指针当前所在位置
2,参照文件末尾的位置
中文:3个字节,英文字母:1个字节
文件修改的两种方式:
硬盘修改数据没有插入的,只能用新内容覆盖旧内容,内存可以修改
方式一:将硬盘内容全部读取到内存中,在内存中修改之后,覆盖到源文件中
- with open(r"D:\PythonWorkspace\study\day01\text\user.txt",mode='rt',encoding='utf-8') as f1:
data = f1.read()
res = data.replace("haha","Sb")
with open(r"D:\PythonWorkspace\study\day01\text\user.txt",mode="wt",encoding="utf-8") as f2:
f2.write(res)
方式二:
#1、循环读取源文件内容,一行行修改一行行写入一个新的临时文件 #2、删除源文件 #3、将临时文件重命名为源文件名
- # import os
# with open('a.html',mode='rt',encoding='utf-8') as f1,\
# open('.a.html.swp',mode='wt',encoding='utf-8') as f2:
# for line in f1: (一行一行的读)
# res=line.replace('SB','lxx')
# f2.write(res)
#
# os.remove('a.html')
# os.rename('.a.html.swp','a.html')
函数
和方法类似
内置函数:
isinstance(x,int)判断x是不是int类型
issubclass(Foo,object)判断Foo是不是子类
定义函数:
1、无参:
2、有参:
def 函数名(参数一,参数二,。。。。。):
代码块
return 返回值
3、空参:
代码块用pass占位
调用函数:
函数名(参数)
函数内调用函数
函数内可以有多个return,但是只要执行一次return函数就立刻结束,并把return后的值当作返回值
函数有三种返回值:
1、return 值:返回该值本身
2、return 值1,值2,值3:返回一个元组
3、没有return:返回一个None
函数的使用分两个阶段: 1、定义阶段:只检测语法,不执行代码
2、调用阶段:执行函数体代码
发生语法错误,定义阶段无法通过
发生逻辑错误,只能在调用阶段检测到
函数参数:
1、形参:定义函数时,括号内定义的变量名
默认形参def max(z=4):默认形参可传可不传,默认形参放在位置形参后面,默认形参值应该是不可变类型
2、实参:调用函数时,括号内传入的值
位置实参必须放在关键字实参(name=haha)的前面
可变长参数:
参数的个数不固定
1、在形参名前加:会把溢出的位置实参存成元组,然后赋值其后的形参名 通常写为:*args
2、在形参名前加:会把溢出的位置实参存成字典(需要用a=1类型),然后赋值其后的形参名 通常写为:**kwargs
实参中用:
1、在实参前加*:会把值打散,相当于for循环
2、在实参前加**:会把值打散成关键字实参
- def max(x,y):
print(x,y)
res = {"x":15,"y":14}
max(**res)
函数对象:
函数对象指的是函数可以被当成变量被使用,方法名存储的是方法的内存地址
- # 1 可以被赋值
# f = foo
# print(f is foo)
# f()
# 2 可以当作参数传给一个函数
# def bar(func):
# print(func)
# func()
#
# bar(foo)
# 3 可以当成一个函数的返回值
# def bar(func):
# return func
# res=bar(foo)
# print(res)
# 4 可以当成容器类型的元素
# l = [foo]
# print(l)
# l[0]()
使用范例:
- def login():
print('登录功能......')
def withdraw():
print('提现功能......')
def transfer():
print('转账功能......')
def recharge():
print('充值功能')
func_dic={
"1": [login,"登录"],
"2": [withdraw,"提现"],
"3": [transfer,"转账"],
"4": [recharge,"充值"]
}
# func_dic["1"][0]()
while True:
print("0 退出")
for k in func_dic:
print("%s %s" %(k,func_dic[k][1]))
choice = input("请输入你的指令编号: ").strip()
if choice == "0":
break
if choice in func_dic:
func_dic[choice][0]()
else:
print('输入的指令不存在')
函数嵌套:
1、函数里面调用函数
2、函数里面定义函数:f2只能在f1内调
- def f1():
def f2():
return
名称空间和作用域:
名称空间:存放名字的地方
1、内置名称空间:存放的是内置的名字(如print/input)
生命周期:解释器启动则产生,关闭则销毁
2、全局名称空间:存放的是顶级的名字(顶头写的)
生命周期:程序运行时则产生,程序结束则销毁
3、局部名称空间:函数内的名字
生命周期:调用函数时则产生,函数调用结束则销毁
3—->2——>1 和嵌套类似
从当前位置往外查找,不会往内查
函数名称空间需要在定义阶段找
全局范围\全局作用域:内置名称空间+全局名称空间
特点:全局存活、全局有效
局部范围\局部作用域:局部名称空间
特点:临时存活、局部有效
global和nonlocal:
global:声明为全局变量,可以在外面修改,修改之后才能输出,不能直接输出
nonlacal:找到临近外层的变量,在内层可以修改外层的变量
- x = 0
def outer():
x = 1
def inner():
nonlocal x
x = 2
print("inner:", x)
inner()
print("outer:", x)
outer()
print("global:", x)
结果:
inner: 2
outer: 2
global: 0
闭包函数:
定义在函数内的函数,并且需要访问一个来自外层函数的变量
装饰器:
定义一个装饰器函数为其他函数添加新功能
1、什么是装饰器 器:工具 装饰:为被装饰者添加额外的功能
2、为何要有装饰器 软件一旦上线运行之后,就应该遵循开放封闭原则: 1、开放指的是对拓展新功能开放 2、封闭指的是对修改源代码封闭
定义装饰器的目的: 定义装饰器就是为了在遵循1和2的前提下来为其他函数添加新功能的
ps: 不修改被装饰对象指的是定义与调用都不能修改 所以下述行为都违反了开放封闭原则: 1、修改被装饰对象定义时的源代码 2、修改被装饰对象的调用方式 3、如何用装饰器
- # import time
#
# def index(x,y):
# time.sleep(1)
# print('index===>',x,y)
#
#
# def outter(func):
# # func = index
# def wrapper(*args,**kwargs):
# start_time = time.time()
# res = func(*args,**kwargs)
# stop_time = time.time()
# print('run time is: %s' %(stop_time - start_time))
return res
# return wrapper
#
# index=outter(index)
#
# # index(1,2)
多装饰器:
2、叠加多个装饰器 2.1 加载顺序:自下而上 2.2 执行顺序:自上而下运行内层的wrapper函数
- # def deco1(func1): # func1 = wrapper2的内存地址
# def wrapper1(*args,**kwargs):
# print('wrapper1====>')
# res1=func1(*args,**kwargs)
# return res1
# return wrapper1
#
# def deco2(func2): # func2 = wrapper3的内存地址
# def wrapper2(*args,**kwargs):
# print('wrapper2====>')
# res2=func2(*args,**kwargs)
# return res2
# return wrapper2
#
# def deco3(func3): # func3 = 最原始的那个被装饰函数的内存地址
# def wrapper3(*args,**kwargs):
# print('wrapper3====>')
# res3=func3(*args,**kwargs)
# return res3
# return wrapper3
#
# # index=wrapper1的内存地址
# @deco1 # deco1(wrapper2的内存地址)=>wrapper1的内存地址
# @deco2 # deco2(wrapper3的内存地址)=>wrapper2的内存地址
# @deco3 # deco3(最原始的那个被装饰函数的内存地址)=>wrapper3的内存地址
# def index(x,y):
# print('index=>',x,y)
#
# index(1,2)
wrapper1====>
wrapper2====>
wrapper3====>
index=> 1 2
有参数装饰器:
- # 有参装饰器的模板:
def outter2(x,y,z,a,b):
def outter1(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
return outter1
def outter(engine = 'file'):
def deco2(func2):
def wrapper2(*args,**kwargs):
inp_name = input('username>>>: ').strip()
inp_pwd = input('password>>>: ').strip()
if engine == "file":
print('基于file的认证')
if inp_name == "egon" and inp_pwd == "123":
print('login successful')
res2=func2(*args,**kwargs)
return res2
else:
print('username or password error')
elif engine == 'mysql':
print('基于mysql的认证')
elif engine == 'ldap':
print('基于ldap的认证')
else:
print('未知的engine')
return wrapper2
return deco2
@outter(engine='mysql') # @deco2 # index=deco2(index)
def index(x,y):
print('index=>',x,y)
index(1,2) # index=>wrapper
迭代器:
内置有iter方法的类型有:
1、字典
2、集合
3、文件对象
4、字符串
5、列表
6、元组
- dic = {"name": "egon", 'age': 18, 'gender': "male"}
dic_iterator = dic.__iter__()
# res1 = dic_iterator.__next__()
迭代器对象:内置有next方法、内置有iter方法
可以直接使用for循环
自定义迭代器:
自定义迭代器实现惰性计算,达到节省内存的效果
函数内出现yield关键字,调用函数不会执行函数体代码,会得到一个返回值,该返回值就是我们自定义的迭代器,称之为生成器
- # def func():
# print("hello1")
# yield 111
# print("hello2")
# yield 222
# print("hello3")
# yield 333
#
# g = func()
# print(g) # 生成器本质就是迭代器
# res=next(g)
# print(res)
yield和return的异同
同:都能返回值
异:return只能返回一次值,函数就立刻结束
yield能返回多次值,yield可以挂起函数
- # 案例
# def func():
# res=0
# while True:
# res+=1
# yield res
#
# g=func()
#
# for i in g:
# print(i)
for循环:先将其变为迭代器对象
不断调用next方法
直到异常结束
面向过程:
核心是过程二字
优点:把复杂的问题流程化,进而简单化
缺点:扩展性差
生成式:
1、列表生成式:
- l = [i for i in range(5) 条件语句]
print(l)
[0,1,2,3,4]
第一个i可以是任何值
2、字典生成式:
- l = {‘k{i}’:i for i in range(5) 条件语句}
3、集合生成式:
- l = {i for i in range(5) 条件语句}
4、生成器生成式:
- # res=(i for i in range(5))
# # print(res,type(res))
# print(next(res))
# print(next(res))
# print(next(res))
# print(next(res))
# print(next(res))
# print(next(res))
内置函数:
- # print(abs(-1))取绝对值
# print(all([True,11,0]))全为真才是真
# print(all([]))真
# print(any([True,False,0]))有一个为真就是真
# print(any([]))假
# print(callable(len))判断变量是否可调用
# print(chr(90))数字转字符
# print(ord('Z'))字符转数字
# l=[1,2,3]
# print(dir(l))
# print(divmod(10,3))
(3,1)
res=eval('{"k1":111}\n')
print(res['k1'])
三元表达式:
表达式1 if 条件 else 表达式2
True:表达式1
Flase:表达式2
匿名函数:
即没有名字的函数,使用lambda
- lambda x,y:x+y
调用 :(lambda x,y:x+y)(1,2)
匿名函数只运行一次,运行完之后就回收
模块:
多个功能的集合,不是用来直接执行的,而是用来导入使用的
多个模块的集合叫包
三大类:
1、内置的模块
2、第三方模块
3、自定义模块
导入模块
导入模块时是从最高级的包下开始找的
- import 模块名
- from 模块名 import 模块中的函数
为导入模块起别名:
- import 模块名 as 别名
模块内加可以控制*的范围
__all__ = [函数1,函数2]
循环导入:
不建议循环导入,解决方法:将导入语句用函数包起来
- __name__方法
当文件被当作主程序直接执行时,值为”__mian__“
当文件被当作模块导入时,值为”模块名“
模块的搜索路径及查找优先级:
搜索路径:
1、先从内存导入的模块中找
2、查找内置的模块
3、最后去sys.path列表中存放的多个文件夹里依次检索
- 如果不在一个包中,需要
import 包.模块
或from 包 import 模块
包的使用:
首次导入包这种模块,发生两件事: 1、创建模块名称空间,运行包下的init.py的文件,将运行过程中产生的名字都丢入模块的名称空间中
2、在当前位置拿到一个名字aaa,该名字指向init.py的名称空间,即aaa.名字,名字是来自于init.py中的
相对导入:
. :代表当前文件的文件夹
序列化和反序列化:
序列化:内存中某一数据类型——————转化为——————>特殊的格式
反序列化:特殊的格式——————转化为——————>内存中某一数据类型
json模块和pickle模块:
优点:跨平台交互数据
缺点:无法识别所有的python类型
集合无法识别,元组可以识别
元组===转化为===》json格式的字符串
序列化:json.dumps()
- 方法一:
items=["圣剑","蝴蝶","BKB"]
dic_str=str(items)
with open('db.txt',mode='wt',encoding="utf-8") as f:
f.write(dic_str)
方法二:
items=["圣剑","蝴蝶","BKB"]
with open('db.txt',mode='wt',encoding="utf-8") as f:
json.dump(items,f)
反序列化:json.loads()
- 方式一:
with open('db.txt',mode='rt',encoding='utf-8') as f:
data=f.read() # "['圣剑', '蝴蝶', 'BKB']"
items=eval(data)
print(items[0])
方式二:
with open('db.txt',mode='rt',encoding='utf-8') as f:
dic = json.load(f)
2、为何要序列化 1、存档:把内存中的数据持久化到硬盘 2、跨平台交互数据
在python中: 存档=》推荐用pickle格式 跨平台交互=》推荐用json格式
三:pickle 优点:可以识别所有python类型 缺点:只能用于python中,无法跨平台交互
序列化出来的是bytes
- s = {1,2,3,4,5}
res=pickle.dumps(s)
# print(res,type(res))
with open('a.pkl',mode='wb') as f:
f.write(res)
with open('a.pkl',mode='rb') as f:
data=f.read()
s=pickle.loads(data)
print(type(s))
hashlib模块:
hash是一种算法,为该算法传入文本内容,传的时候需要用bytes,该算法会计算得到一个值
使用场景:密码安全
hash值具备以下三个特点: 1、传入文本内容一致,使用算法一致,得到的hash值也一样
2、hash值的长度取决于采用的算法,与传入的文本内容大小无关
3、hash值不可逆,只能由文本变为hash值,不能由hash值变为文本
- import hashlib
m=hashlib.md5() #hash工厂,可以直接传值
m.update("你好".encode('utf-8')) #传入数据
m.update("egon".encode('utf-8'))
m.update("哈哈哈".encode('utf-8')) # "你好egon哈哈哈"
res=m.hexdigest() #制造hash值
print(res)
time模块:
时间有三种格式:
1、时间戳:秒数
从1970年到现在
- time.time() 用于时间计算
2、格式化的字符串
- time.strftime("%Y-%m-%d %H:%M:%S %p") %p:上午,下午
time.strftime("%Y-%m-%d %X)
3、结构化的时间:
- res = time.localtime() 获取时间的某一部分
res.time_year
三种格式的转换:
- # 2.1 时间戳---》格式化的字符串
# struct_time=time.localtime(3333.3)
# res=time.strftime("%Y:%m",struct_time)
# print(res)
# 2.2 格式化的字符串---》时间戳
# struct_time=time.strptime("2017-07-03 11:11:11","%Y-%m-%d %H:%M:%S")
# res=time.mktime(struct_time)
# print(res)
# 三:
# print(time.ctime(3333.3))
# print(time.asctime(time.localtime(3333.3)))
# 四:
# time.sleep(3)
datetime模块:
- datetime.datetime.now()当前时间
datetime.date.fromtimestamp(time.time())时间戳转化为格式化字符串
datetime.datetime.fromtimestamp(time.time())
res=datetime.datetime.now() + datetime.timedelta(days=3)当前时间加三天
将时间的某一部分换掉
# res=datetime.datetime.now()
# print(res)
# new_res=res.replace(year=1999,month=9)
# print(new_res)
random模块:
- 1 import random
2
3 print(random.random())#(0,1)----float 大于0且小于1之间的小数
4
5 print(random.randint(1,3)) #[1,3] 大于等于1且小于等于3之间的整数
6
7 print(random.randrange(1,3)) #[1,3) 大于等于1且小于3之间的整数
8
9 print(random.choice([1,'23',[4,5]]))#1或者23或者[4,5]
10
11 print(random.sample([1,'23',[4,5]],2))#列表元素任意2个组合
12
13 print(random.uniform(1,3))#大于1小于3的小数,如1.927109612082716
14
15
16 item=[1,3,5,7,9]
17 random.shuffle(item) #打乱item的顺序,相当于"洗牌"
18 print(item)
随机验证码:
- def make_code(n=5):
res = ''
for i in range(n):
s1 = str(random.randint(0, 9))
s2 = chr(random.randint(65, 90))
res += random.choice([s1, s2])
return res
print(make_code(4))
os模块:
和操作系统将交互
- os模块是与操作系统交互的一个接口
View Code
复制代码
在Linux和Mac平台上,该函数会原样返回path,在windows平台上会将路径中所有字符转换为小写,并将所有斜杠转换为饭斜杠。
>>> os.path.normcase('c:/windows\\system32\\')
'c:\\windows\\system32\\'
规范化路径,如..和/
>>> os.path.normpath('c://windows\\System32\\../Temp/')
'c:\\windows\\Temp'
>>> a='/Users/jieli/test1/\\\a1/\\\\aa.py/../..'
>>> print(os.path.normpath(a))
/Users/jieli/test1
复制代码
复制代码
os路径处理
#方式一:推荐使用
import os
#具体应用
import os,sys
possible_topdir = os.path.normpath(os.path.join(
os.path.abspath(__file__),
os.pardir, #上一级
os.pardir,
os.pardir
))
sys.path.insert(0,possible_topdir)
#方式二:不推荐使用
os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys模块:
- 1 sys.argv 命令行参数List,第一个元素是程序本身路径
2 sys.exit(n) 退出程序,正常退出时exit(0)
3 sys.version 获取Python解释程序的版本信息
4 sys.maxint 最大的Int值
5 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值
6 sys.platform 返回操作系统平台名称
- src_file = sys.argv[1]
dst_file = sys.argv[2]
将输入的所有数据变为一个列表
打印进度条:
- print("\r[#### ]",end='') end不换行,\r:从头打印
- print("[%-15s]" % "###",) -左对齐,15:长度
- import time
def progress(percent):
if percent > 1:
percent=1
print("\r[%-50s] %d%%" % ("#"*int(50*percent),int(100 * percent)),end='')
total_size = 1025
recv_size = 0
while recv_size < total_size:
# 每次下载1024
time.sleep(0.3)
recv_size+=1024
percent = recv_size / total_size
progress(percent)
shutil模块:
- shutil.copyfileobj(fsrc, fdst[, length])
将文件内容拷贝到另一个文件中
1 import shutil
2
3 shutil.copyfileobj(open('old.xml','r'), open('new.xml', 'w'))
shutil.copyfile(src, dst)
拷贝文件
1 shutil.copyfile('f1.log', 'f2.log') #目标文件无需存在
shutil.copymode(src, dst)
仅拷贝权限。内容、组、用户均不变
1 shutil.copymode('f1.log', 'f2.log') #目标文件必须存在
shutil.copystat(src, dst)
仅拷贝状态的信息,包括:mode bits, atime, mtime, flags
1 shutil.copystat('f1.log', 'f2.log') #目标文件必须存在
shutil.copy(src, dst)
拷贝文件和权限
1 import shutil
2
3 shutil.copy('f1.log', 'f2.log')
shutil.copy2(src, dst)
拷贝文件和状态信息
1 import shutil
2
3 shutil.copy2('f1.log', 'f2.log')
shutil.ignore_patterns(*patterns)
shutil.copytree(src, dst, symlinks=False, ignore=None)
递归的去拷贝文件夹
1 import shutil
2
3 shutil.copytree('folder1', 'folder2', ignore=shutil.ignore_patterns('*.pyc', 'tmp*')) #目标目录不能存在,注意对folder2目录父级目录要有可写权限,ignore的意思是排除
拷贝软连接
shutil.rmtree(path[, ignore_errors[, onerror]])
递归的去删除文件
1 import shutil
2
3 shutil.rmtree('folder1')
shutil.move(src, dst)
递归的去移动文件,它类似mv命令,其实就是重命名。
1 import shutil
2
3 shutil.move('folder1', 'folder3')
shutil.make_archive(base_name, format,...)
创建压缩包并返回文件路径,例如:zip、tar
创建压缩包并返回文件路径,例如:zip、tar
base_name: 压缩包的文件名,也可以是压缩包的路径。只是文件名时,则保存至当前目录,否则保存至指定路径,
如 data_bak =>保存至当前路径
如:/tmp/data_bak =>保存至/tmp/
format: 压缩包种类,“zip”, “tar”, “bztar”,“gztar”
root_dir: 要压缩的文件夹路径(默认当前目录)
owner: 用户,默认当前用户
group: 组,默认当前组
logger: 用于记录日志,通常是logging.Logger对象
复制代码
1 #将 /data 下的文件打包放置当前程序目录
2 import shutil
3 ret = shutil.make_archive("data_bak", 'gztar', root_dir='/data')
4
5
6 #将 /data下的文件打包放置 /tmp/目录
7 import shutil
8 ret = shutil.make_archive("/tmp/data_bak", 'gztar', root_dir='/data')
复制代码
- shutil 对压缩包的处理是调用 ZipFile 和 TarFile 两个模块来进行的,详细:
复制代码
import zipfile
# 压缩
z = zipfile.ZipFile('laxi.zip', 'w')
z.write('a.log')
z.write('data.data')
z.close()
# 解压
z = zipfile.ZipFile('laxi.zip', 'r')
z.extractall(path='.')
z.close()
复制代码
复制代码
import tarfile
# 压缩
>>> t=tarfile.open('/tmp/egon.tar','w')
>>> t.add('/test1/a.py',arcname='a.bak')
>>> t.add('/test1/b.py',arcname='b.bak')
>>> t.close()
# 解压
>>> t=tarfile.open('/tmp/egon.tar','r')
>>> t.extractall('/egon')
>>> t.close()
shevle和xml模块:
- shelve模块比pickle模块简单,只有一个open函数,返回类似字典的对象,可读可写;key必须为字符串,而值可以是python所支持的数据类型
复制代码
import shelve
f=shelve.open(r'sheve.txt')
# f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}
# f['stu2_info']={'name':'gangdan','age':53}
# f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])
f.close()
- xml的格式如下,就是通过<>节点来区别数据结构的:
复制代码
<?xml version="1.0"?>
<data>
<country name="Liechtenstein">
<rank updated="yes">2</rank>
<year>2008</year>
<gdppc>141100</gdppc>
<neighbor name="Austria" direction="E"/>
<neighbor name="Switzerland" direction="W"/>
</country>
<country name="Singapore">
<rank updated="yes">5</rank>
<year>2011</year>
<gdppc>59900</gdppc>
<neighbor name="Malaysia" direction="N"/>
</country>
<country name="Panama">
<rank updated="yes">69</rank>
<year>2011</year>
<gdppc>13600</gdppc>
<neighbor name="Costa Rica" direction="W"/>
<neighbor name="Colombia" direction="E"/>
</country>
</data>
复制代码
xml协议在各个语言里的都 是支持的,在python中可以用以下模块操作xml:
# print(root.iter('year')) #全文搜索
# print(root.find('country')) #在root的子节点找,只找一个
# print(root.findall('country')) #在root的子节点找,找所有
View Code
复制代码
#在country内添加(append)节点year2
import xml.etree.ElementTree as ET
tree = ET.parse("a.xml")
root=tree.getroot()
for country in root.findall('country'):
for year in country.findall('year'):
if int(year.text) > 2000:
year2=ET.Element('year2')
year2.text='新年'
year2.attrib={'update':'yes'}
country.append(year2) #往country节点下添加子节点
tree.write('a.xml.swap')
复制代码
自己创建xml文档:
复制代码
import xml.etree.ElementTree as ET
new_xml = ET.Element("namelist")
name = ET.SubElement(new_xml,"name",attrib={"enrolled":"yes"})
age = ET.SubElement(name,"age",attrib={"checked":"no"})
sex = ET.SubElement(name,"sex")
sex.text = '33'
name2 = ET.SubElement(new_xml,"name",attrib={"enrolled":"no"})
age = ET.SubElement(name2,"age")
age.text = '19'
et = ET.ElementTree(new_xml) #生成文档对象
et.write("test.xml", encoding="utf-8",xml_declaration=True)
ET.dump(new_xml) #打印生成的格式
configerparser模块:
配置文件后缀:.ini
.cfg
.cnf
配置文件如下:
- # 注释1
; 注释2
[section1]
k1 = v1
k2:v2
user=egon
age=18
is_admin=true
salary=31
[section2]
k1 = v1
读取
- import configparser
config=configparser.ConfigParser()
config.read('a.cfg')
#查看所有的标题
res=config.sections() #['section1', 'section2']
print(res)
#查看标题section1下所有key=value的key
options=config.options('section1')
print(options) #['k1', 'k2', 'user', 'age', 'is_admin', 'salary']
#查看标题section1下所有key=value的(key,value)格式
item_list=config.items('section1')
print(item_list) #[('k1', 'v1'), ('k2', 'v2'), ('user', 'egon'), ('age', '18'), ('is_admin', 'true'), ('salary', '31')]
#查看标题section1下user的值=>字符串格式
val=config.get('section1','user')
print(val) #egon
#查看标题section1下age的值=>整数格式
val1=config.getint('section1','age')
print(val1) #18
#查看标题section1下is_admin的值=>布尔值格式
val2=config.getboolean('section1','is_admin')
print(val2) #True
#查看标题section1下salary的值=>浮点型格式
val3=config.getfloat('section1','salary')
print(val3) #31.0
改写
- import configparser
config=configparser.ConfigParser()
config.read('a.cfg',encoding='utf-8')
#删除整个标题section2
config.remove_section('section2')
#删除标题section1下的某个k1和k2
config.remove_option('section1','k1')
config.remove_option('section1','k2')
#判断是否存在某个标题
print(config.has_section('section1'))
#判断标题section1下是否有user
print(config.has_option('section1',''))
#添加一个标题
config.add_section('egon')
#在标题egon下添加name=egon,age=18的配置
config.set('egon','name','egon')
config.set('egon','age',18) #报错,必须是字符串
#最后将修改的内容写入文件,完成最终的修改
config.write(open('a.cfg','w'))
日志模块:
1、日志级别与配置
- 可在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
- import logging
# 一:日志配置
logging.basicConfig(
# 1、日志输出位置:1、终端 2、文件
# filename='access.log', # 不指定,默认打印到终端
# 2、日志格式
format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',
# 3、时间格式
datefmt='%Y-%m-%d %H:%M:%S %p',
# 4、日志级别
# critical => 50
# error => 40
# warning => 30
# info => 20
# debug => 10
level=30,
)
# 二:输出日志
logging.debug('调试debug')
logging.info('消息info')
logging.warning('警告warn')
logging.error('错误error')
logging.critical('严重critical')
'''
# 注意下面的root是默认的日志名字
WARNING:root:警告warn
ERROR:root:错误error
CRITICAL:root:严重critical
'''
access.log内容:
2017-07-28 20:32:17 PM - root - DEBUG -test: 调试debug
2017-07-28 20:32:17 PM - root - INFO -test: 消息info
2017-07-28 20:32:17 PM - root - WARNING -test: 警告warn
2017-07-28 20:32:17 PM - root - ERROR -test: 错误error
2017-07-28 20:32:17 PM - root - CRITICAL -test: 严重critical
2、日志配置字典
- """
logging配置
"""
import os
# 1、定义三种日志输出格式,日志中可能用到的格式化串如下
# %(name)s Logger的名字
# %(levelno)s 数字形式的日志级别
# %(levelname)s 文本形式的日志级别
# %(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
# %(filename)s 调用日志输出函数的模块的文件名
# %(module)s 调用日志输出函数的模块名
# %(funcName)s 调用日志输出函数的函数名
# %(lineno)d 调用日志输出函数的语句所在的代码行
# %(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
# %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
# %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
# %(thread)d 线程ID。可能没有
# %(threadName)s 线程名。可能没有
# %(process)d 进程ID。可能没有
# %(message)s用户输出的消息
# 2、强调:其中的%(name)s为getlogger时指定的名字
standard_format = '[%(asctime)s][%(threadName)s:%(thread)d][task_id:%(name)s][%(filename)s:%(lineno)d]' \
'[%(levelname)s][%(message)s]'
simple_format = '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'
test_format = '%(asctime)s] %(message)s'
# 3、日志配置字典
LOGGING_DIC = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
'standard': {
'format': standard_format
},
'simple': {
'format': simple_format
},
'test': {
'format': test_format
},
},
'filters': {},
'handlers': {
#打印到终端的日志
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler', # 打印到屏幕
'formatter': 'simple'
},
#打印到文件的日志,收集info及以上的日志
'default': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 保存到文件,日志轮转
'formatter': 'standard',
# 可以定制日志文件路径
# BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # log文件的目录
# LOG_PATH = os.path.join(BASE_DIR,'a1.log')
'filename': 'a1.log', # 日志文件
'maxBytes': 1024*1024*5, # 日志大小 5M
'backupCount': 5,
'encoding': 'utf-8', # 日志文件的编码,再也不用担心中文log乱码了
},
'other': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 保存到文件
'formatter': 'test',
'filename': 'a2.log',
'encoding': 'utf-8',
},
},
'loggers': {
#logging.getLogger(__name__)拿到的logger配置
'': {
'handlers': ['default', 'console'], # 这里把上面定义的两个handler都加上,即log数据既写入文件又打印到屏幕
'level': 'DEBUG', # loggers(第一层日志级别关限制)--->handlers(第二层日志级别关卡限制)
'propagate': False, # 默认为True,向上(更高level的logger)传递,通常设置为False即可,否则会一份日志向上层层传递
},
'专门的采集': {
'handlers': ['other',],
'level': 'DEBUG',
'propagate': False,
},
},
}
使用:
import settings
# !!!强调!!!
# 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
# from logging import config
# from logging import getLogger
# 2、也可以使用如下导入
import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.
# 3、加载配置
logging.config.dictConfig(settings.LOGGING_DIC)
# 4、输出日志
logger1=logging.getLogger('用户交易')
logger1.info('egon儿子alex转账3亿冥币')
# logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
# logger2.debug('专门采集的日志')
3、使用
- import settings
# !!!强调!!!
# 1、logging是一个包,需要使用其下的config、getLogger,可以如下导入
# from logging import config
# from logging import getLogger
# 2、也可以使用如下导入
import logging.config # 这样连同logging.getLogger都一起导入了,然后使用前缀logging.config.
# 3、加载配置
logging.config.dictConfig(settings.LOGGING_DIC)
# 4、输出日志
logger1=logging.getLogger('用户交易')
logger1.info('egon儿子alex转账3亿冥币')
# logger2=logging.getLogger('专门的采集') # 名字传入的必须是'专门的采集',与LOGGING_DIC中的配置唯一对应
# logger2.debug('专门采集的日志')
re模块:
正则表达式:
由一系列特殊字符拼接而成的表达式,该表达式用于从一个大字符串中匹配出符合规则的子字符串
*+是贪婪的
- print(re.findall("ab{2,5}","a ab abb abbb abbbb abbbbbbbb abbbbbbbbbbbb bbbbbbbbb"))
['abb', 'abbb', 'abbbb', 'abbbbb', 'abbbbb']
9.7 .*: 匹配所有
- # print(re.findall("a.*b","123 a1231-==-000b123123123123123b"))
# a1231-==-000b123123123123123b 贪婪的
print(re.findall("a.*?b","123 a1231-==-000b123123123123123b"))
a1231-==-000b
- 10 ():分组
# print(re.findall('ab+','ababab123')) #['ab', 'ab', 'ab']
# print(re.findall('(ab)+123','ababab123')) #['ab'],匹配到末尾的ab123中的ab
# ababab123
# (ab)(ab)(ab)(ab)
10.1 取消分组?:
# print(re.findall('(?:ab)+123','ababab123'))
-
\
- # print(re.findall('a\\\\c','a\c a1c aac')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
# print(re.findall(r'a\\c','a\c a1c aac')) #对于正则来说a\\c确实可以匹配到a\c,但是在python解释器读取a\\c时,会发生转义,然后交给re去执行,所以抛出异常
- msg = '<a href="https://pan.baidu.com/s/1skWyTT7" target="_blank"><strong><span style="color: #ff0000;">原理图:https://pan.baidu.com/s/1skWyTT7</span></strong></a><a href="https://www.baidu/com">"点我啊"</a>'
url_pattern = re.compile('href="(.*?)"')
res=url_pattern.findall(msg)
print(res)
- # ===========================re模块提供的方法介绍===========================
import re
#1
print(re.findall('e','alex make love') ) #['e', 'e', 'e'],返回所有满足匹配条件的结果,放在列表里
#2
print(re.search('e','alex make love').group()) #e,只到找到第一个匹配然后返回一个包含匹配信息的对象,该对象可以通过调用group()方法得到匹配的字符串,如果字符串没有匹配,则返回None。
#3
print(re.match('e','alex make love')) #None,同search,不过在字符串开始处进行匹配,完全可以用search+^代替match
#4
print(re.split('[ab]','abcd')) #['', '', 'cd'],先按'a'分割得到''和'bcd',再对''和'bcd'分别按'b'分割
#5
print('===>',re.sub('a','A','alex make love')) #===> Alex mAke love,不指定n,默认替换所有
print('===>',re.sub('a','A','alex make love',1)) #===> Alex make love
print('===>',re.sub('a','A','alex make love',2)) #===> Alex mAke love
print('===>',re.sub('^(\w+)(.*?\s)(\w+)(.*?\s)(\w+)(.*?)$',r'\5\2\3\4\1','alex make love')) #===> love make alex
print('===>',re.subn('a','A','alex make love')) #===> ('Alex mAke love', 2),结果带有总共替换的个数
#6
obj=re.compile('\d{2}')
print(obj.search('abc123eeee').group()) #12
print(obj.findall('abc123eeee')) #['12'],重用了obj
?!:没有匹配到
- ?!pattern,表示在没有配到pattern的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
- ?=pattern,表示在配到pattern的字符串的前提下,再进行后续的正则表达式匹配,后续匹配仍然从被匹配字符串的头开始
面向对象编程:
class 类名:(类名推荐用驼峰体)
创建对象:类名()
在类中加入:
- def __init__(obj,x,y,z):
pass
不能有返回值
- # 调用类:
# 1、创建一个空对象与类相关
# 2、把空对象、"冯疯子", 18, "female"一起传给__init__方法,完成对象的初始化
# 3、赋值符号把初始化好的对象的内存地址绑定变量名stu_obj1
stu_obj1 = Student("冯疯子", 18, "female")
封装:
封装对外不对内
- 属性和方法名前加__
使用时:_类名__属性名 #强烈不建议
property装饰器:
将功能伪造为属性
- # class People:
# def __init__(self, name, height, weight):
# self.name = name
# self.height = height
# self.weight = weight
#
# @property
# def bmi(self):
# return self.weight / (self.height ** 2)
#
#
# p = People('egon', 1.81, 70)
# p.height = 1.84
# print(p.bmi)
- # class Student:
# __school = "oldboy" # _Student__school = "oldboy"
#
# def __init__(obj, x, y, z):
# obj.__name = x
# obj.__age = y
# obj.gender = z
#
# def get_name(self):
# print("访问控制")
# return self.__name
#
# def set_name(self,x):
# print("赋值控制")
# self.__name = x
#
# def del_name(self):
# print("删除控制")
# del self.__name
#
# def get_age(self):
# return self.__age
#
# def set_age(self, x):
# if type(x) is not int:
# print("年龄必须是整型,傻叉")
# return
# self.__age = x
#
# def del_age(self):
# print("不让删")
#
#
# age = property(get_age, set_age, del_age)
# name = property(get_name, set_name, del_name)
#
#
# stu_obj1 = Student("冯疯子", 18, "female")
#
# # print(stu_obj1.age)
# # stu_obj1.age = "19"
# # del stu_obj1.age
# # print(stu_obj1.age)
- class Student:
__school = "oldboy" # _Student__school = "oldboy"
def __init__(obj, x, y, z):
obj.__name = x
obj.__age = y
obj.gender = z
@property
def name(self):
print("访问控制")
return self.__name
@name.setter
def name(self, x):
print("赋值控制")
self.__name = x
@name.deleter
def name(self):
print("删除控制")
del self.__name
stu_obj1 = Student("冯疯子", 18, "female")
stu_obj1.name
classmethod:
将函数绑定给了类,由类来调用,把类当作第一个参数传入
- @classmethod
def 方法名(cls):
pass
staticmethod:
函数既不和类绑定也不和对象绑定,就是一个普通的函数,谁都可以调用,没有自动传参效果
继承:
class sub(父类名): python支持多继承
方式一:指名道姓地调用某一个类的函数
特点:不依赖于继承关系
- #
class OldboyPeople:
school = "oldboy"
# 空对象,"艾利克斯",73,'male'
def __init__(self,name,age,gender):
self.name = name
self.age = age
self.gender = gender
def f1(self):
print('1111111')
class Student(OldboyPeople):
# 空对象,"艾利克斯",73,'male',1001,"python全栈开放"
def __init__(self,name,age,gender,stu_id,course):
OldboyPeople.__init__(self,name,age,gender) # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
self.stu_id = stu_id
self.course = course
def choose(self):
print('%s 正在选
课' %self.name)
def f1(self):
OldboyPeople.f1(self)
print("22222")
方式二、super(自己的类名,self)python3可以省略
调用super(自己的类名,self)会返回一个特殊的对象,super(自己的类名,self).属性,会参照属性查找发起的那个类的mro列表去它父类中查找属性
- # class OldboyPeople:
# school = "oldboy"
# # 空对象,"艾利克斯",73,'male'
# def __init__(self,name,age,gender):
# self.name = name
# self.age = age
# self.gender = gender
#
# def f1(self):
# print('1111111')
#
# class Student(OldboyPeople):
# def __init__(self,name,age,gender,stu_id,course):
# # OldboyPeople.__init__(self,name,age,gender) # OldboyPeople.__init__(空对象,"艾利克斯",73,'male')
# super(Student,self).__init__(name,age,gender)
# self.stu_id = stu_id
# self.course = course
#
#
# def choose(self):
# print('%s 正在选课' %self.name)
#
# def f1(self):
# # OldboyPeople.f1(self)
# # super().f1()
- 父类如果不想让子类覆盖自己的方法,可以在方法名前加前缀__
class Foo:
def __f2(self): # _Foo__f2
print("Foo.f2")
def f1(self):
print('Foo.f1')
self.__f2() # obj._Foo__f2()
class Bar(Foo):
def __f2(self): # _Bar__f2
print("Bar.f2")
新式类:但凡是继承了object类的子类,以该子类子子孙孙类都称之为新式类 经典类:没有继承了object类的子类,以该子类子子孙孙类都称之为经典类
python3中全都是新式类,python2中才有经典类: 在python3中没有继承任何类的类会默认继承object类
菱形继承:
python2:深度优先,一条道走到黑,然后再找其他
python3:广度优先,先找所有的父类
非菱形继承:
深度优先
mixins机制:
day26
- 类通常以Mixin,able,ible为后缀
通常Mixin结果的类放在左边
首先它必须表示某一种功能,而不是某个物品,python 对于mixin类的命名方式一般以 Mixin, able, ible 为后缀
其次它必须责任单一,如果有多个功能,那就写多个Mixin类,一个类可以继承多个Mixin,为了保证遵循继承的“is-a”原则,只能继承一个标识其归属含义的父类
然后,它不依赖于子类的实现
最后,子类即便没有继承这个Mixin类,也照样可以工作,就是缺少了某个功能。(比如飞机照样可以载客,就是不能飞了)
组合:
反应的是has a的关系
组合:把另外一个类的对象赋值给当前对象的属性
组合表达的是有的关系
- class Teacher:
def __init__(self, name, age, gender, level):
self.name = name
self.age = age
self.gender = gender
self.level = level
def tell(self):
print("%s:%s" % (self.name, self.age))
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
class Course:
def __init__(self, name, price, period):
self.name = name
self.price = price
self.period = period
def tell(self):
print('<%s:%s:%s>' % (self.name, self.price, self.period))
tea1 = Teacher("egon", 18, "male", 10)
stu1 = Student("xxx", 19, "male")
python = Course("python开放", 30000, "3mons")
linux = Course("linux课程", 30000, "3mons")
tea1.courses = [python,linux]
stu1.course = python
# tea,stu # 超级对象
# stu1.course.tell()
for course_obj in tea1.courses:
course_obj.tell()
多态:
推荐鸭子类型,不使用继承
- 和Java抽象类的概念相似
# import abc
#
# class Animal(metaclass=abc.ABCMeta):
# @abc.abstractmethod
# def speak(self):
# pass
#
# @abc.abstractmethod
# def run(self):
# pass
#
# # Animal() # Animal的作用是用来制定标准的
#
# class People(Animal):
# def speak(self):
# print("啊啊啊啊")
#
# def run(self):
# print("咻咻咻...")
#
# class Dog(Animal):
# def giao(self):
# print("汪汪汪")
#
# class Pig(Animal):
# def heheng(self):
# print("哼哼哼")
# peo1=People()
# d1=Dog()
# p1=Pig()
# peo1.jiao()
# d1.giao()
# p1.heheng()
元类:
- 类():先调用__new__方法,创建一个空对象
再调用__init__方法,将属性方法放入空对象中,完成初始化
对象 = 类()
对象():调用__call__方法,运行
exec(cmd, {}, class_dic) #类名,类的基类,类的名称空间 执行这个函数生成类
单例模式:
- # 实现方式1:classmethod
"""
import settings
class MySQL:
__instance = None
def __init__(self, ip, port):
self.ip = ip
self.port = port
@classmethod
def singleton(cls):
if cls.__instance:
return cls.__instance
cls.__instance = cls(settings.IP, settings.PORT)
return cls.__instance
# obj1=MySQL("1.1.1.1",3306)
# obj2=MySQL("1.1.1.2",3306)
# print(obj1)
# print(obj2)
obj3 = MySQL.singleton()
print(obj3)
obj4 = MySQL.singleton()
print(obj4)
"""
# 方式2:元类
"""
import settings
class Mymeta(type):
__instance = None
def __init__(self,class_name,class_bases,class_dic):
self.__instance=object.__new__(self) # Mysql类的对象
self.__init__(self.__instance,settings.IP,settings.PORT)
def __call__(self, *args, **kwargs):
if args or kwargs:
obj = object.__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
else:
return self.__instance
# MySQL=Mymeta(...)
class MySQL(metaclass=Mymeta):
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)
"""
# 方式3:装饰器
"""
import settings
def outter(func): # func = MySQl类的内存地址
_instance = func(settings.IP,settings.PORT)
def wrapper(*args,**kwargs):
if args or kwargs:
res=func(*args,**kwargs)
return res
else:
return _instance
return wrapper
@outter # MySQL=outter(MySQl类的内存地址) # MySQL=》wrapper
class MySQL:
def __init__(self, ip, port):
self.ip = ip
self.port = port
# obj1 = MySQL("1.1.1.1", 3306)
# obj2 = MySQL("1.1.1.2", 3306)
# print(obj1)
# print(obj2)
obj3 = MySQL()
obj4 = MySQL()
print(obj3 is obj4)
"""
猴子补丁:
把程序的某一部分功能换成另外的功能
- class A:
def speak(self):
return "hello"
def speak_patch(self):
return "world"
A.speak = speak_patch # <1>
some_class = A()
print('some_class.speak():', some_class.speak()) # <2>
some_class.speak(): world
内置方法:
内置方法都是在满足某种条件下自动触发的
- __str__:控制对象打印行为
重点:要用return 返回
# class People:
# def __init__(self, name, age):
# self.name = name
# self.age = age
#
# def __str__(self):
# # print('===>')
# return "<%s:%s>" %(self.name,self.age)
#
# obj = People("egon", 18)
#
# print(obj) # print(obj.__str__())
<egon:18>
__del__:删除对象时触发
反射:
dir(对象)以列表形式显示所有属性、方法
hasattr(对象,“属性”)判断对象是否有属性
getattr(对象,“属性”)显示属性值
getattr(对象,“属性”,None)显示属性值,没有的话不要报错,返回None
setattr(对象,属性,值)有的话改属性,没有添加
delattr(对象,属性)删除属性
- # class Person():
# def __setattr__(self, key, value): # 对象.赋值会触发 a.name='lqz' name给key,lqz给value
# print('set')
#
# def __getattr__(self, item):# 对象.取值会触发 a.name name给item,return 1
# print('get')
# return 1
#
# def __delattr__(self, item):# del 对象.属性 会触发
# print('delete')
#
#
# p = Person()
# p.name
# print(p.name)
- # 1 __ setattr__的使用
# 2 递归现象的出现
-通过反射赋值 setattr(obj,key,value)
-self.key=value
# 3 避免递归
-self.__dict__[key] = value
-object.__setattr__(self,key,value)
# 4 object.__setattr__(f,'_Foo__size',178)的使用
# 5 __getattr__
-对象.属性 取值属性不存在就会触发它的执行
# 6 应用场景(字典只支持中括号取值和赋值,让它支持 . 取值和赋值)
- 3 `__setitem__`和`__getitem__`
```python
# 对象[]取值赋值会触发它的指向
# 不继承字典,还支持[]赋值取值
class Foo:
def __setitem__(self, key, value):
setattr(self, key, value)
# object.__setattr__(self,key,value)
def __getitem__(self, item):
return getattr(self, item)
f = Foo()
f.name = 'lqz'
print(f.name)
print(f['name'])
f['age'] = 19
print(f.age)
print(f['age'])
- __dict__:
a.age = 10
print(a.__dict__) # {'num': 10, 'age': 10}
当一个类设置了__slots__属性后,这个类的__dict__属性就不存在了:
class A:
__slots__ = ['name', 'age']
a1 = A()
# print(a1.__dict__) # AttributeError: 'A' object has no attribute '__dict__'
a1.name = '张三'
a1.age = 24
# a1.hobby = '泡妞' # AttributeError: 'A' object has no attribute 'hobby'
print(a1.__slots__)
- __item__:
class Foo:
def __init__(self, name):
self.name = name
def __getitem__(self, item):
print(self.__dict__[item])
def __setitem__(self, key, value):
print('obj[key]=lqz赋值时,执行我')
self.__dict__[key] = value
def __delitem__(self, key):
print('del obj[key]时,执行我')
self.__dict__.pop(key)
def __delattr__(self, item):
print('del obj.key时,执行我')
self.__dict__.pop(item)
f1 = Foo('sb')
print(f1.__dict__)
f1['age'] = 18
f1.hobby = '泡妞'
del f1.hobby
del f1['age']
f1['name'] = 'lqz'
print(f1.__dict__)
- __call__ 方法的执行是由对象后加括号触发的
__doc__ 注释信息
https://www.cnblogs.com/liuqingzheng/articles/9949568.html
- __eq__
拥有__eq__方法的对象支持相等的比较操作
复制代码
class A:
def __init__(self,x,y):
self.x = x
self.y = y
def __eq__(self,obj):
# 打印出比较的第二个对象的x值
print(obj.x)
if self.x +self.y == obj.x+obj.y:
return True
else:
return False
a = A(1,2)
b = A(2,1)
print(a == b)
异常处理:
1、语法错误,在运行前需要改正
2、逻辑异常,
变量没有定义NameError
索引异常:IndexError
键不存在:KeyError
属性不存在:AttributeError
- try:
代码块
except 异常类型:
发生异常后要执行的代码
except 异常类型:
发生异常后要执行的代码
finally:
一定会执行
异常类型可以用Exception万能异常
- raise NameError(“变量名未定义”)
自定义异常
- # class Interface(BaseException):
# def __init__(self, msg, x, y, z):
# self.msg = msg
# self.x = x
# self.y = y
# self.z = z
#
# def __str__(self):
# return "<%s:%s:%s:%s>" % (self.msg,self.x,self.y,self.z)
#
#
# raise Interface("接口异常", 11, 22, 33)
- 断言:判断上一部分是否正确,正确后续执行,错误不执行
print("====1")
print("====2")
print("====3")
salaries=[1.1,2.2]
# if len(salaries) != 3:
# raise NameError
assert len(salaries) == 3
print(salaries[2])
print(salaries[2])
print(salaries[2])
python回收机制:
核心是引用计数:一个变量的引用计数为0时,才会被当作垃圾回收
问题1:循环引用——–》导致内存泄漏
标记—清除: 标记:栈区相当于根,从根出发可以访问的(直接或者间接都可以),标记起来
清除:遍历堆中所有对象,没有标记的对象会被清除
问题2:效率问题:每次从头开始扫描,效率慢
分代回收