2020年6月10号晚 阴 微风
今晚出去庆祝同事进公司一周年 回来后发现自己也即将写了三年PHP了~~也感觉自己好久没有学习了
所以从今晚开始 学习学习Python 主要也是想通过Python也将自己 丢掉已久的数学给捡回来
为什么是Python而不是Java、Go或者C#之类的呢 因为我始终感觉自己对Java喜爱不起来 从我大学开始学编程便是如此 所以不想再因为兴趣问题半途而废 Go的话其实还是蛮有兴趣 等我学完Python还有精力学习的话应该会考虑学习学习Go(毕竟下载的B站后台源码除了一句 fuck chanpin 其他的还没看懂哈哈哈哈)
好了 废话不多说 下面就开撸吧~~~
#这是一行注释 (学一门编程语言 从学习怎么写注释开始~~~~)
'''
这是一段注释
'''
# python 数据类型
# 整数
# 浮点数
# 字符串
# 布尔值
# 空值 None None不能理解为0,因为0是有意义的,None是没意义的
# 除以上还有列表字典等多种数据类型 还允许自定义数据类型
# 占位符
# %d 表示整数占位符
# %f 表示浮点数占位符
# %s 表示字符串占位符
# %x 表示十六进制整数占位符
# 如果不确定应该用什么,用%s就可以了,因为它会将任何数据类型转成字符串类型
str = '整数占位符 %d ,字符串占位符 %s, 浮点数占位符 %f' %(1000,'字符串',3.25)
print(str)
# 定义变量 (与php相同,只是不用写$符哈哈哈)
a = 10
b = 3.25
c = '哈哈哈哈'
# 数据类型 list list是一种有序的集合 可以随时添加或删除其中的元素 list元素的类型可以不一样 然后list元素也可以是一个list(与php数组相同)
classmates = ['小红','小明','小白']
# 获取list的长度可以用len()函数 len(classmates) 获取字符串的长度也可以用len()函数
listLength = len(classmates)
# 可以通过索引来获取list内的元素(与php相同) 但超出索引范围会报错 最后一个元素的索引是 len(classmates)-1 list长度减一
# 要获取最后一个元素还可以通过-1做索引 list[-1]就获取到最后一个元素,以此类推-2,-3分别获取倒数第二、倒数第三个元素 同样越界之后会报错
stuOne = classmates[0] #第一个学生
stuTwo = classmates[1] #第二个学生
lastStu = classmates[len(classmates)-1] #最后一个学生
# 往list后面添加元素 list.append('小花')
classmates.append('小花')
# 把元素插到指定位置 list.insert(0,'小彭')
classmates.insert(0,'小彭') #这样小彭就变成了班里001号同学
# 删除list末尾的元素 list.pop()
classmates.pop() #将小花从班里名单里移除(调到其他班去了)
# 删除指定位置的元素 list.pop(i) i是索引
classmates.pop(1) #将小红从班里名单移除(辍学了)
# 数据类型tuple tuple是有序列表元组 tuple与list很像 但是tuple一旦初始化就不能再改了 因此没有append() insert()这些方法
# 不可变的tuple有什么意义? 因为tuple不可变 所以代码更安全 能用tuple代替list就尽量使用tuple
otherClassmates = ('小黄','小饭','大华')
# tuple的坑 当你的tuple只有一个元素时
tupleA = (1) #此时定义的不是tuple 而是数字1 因为()即可以表示tuple 又可以表示数学公式中的小括号 为了避免这种问题 只有一个元素的tuple定义时必须加一个逗号来消除歧义
tupleB = (2,) #这样定义的才是tuple
#定义一个可变tuple
canChangeTuple = ('小红','小白',['小黄','小花'])
canChangeTuple[2][0] = '小彭'
'''
此时这个的tuple的元素就变成了 ('小红','小白',['小彭','小花']) 表面上看起来tuple的元素的确变了
但这里要理解tuple的不变到底是什么含义 tuple所谓的“不变” 指的是 指向不变 即指向 '小红' 就不能改为指向 '小黑', 指向一个list 就不能改为指向其他对象
但指向的这个list本身是可变的
所以要创建一个不变的tuple要怎么做? 那就要保证tuple 的每一个元素都不可变
'''
# list和tuple是Python内置的有序集合,一个可变,一个不可变。根据需要来选择使用它们。
'''
2020-6-11 00:33 今晚就先学到这里吧~~~ 加油
'''
# --------------------------- 时间分割线 -------------------------------------
# 条件判断 if: elif: else:
age = 20
if age >=18:
print('成年人') #这里一定要缩进 不然程序执行的时候会报错
elif age >= 60 :
print('退休了')
else :
print('未成年')
# 再看input()函数
# 直接用input返回的值作为数字去判断会报错 因为input函数返回的是字符串 应该要用int()转一下
# 但是int函数如果你的参数是类似于abc这种字符串 int函数又会报错
age = int(input())
if age >= 10:
print('够10岁了')
else :
print('不够10岁')
# 循环 有2中循环 一种是 for x in ... 一种是while循环
# for x in ...循环 依次把list或tuple中的每一个元素迭代出来 如:
names = ['小红','小彭','小花']
for name in names: #别忘记冒号
print(name)
# 计算1到100的和 range()函数可以生成一个整数序列 再通过list()函数将这个序列转成list
numbers = list(range(101))
sum = 0
for number in numbers:
sum += number
print(sum)
# while 循环 以及 break continue都与php相同 这里不再累赘
# 数据类型 dict(字典) 在其他语言中叫map 一种键值对的结构 也就是php的键值对数组
scores = [
'小红':98,
'小彭':100,
'小花':60
]
print(scores['小彭']) # 输出100 如果key不存在 就会报错
#要避免key不存在报错 有2种方法
# 通过 in 判断
if '小彭' in scores:
print('成绩有效')
else :
print('查无此人')
#用get() 如果key不存在可以返回None 或自己定义的value
score = scores.get('小白',60)#找不到小白的成绩就返回60分
'''
和list相比dict有以下几个特点:
1、查找和插入的速度极快 不会随着key的增加而变慢
2、需要占用大量的内存 内存浪费多
而list与dict相反
1、查找与插入的速度会随着元素的增多而变慢
2、占用空间小 浪费内存很少
所以dict是用空间来换时间的一种方法
'''
# 数据类型set set与dict类型 也是一组key的集合 但set不存储value 在set中 不存在重复的key
# 创建一个set 需要提供一个list作为输入集合
setA = set([1,2,3])
print(setA) # 输出{1,2,3} set是无序的 所以输出123并不表示它内部元素的顺序就是123
# 重复的元素在set中会被自动过滤掉
setB = set([1,1,2,3])
print(setB) # 输出{2,3,1}
# 通过add(key)的方式可以添加元素到set中
setB.add(5)
#可以通过remove(key)的方式删除元素
setB.remove(5)
# set可以看做数学上的无序以及无重复元素的集合 所以它有一些集合的特性 可以求交集与并集
print(setA&setB)
print(setA | setB)
# 函数
# 内置函数 如:abs() print()等等 可以通过help(abs)查看abs函数的帮助信息
# 可以访问http://docs.python.org/3/library/functions.html#abs 查看Python内置函数
# 自定义函数 使用def语句 依次写出函数名 括号中的参数以及冒号:
def my_add(a,b):
return a + b
print(my_add(10,20))
# 函数结果通过return返回 如果没有return 函数执行完毕也会返回结果 返回结果为None return None 可以简写为return
# 如果想定义一个空函数 或者函数的内部逻辑你还没确定
def nop():
pass
# 调用函数时 如果参数个数不对 Python解释器可以帮我们检查出来 并抛出typeError 但是如果参数的类型不对 解释器就不能帮我们检查出来了
# 数据类型检查我们可以通过 isinstance()实现
a = 10
if not isinstance(a,(int,float)):
print('参数错误')
# 返回多个值 (在php中函数要返回多个值一般是将多个返回值放到一个数组中一起返回 )
# 输入x和y坐标 返回真实坐标函数
def new_local(x,y):
newX = x+10
newY = y+5
return newX,newY
newX,newY = new_local(5,50) #这样我们就同时获取到2个函数返回值
# 但其实这是一种假象 python函数返回的仍然是单一值 可以通过一个变量去接收返回值看出
newLocal = new_local(5,10)
print(newLocal) # 输出(15,10) 原来多个返回值时是将所有的返回值放到一个tuple中 多个变量同时接收一个tuple时 按位置赋值
# 函数的参数 pyton函数定义非常简单 但灵活度却很高 除了正常定义的参数外 还可以使用默认参数、可变参数和关键字参数
#必选参数以及默认参数比较简单 这里不再展开叙述 但必选参数在前 默认参数在后 不然python会报错 而且默认参数必须指向一个不变的对象
#可变参数 在php中要实现可变参数一般是将参数都扔到数组里面 在python中也可以将参数都传到list或tuple中
def cala(numbers):
sum = 0
for number in numbers:
sum = sum + number
return sum
sum = cala([1,2,3]) #像这样 要先构建一个list
# 但是如果在numbers参数见前面加个* 就不需要提前构建list了
def calas(*numbers):
sum = 0
for number in numbers:
sum = sum + number
return sum
sum = cala(1,2,3) #像这样 在函数内部 参数numbers接收到的是一个tuple
# 如果已经有一个list或tuple了
numbersNew = [1,2,3]
calas(*numbersNew) # 就可以这样去调用函数
# 关键字参数
# 可变参数允许你传入0个或任意个参数 这些可变参数在函数 调用时会组成一个tuple 而关键字参数允许你传入0个或任意个含参数名的参数 这些关键字参数在函数内部会组成一个dict
def person(name, age ,**kw):
print('name:',name,'age:',age,'other:',kw)
# 函数person除了可以接收必选参数name与age之外还可以接收关键字参数kw,在调用函数 可以只传入必传参数
person('小彭',18)
# 也可以传入一些关键字参数
person('小彭',18,city='东莞')
person('小彭',18,city='东莞',job = '文案')
# 和可变参数一样 如果已经有了一个dict
personDict = {
'city':'东莞',
'job':'文案'
}
person('小彭',18,**personDict)
# **personDict表示把personDict这个dict的所以key-value用关键字参数传入到函数的**kw参数,kw将获得一份dict,但这是personDict的拷贝,修改kw并不会影响到原来的personDict
# 命名关键字参数
# 对于关键字参数 调用者可以随便传 至于传了什么 要在函数内部用in去判断 命名关键字参数 直接限制了只接收指定的关键字参数
def personA(name, age, *, city, job): #这样就表示关键字参数只接收city与job
print(name, age, city, job)
# 如果函数定义中已经有一个可变参数 那后面的命名关键字参数就不用加*了
def personB(name, age, *arges, city, job):
print(name, age, args, city, job)
# 命名关键字参数必须传入参数名,这和位置参数不同。如果没有传入参数名,调用将报错
'''
小结:
1、*args 是可变参数 arges接收的是一个tuple
2、可变参数既可以直接传入fun(1,2,3) 也可以先定义一个tuple或list再fun(*tuple)调用
3、**kw 是关键字参数 kw接收的是一个dict
3、关键字参数既可以直接传入fun(a=1,b=2) 也可以先定义一个dict再fun(**dict)调用
'''
'''
2020-6-11 23:23 今晚任务结束~~~~~
'''
# --------------------------- 时间分割线 -------------------------------------
# 切片(slice) 可以用来截取list、tuple以及字符串等 作用可以相当于php的array_slice、sub_str等函数
aList = ['小红','小明','小黄','小花'] # 定义一个list 用切片获取除第一个同学外的同学名单
bList = aList[1:3] # 切片操作符 : 前面参数指的是开始截取的元素索引(不输入的话默认0) 后面参数指的是截取长度(不输入的话默认到最后)其实就是mysql的start与limit 但是切片可以从后面往前面截取 最后一个元素的索引是-1 记住这些就可以了
# 迭代(作用类似于php数组的foreach) 在Python中 迭代是通过for in来完成的 Python中for循环的抽象程度比较高 因为Python的for循环不仅仅用在list或者tuple上 还可以用在其他的可迭代对象上
aDict = {'a':1,'b':2,'c':3} #定义一个dict
#输出key
for key in aDict:
print(key) #输出'a','b','c'
#输出value
for value in aDict.values():
print(value) #输出1,2,3
#同时输出key与value (很常用)
for key,value in aDcit.items():
print(key,'=',value) #输出 a=1,b=2,c=3
# 字符串也是可以作为迭代对象的
aStr = 'abcd'
for value in aStr:
print(value) # 输出a,b,c,d
# 当我们使用for循环时 只要作用于一个可迭代对象for循环就能正常运行 不太关心这个对象是list还是字符串或其他 那么如何判断一个对象是否可以迭代呢? 用collections模块的Iterable类型判断
from collections import Iterable
print(isinstance('abc',Iterable)) #输出True
print(isinstance(123,Iterable)) #输出False
# 最后一个问题 如果list要实现下标与值的循环要怎么办 Python内置的emumerate函数可以将list变成索引-元素对
aList = ['a','b','v']
for key,value in enumerate(aList): #注意这里不需要.items()
print(key,'-',value)
# 列表生成式 Python内置的非常简单却强大的可以用来创建list的生成式
aList = list(range(1,6)) #生成1到10的list[1,2,3,4,5]
# 如果要生成 [1*1,2*2,3*3]的怎么办 先想到的是循环
aList = []
for i in list(range(1,6)):
aList.append(i*i)
# 这种方式太繁琐 通过列表生成式一句代码就能生成
aList = [x*x for x in range(1,6)]
print(aList) #输出[1,4,9,16,25]
# 还可以在for循环后面加判断
aList = [a*a for a in range(1,6) if a%2==0]
print(aList) #输出[4,16]
# 还可以通过2层循环生成2个集合的全排列
aList = [a+b for a in 'abc' for b in 'xyz' if b=='x']
print(aList) #输出['ax','bx','cx']
# 三层以上的很少用但原理都是一样的
'''
再说下列表生成式中if else的用法
[x for x in range(1, 11) if x % 2 == 0] 这个能正常筛选出偶数
[x for x in range(1, 11) if x % 2 == 0 else 0] 这个会报错
因为for后面的if是一个筛选条件 不能带上else 我们可以尝试将if else写在for前面
[x if x % 2 == 0 else 0 for x in range(1, 11)]
'''
aList = [a if a%2==0 else 0 for a in range(1,6)]
print(aList) # 输出[0,2,0,4,0]
# 生成器 通过列表生成式我们可以快速生成一个list 但是由于内存限制 列表时的容量也是有限的 而且当创建一个百万级元素的list时 如果只用到前面几个元素 这么大的空间就白白地浪费了 所以如果列表的元素可以通过某种固定的算法计算出来 那么我们是否可以在循环的过程中不断的推算后续的元素 这样就不必创建完成的list 从而节省空间 在Python中 一边循环一边计算的的机制 叫生成器 (generator)
# 要创建一个generator 有很多种方式 最简单的一种是将列表生成式的[] 改为() 就创建了一个generator
aGenerator = (x for x in range(1,6)) #这样就生成了一个generator 但list可以直接打印 generator要这么打印呢?如果要一个个打印出来可以通过next(aGenerator)打印 但这种方式打印到最后没有更多的元素时会报错 正确的打印方式是通过for循环 因为generator也是一个可迭代对象啊
for value in aGenerator:
print(value) #输出1,2,3,4,5 这样也不用关心到了最后一个会报错的问题
# 但并不是所有的生成算法都那么简单 当一个list的生成算法比较复杂不能通过列表生成式去生成list的时候 我们还可以通过函数去生成
# 比如比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
# 1, 1, 2, 3, 5, 8, 13, 21, 34, ... 这种列表生成式处理不了 但通过函数我们却能简单的实现它
def flb(max):
n,a,b = 0,0,1
while n < max:
print(b)
a,b = b,a+b
n = n + 1
return 'done'
flb(5) #输出1,1,2,3,5
# 仔细观察其实flb函数中是定义了斐波拉契数列的推算规则 这种逻辑就很像generator 要将flb函数变成generator 只需要将print(b)改为yield b 就可以了
# 这就是定义generator的另一种方式了
def flb(max):
n,a,b = 0,0,1
while n < max:
yield b
a,b = b,a+b
n = n + 1
return 'done'
# 如果一个函数定义中包含了yield关键字 那么它就不是一个简单的函数了 而是一个generator
# 同样我们使用for循环来调用generator 但这里我们发现拿不到generator的return语句返回值 如果想要拿到return语句的返回值 必须捕获 StopIteration异常 返回值包含在StopIteration的value中
g = flb(6)
while True:
try:
x = next(g)
print('g:',x)
except StopIteration as e:
print('Generator return value:', e.value)
break
'''
2020-6-14 1:17 结束了一场在台风天由于吃饱了睡不着而跨天的学习 睡觉~~
'''
# 迭代器
'''
可以作用于for循环的数据类型有以下几种
一类是数据集合类型:list、tuple、dict、set、str等
一类是generator
这些可以直接作用于for循环的对象统称为可迭代对象:Iterable
可以使用isinstance()判断一个对象是否为可迭代对象
而生成器不但可以作用于for循环 还能被next()函数不断调用并返回下一个值 知道最后抛异常表示没有后面的值了
可以被next()函数不断调用并返回下一个值的对象成为迭代器:Iterator
同样也可以通过isinstance()函数来判断一个对象是否为Iterator对象
生成器都是Iterator对象 但list、tuple、dict、str虽然是Iterable 但不是Iterator 但可以通过iter()函数将Iterable转为Iterator
'''
# 函数式编程
# 高阶函数
# map/reduce Python内建了map与reduce函数
# map() 函数接收2个参数 一个是函数 一个Iterable map将传入的函数依次作用到序列的每个元素 并把结果作为新的Iterator返回 例:
def f(x):
return x*x
aList = map(f,list(range(1,11)))
aList = list(aList)
print(aList) # 输出 [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 再例如 将list里面的所有元素转成str
aStr = list(map(str,list(range(1,11))))
print(aStr) #输出 ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10']
# reduce() 同样接收2个参数 reduce把结果和继续和下一个元素做积累计算 其效果就是
# reduce(f,[x1,x2,x3,x4]) = f(f(f(x1,x2),x3),x4) 例如将一个序列[1,2,3,4,5]转成整数12345
from functools import reduce
def f1(x,y):
return x*10+y
aReduce = reduce(f1,list(range(1,6)))
print(aReduce) #输出 12345
# filter filter()函数用来过滤序列 filter函数也接收一个函数与一个序列 filter把传入的函数依次作用于序列 但根据函数返回值是True还是False俩决定保留还是遗弃该元素
# 例:保留一个list中的偶数
def is_o(x):
return x%2 == 0
aList = list(filter(is_o,list(range(1,11)))) #要注意filter函数返回的是一个Iterator,所以要强迫filter()完成计算结果,需要用list()函数获得所有结果并返回list
print(aList) #输出[2, 4, 6, 8, 10]
# sorted 排序算法 无论是冒泡还是快速排序 排序的核心都是比较两个元素的大小
# 通过sorted对list排序
aList = sorted([10,8,97,-5,56,99])
print(aList) #输出 [-5, 8, 10, 56, 97, 99]
# 还可以传入一个key函数来实现自定义的排序
aList = sorted([10,8,97,-5,56,-99],key=abs)
print(aList) #输出[-5, 8, 10, 56, 97, -99]
# 返回函数(闭包) 告诫函数除了可以接收h函数作为参数外 还能将函数作为返回值
# 实现一个可变参数的求和
def my_sum(*args):
sum = 0
for x in args:
sum = sum + x
return sum
# 但是如果不需要立即求和 而是在后面的代码中根据需求再计算
def lazy_sum(*args):
def my_sum():
total = 0
for x in args:
total = total + x
return total
return my_sum
f = lazy_sum(1,2,3,4,5)
print(f) # 输出.my_sum at 0x000000000269ACA0>
print(f()) # 输出15
# 返回一个函数时 牢记该函数未被执行 所以返回函数中不要引用任何可能会变化的变量
# 匿名函数 当我们将函数作为参数去传值时 正常是先定义函数 但直接传入匿名函数会更方便
# 关键字lambda表示匿名函数 例如
f = lambda x:x*x
print(f(2)) #输出4 由此可以看出 冒号前面的x表示函数的参数 冒号后面的x*x表示函数内部计算逻辑 匿名函数不需要写return
'''
2020-6-14 23:43 一个没有台风的台风天
'''
#-------------------------时间分割线-------------------------------------------------
# 模块
# 作用域 在一个模块中我们可能会定义很多的函数与变量 有一些是可以给外部调用 但有一些我们不希望外部调用 Python通过 _ 前缀来实现变量与函数的私有化
# 面向对象编程 封装、继承与多态是 面向对象的三大特点
# 类和实例 面对对象最重要的就是类(class) 与 实例 (Instance) 必须牢记类是抽象的模板 而实例是根据类创建出来的的一个个具体的对象 每个对象拥有相同的方法 但数据可能会不一样 在Python中 定义类 是通过class关键字
class Student(object):
pass
# class 后面紧跟着类名 即Student 类名通常是大写开头的单词 紧接着是(object) 表示该类从哪个类继承下来 通常如果没有合适的继承类就使用object 因为这是所有类最终都会继承的类
# 定义好类之后就可以通过该类创建出实例 创建实例是通过类名+()实现
studentOne = Student()
print(studentOne) # 输出 <__main__.Student object at 0x00000000021E97C0>
# 可以看到变量studentOne指向的就是一个Student实例 后面的0x00000000021E97C0是内存地址
# 然后可以给实例对象绑定属性 例如 我们给这个一号学生绑定一个name
studentOne.name = '小明'
print(studentOne.name) # 输出小明
# 由于类起到了一个模板的作用 因此我们可以在创建实例的时候 把一些我们认为必须绑定的属性强制写进去 通过定义一个__init__方法
class Student(object):
def __init__(self,name,age,score):
self.name = name
self.age = age
self.score = score
# __init__方法前后都有2个下划线 第一个参数一定是self 表示实例本身 有了__init__方法 创建实例的时候就不能传入空的参数 但self参数不用传
# 数据封装 面对对象编程的一个重要特点就是封装 其实就是将内部方法封装起来 外部调用这个方法时不需要知道方法的内部实现逻辑 只需要知道传什么参数 会得到什么结果就行了
# 访问限制 在类中 如果希望内部属性或方法不被外部直接调用 那么定义属性或方法时请在前面加上 _ 下划线 在Python中 实例的变量名如果以下划线_开头 就变成了一个私有变量 只有内部可以使用 外部不能直接调用
class Student(object):
def __init__(self,name,score):
self._name = name
self._score = score
def print_score(self):
print('%s:%s' %(self._name,self._score))
studentOne = Student('小明',99)
studentOne.print_score() # 输出 小明:99
# 继承与多态
# 继承 当我们定义一个class的时候 可以从某个现有的class继承 新的class称为 子类 而被继承的class 称为 父类、基类或超类
# 定义一个叫 human 的类 有一个run()方法可以打印
class Human(object):
def run(self):
print('人类在奔跑......')
# 当我们需要编写 Boy或Girl类的时候 就可以从Human类继承出来
class Boy(Human):
pass
class Gril(Human):
pass
# 继承有什么好处 当然是获得父类的全部财产(功能)啊!!!
boy = Boy()
boy.run() # 输出 人类在奔跑......
girl = Girl()
girl.run() # 输出 人类在奔跑......
# 如果父类的方法满足不了子类 子类完全可以重写父类的方法 比如
class Boy(Human):
def run(self):
print('男孩在奔跑......')
class Girl(Human):
def run(self):
print('女孩在奔跑......')
boy = Boy()
boy.run() # 输出 男孩在奔跑
# 当子类与父类都存在相同的run方法时 我们就说 子类的run()覆盖了父类的run() 在代码运行时 总会调用子类的run() 这样 我们就获得了继承的另一个好处 多态
# 多态 要理解什么是多态 我们首先还要对数据类型进行一个说明 当我们定义class的时候 实际上就定义了一种数据类型 和自带的list、tuple、dict没什么2样
# 判断一个变量是什么类型我们可以通过isinstance()函数
isinstance(boy, Boy) # 输出True
isinstance(boy, Human) # 输出True boy既是男孩也是人类
# 所以 在继承关系中 如果一个实例的数据类型是某个子类 那它的数据类型也可以看做是父类 反过来就不行 男孩可以被看作人类 但人类不能被看作男孩
# 要理解多态的好处 我们再定义一个函数 该函数接收一个Human类型的变量
def run_twice(Human):
Human.run()
Human.run()
# 当我们传入Human实例时
run_twice(Human())
# 输出 人类在奔跑...... 人类在奔跑......
# 当我们传入Boy实例时
run_twice(Boy()) # 输出 男孩在奔跑...... 男孩在奔跑......
# 整理一下以上的代码 就是:
class Human(object):
def run(self):
print('人类在奔跑')
class Boy(Human):
def run(self):
print('男孩在奔跑')
class Girl(Human):
def run(self):
print('女孩在奔跑')
class Stone(object):
pass
def run_twice(Human):
Human.run()
Human.run()
run_twice(Human()) #人类跑2次
run_twice(Boy()) # 男孩跑2次
run_twice(Girl()) # 女孩跑2次
run_twice(Stone()) # 石头没有继承人类也没有run()方法 所以它不会跑(报错)
'''
所以 多态的意思就是:对于一个变量 我们只需要知道它是Human类型 无需知道它的子类 就可以放心的调用run() 而具体的 run()方法是作用在Human、Boy是Girl对象上 由运行时该对象的确切类型决定 这就是多态的威力 调用方只管调用 不管细节 而我们再新增一个Human的子类时 只要确保run()方法编写正确 不用管原来的代码是怎么调用的
'''
'''
2020-6-15 23:30 万周开头难 周一即将结束
'''
#-----------------------时间分割线------------------------------------------------
# 面对对象高级编程
# 使用__slots__
# 正常情况下 当我们定义了一个class 创建了一个class实例之后我们可以动态的给这个实例绑定任何的属性与方法
class Student(object):
pass
# 给绑定一个属性
s = Student()
s.name = '小明'
# 绑定一个方法
def set_age(self,age): # 先定义一个函数
self.age = age
from types import MethodType
s.set_age = MethodType(set_age,s)
s.set_age(25)
print(s.age) # 输出25
# 但是你给这个实例绑定的方法 对其他的实例是不起作用的
# 但是 如果我们要限制实例的属性怎么办 只允许对Student实例添加name与age属性
# 为了达到限制的目的 Python允许在定义class 的时候定义一个特殊的__slots__变量 来限制该class实例能添加的属性
class Student(object):
__slots__ = ('name','age') # 用tuple类型定义允许绑定的属性名称
# 使用__slots__要注意 __slots__定义的属性只对当前类实例起作用 对继承的子类是不起作用的
# 使用@property
# 在绑定属性时 如果我们直接把属性暴露出去 虽然写起来简单 但是没办法校验参数 导致属性值可以随便修改
s = Student()
s.score = 9999 # 这显然不符合逻辑 为了限制score 可以通过一个set_score()方法来设置成绩 再通过一个get_score()方法来获取成绩 这样在set_score()方法里就能校验参数
class Student(object):
def get_score(self):
return self.score
def set_score(self,score):
if not isinstance(score,int):
raise ValueError('成绩应该是整数')
if score < 0 or score > 100:
raise ValueError('成绩应该在0-100')
self.score = score
# 但是 上面的方法调用又显得复杂 没有直接用属性那么简单 有没又能检查参数 又能通过属性这样简单的方法来访问变量呢
# Python内置的@property装饰器就是负责把一个方法变成属性调用
class Student(object):
@property
def score(self):
return self._score # 这里的_score表示score是私有变量
@score.setter
def score(self, value):
if not isinstance(value,int):
raise ValueError('成绩应该为整数')
if value < 0 or value > 100 :
raise ValueError('成绩应该在0-100之间')
self._score = value
s = Student()
s.score = 60
print(s.score) # 输出60
s.score = 9999 # 输出提示成绩应该在0-100之间
# 还可以定义只读属性 不设置setter就是只读属性
# 多重继承 简单点就是可以继承多个类 而不是像php或java这样只能继承一个类
'''
2020-6-16 23:32 今晚微风 效率低下
'''
#----------------------------时间分割线-----------------------------------------------
# IO编程
# 文件读写 读写文件是最常见的IO操作 在读写文件前 我们必须了解 在磁盘上读写文件的功能都是操作系统提供的 现代操作系统不允许普通的程序直接操作磁盘 所以 读写文件就是请求操作系统打开一个文件对象(通常描述为文件操作符) 然后通过操作系统提供的接口从这个文件对象中读取数据 或者将数据写到这个文件对象中
# 读文件 使用Python内置的open()函数 传入文件名与标识符
f = open('/haha.txt','r') # r表示读 如果该文件不存在 就会报一个IOError的错误 并且给出错误码和详细的信息告诉你这个文件不存在
# 如果文件打开成功 调用read()方法可以一次性读取文件的所有内容 Python将内容读到内存中 用一个str对象保存
content = f.read()
print(content) # 输出 这个一个哈哈哈文件
# 最后是调用close()方法将文件关闭 文件使用完之后必须关闭 因为文件对象会占用操作系统的资源 并且操作系统同一时间能打开的文件数量也是有限的
f.close()
# 由于文件读写随时都有可能产生IOError 一旦出错 后面的f.close()就不会被调用 为了保证无论是否出错都能正确的关闭文件 我们可以用try...finally来实现
try:
f = open('haha.txt','r')
print(f.read())
except expression as identifier:
pass
finally:
f.close()
# 但每次都这么写太繁琐了 所以Python引入了with语句来帮我们自动调用close()
with open('haha.txt','r') as f:
print(f.read())
# 这个效果与前面的try 是一样的 但代码更简洁并且不用调用close()方法
# 调用read()会一次性读取文件内容 但如果文件有个10G大小 内存就爆了 为了保险起见 不确定大小的文件 可以反复调用read(size)方法 限制每次最多读取size字节的内容 另外 调用readline()可以每次读一行内容 调用readlines()可以一次性读取所以内容然后以list方式返回 因此要根据需求决定怎么用
# 如果能确定文件大小 直接用read() 不确定文件大小就用 read(size) 如果是配置文件用readlines()最佳
with open('haha.txt','a') as f:
content = f.readlines()
for text in content:
print(text) # b'\xff\xd8\xff\xe0\x00\x10JF......' 十六进制表示的字节
# file-like Object
# 像open()函数返回的这个有个read()方法的对象 在Python中被称为file-like Object。除了file外 还可以是内存的字节流 网络流和自定义流等 file-like Object不要求从特定类继承 只要有个read()方法就行
# StringIO 就是在内存中创建的file-like Object 常用于临时缓冲
# 二进制文件
# 前面将的都是读取文本文件 并且是utf-8编码的文本文件 要读取二进制文件 比如图片、视频等 用'rb'模式打开文件即可
with open('3.jpg','rb') as image:
print(image.read())
# 字符编码
# 要读取非UTF-8编码的的文本文件 需要给open()函数传入encoding参数 例如读取GBK编码的文件
with open('haha.txt','r',encoding='gbk') as f:
print(f.read())
# 遇到一些编码不规范的文件 你还可能会遇到UnicodeDecodeError 因为在文本中可能掺夹了一些非法的字符 遇到这种情况 open()函数还接收一个errors参数 表示遇到编码错误之后怎么处理 最简单的方式就是直接忽略
with open('haha.txt','r', errors='ignore') as target:
print(target.read())
# 写文件 写文件与读文件的操作是一样的 唯一区别是操作open函数时 传入标志符'w'或者'wb'表示写文本文件或写二进制文件
with open('haha.txt','w') as p:
p.write('嘿嘿嘿我是后面加入的') # 要写入特定编码的文本文件 请给open()函数传入encoding参数 将字符串转成特定的编码
# 以w或者wb模式写入文件时 如果文件已存在 会直接覆盖 相当于将之前的内容删掉重新写入 如果希望追加到文件末尾可以通过'a'(append)模式
# 所有模式的定义与含义 https://docs.python.org/3/library/functions.html#open
# StringIO和BytesIO
# StringIO 很多时候 数据读写不一定是文件 也可以在内存中读写 StringIO顾名思义就是在内存中读写str
# 要将str写入StringIO 我们需求先创建一个StringIO 然后像文件一个写入即可
from io import StringIO
f = StringIO()
f.write('hello StringIO')
print(f.getvalue()) # getValue()方法用于获取写入后的str
# 要读取StringIO 可以用一个str初始化StringIO 然后像读文件一样企业读取就好了
f = StringIO('hello\n StringIO')
print(f.read())
# BytesIO
# StringIO只能操作字符串 如果要操作二进制文件 就需要用到BytesIO
# BytesIO实现了在内存中读写bytes 我们创建一个BytesIO 然后写入一些bytes
from io import BytesIO
f = BytesIO()
f.write('中文'.encode('utf-8'))
print(f.getvalue()) # 输出 b'\xe4\xb8\xad\xe6\x96\x87'
# 和StringIO类似 可以用一个bytes初始化BytesIO 然后像读文件一个去读
f = BytesIO(b'\xe4\xb8\xad\xe6\x96\x87')
print(f.read())
# 操作文件与目录
# Python内置的os模块可以直接调用操作系统提供的接口函数
import os
print(os.name) # 输出操作系统名称 如果是posix,说明系统是Linux、Unix或Mac OS X,如果是nt,就是Windows系统。
print(os.uname()) # 报错 因为在windows上不提供这个函数
print(os.environ) # 打印全部环境变量
# 获取某个环境变量的值 可以直接os.environ.get('key)
print(os.environ.get('APPCAN_PATH','没有找到适合返回的默认值'))
# 操作文件与目录的函数一部分放在 os模块中 一部分放在os.path模块中 查看、创建与删除目录可以这么调用:
path= os.path.abspath('.') # 查看当前目录的绝对路径
# 在某个目录下创建一个新目录 首先将新目录的完整路径展示出来
newPath = os.path.join(path,'newDir')
os.mkdir(newPath)
# 删掉一个目录
os.rmdir(newPath)
# 将两个路径合成一个时 不要直接拼接字符串 而要通过os.path.join()函数 这样可以正确处理不同操作系统的路径分隔符
# 在Linux/Unix/Mac下,os.path.join()返回这样的字符串:
# part-1/part-2
# 在windows下返回这样的字符串:
# part-1\part-2
# 同样的道理 要拆分路径时 也不要直接去拆字符串 而要通过os.path.split()函数 后一部分总是最后级别的目录或文件名
# os.path.splitext() 可以直接获取到文件扩展名
# 序列化
# json
import json
d = dict(name = 'jon',age=18,score=80)
print(json.dumps(d)) # 输出{"name": "ddd", "age": 18, "score": 88}
# json.dumps()方法返回一个str
# 将json反序列为Python对象
json_str = '{"name": "ddd", "age": 18, "score": 88}'
print(json.loads(json_str))
'''
2020-6-18 17:45 学习了一天 充实 准备下班~~
'''
#---------------------时间分割线-----------------------------------
# 进程与线程
# 操作系统相关知识:Unix/Linux操作系统提供一个fork()系统调用 普通的函数 调用一次 返回一次 但是fork()调用一次返回2次 因为操作系统自动把当前进程(成为父进程) 复制了一份(成为子进程) 然后 分别在父进程与子进程中返回 子进程永远返回0 而父进程返回子进程的ID 因为一个父进程有很多子进程 所以 父进程要记下所有子进程的ID 而子进程字需要调用getppid()就能拿到父进程的ID
# 多进程
# Python 的os模块封装了常见的系统调用 其中fork()就包含在内
# 下面这段代码只能在Unix或linux下执行 因为windows系统没有fork调用
import os
print('Process (%s) start' % os.getpid())
pid = os.fork()
if pid == 0:
# 子进程
print('我的子进程%s 我的父进程是 %s' % os.getpid(),os.getppid())
else :
print('我是父进程%s,我创建了一个子进程%s' %os.getpid(),pid)
# multiprocessing
# Python的multiprocessing模块提供了一个Process类来代表一个进程对象 下面的例子演示了启动一个子进程并等待其结束
from multiprocessing import Process
import os
# 子进程要执行的代码
def run_proc(name):
print('运行子进程%s(%s)' %(name,os.getpid()))
if __name__ == '__main__':
print('父进程%s' %os.getpid())
p = Process(target=run_proc,args=('test',))
print('子进程即将启动')
p.start()
p.join()
print('子进程结束')
''' 输出
父进程14944
子进程即将启动
运行子进程test(14448)
子进程结束
'''
# 创建子进程时 只需要传入要执行的函数以及函数的参数 创建一个Process实例 用start()方法启动
# join()可以等待子进程结束后再继续往下运行 通常用于进程间的同步
# Pool 如果需要创建大量的子进程 可以用进程池的方式批量创建子进程
from multiprocessing import Pool
import os,time,random
def long_time_task(name):
print('运行任务%s(%s)' %(name,os.getpid()))
start = time.time()
time.sleep(random.random()*3)
end = time.time()
print('任务%s运行时间为:%0.2f' %(name,(end-start)))
if __name__ == '__main__':
print('父进程为%s' % os.getpid())
p = Pool(4)
for i in range(5):
p.apply_async(long_time_task,args=(i,))
print('等待全部子进程结束')
p.close()
p.join()
print('全部子进程运行结束')
''' 输出
父进程为7224
等待全部子进程结束
运行任务0(2252)
运行任务1(6488)
运行任务2(4504)
运行任务3(9572)
任务3运行时间为:0.08
运行任务4(9572)
任务1运行时间为:0.51
任务2运行时间为:1.48
任务4运行时间为:1.62
任务0运行时间为:2.11
全部子进程运行结束
'''
# 对Pool对象调用join()方法会等待所有的子进程执行完毕 调用join()之前必须调用close() 调用close()之后就不能继续添加Process了
# 请注意输出的结果 task0,1,2,3是立刻执行的 而task4是等到task3运行完了之后才执行的 这是因为Pool的默认大小是4 因为最多只能同时执行4个子进程 如果p = Pool(5) 就能同时执行5个子进程
# 子进程
# 很多时候 子进程并不是自身 二是一个外部进程 我们创建了子进程后 还要控制子进程的输入与输出
# subprocess模块可以让我们很方便的启动一个子进程 然后控制其输入输出
import subprocess
print('$ nslookup www.python.org')
r = subprocess.call(['nslookup','www.python.org'])
'''
输出
$ nslookup www.python.org
服务器: public1.114dns.com
Address: 114.114.114.114
非权威应答:
名称: dualstack.python.map.fastly.net
Addresses: 2a04:4e42:36::223
151.101.228.223
Aliases: www.python.org
'''
# 进程间通信
# 进程之间肯定是要通信的 Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据
# 以Queue为例 在父进程中创建2个子进程 一个往Queue里写数据 一个往Queue里读数据
from multiprocessing import Process,Queue
import os, time, random
# 写数据
def write(q):
print('写进程%s' % os.getpid())
for value in ['a','b','c']:
print('往queue里写入%s' % value)
q.put(value)
time.sleep(random.random())
# 读数据
def read(q):
print('读进程%s' % os.getpid())
while True:
value = q.get(True)
print('从Queue中取出的值%s' % value)
if __name__ == '__main__':
# 父进程创建queue 并传给各个子进程
q = Queue()
pw = Process(target=write,args=(q,))
pr = Process(target=read,args=(q,))
# 启动子进程pw 开始写入数据
pw.start()
# 启动子进程pr 开始读数据
pr.start()
# 等待pw结束
pw.join()
# 子进程pr里面是一个死循环 无法等待其结束 只能强制终止
pr.terminate()
'''
输出
写进程8576
往queue里写入a
读进程11572
从Queue中取出的值a
往queue里写入b
从Queue中取出的值b
往queue里写入c
从Queue中取出的值c
'''
# 关于进程与requests的一个小demo
# 采用多进程从本地另外一个项目拿数据回来 用一个list接收 然后统一写到txt文件里面
from multiprocessing import Pool
import requests,json,time
def get_company_data(companyId):
url = 'http://zaa.com/index.php?s=/Index/test&company_id='+ str(companyId)
ret = requests.get(url)
ret = json.loads(ret.text)
return ret['data']
if __name__ == '__main__':
start = time.time()
companyIds = [441,531,581,605,620,645,647,669]
#companyIds = [441, 531, 581, 605]
p = Pool(4)
results = []
for companyId in companyIds:
results.append(p.apply_async(get_company_data, args=(companyId,)))
print('任务进行中......')
p.close()
p.join()
# 将读回来的数据写到一个txt文件中
txtFile = open('客户欠款文件.txt','a',encoding='utf-8')
dataList = []
for res in results:
companyCustomInfo = res.get()
for cf in companyCustomInfo:
string = '企业id:%s,企业名:%s,客户名称:%s,交易额:%s,欠、还时间差:%s,欠款次数:%s,回款周期:%s' % (
cf['company_id'],cf['name'],cf['custom_name'],cf['amount_receivable'],cf['day'],cf['num'],cf['avg'])+'\n'
txtFile.write(string)
txtFile.close()
end = time.time()
print('任务完成!总耗时:',(end-start))
# 多线程
# 多任务可以由多进程完成 也可以由一个进程内的多线程完成 一个进程至少有一个线程
# Python的标准库提供了2个模块: _thread 和 threading, _thread是低级模块 threading是高级模块 对_thread进行了封装 大多数情况下我们都使用threading
# 启动一个线程就是把一个函数传入并创建Thread实例 然后调用start()开始执行
import time,threading
def loop():
print('%s 正在运行...' % threading.current_thread().name)
n = 0
while n < 5:
n = n + 1
print('%s 输出 %s' % (threading.current_thread().name, n))
time.sleep(1)
print('%s 结束' % threading.current_thread().name)
print('主线程%s 正在运行' % threading.current_thread().name)
t = threading.Thread(target=loop, name='子线程')
t.start()
t.join()
print('主线程%s结束' % threading.current_thread().name)
'''
主线程MainThread 正在运行
子线程 正在运行...
子线程 输出 1
子线程 输出 2
子线程 输出 3
子线程 输出 4
子线程 输出 5
子线程 结束
主线程MainThread结束
'''
# 由于任何进程会启动一个线程 我们把该线程成为主线程 主线程又可以启动新的子线程 threading模块有一个current_thread()函数 它可以返回当前线程实例
# lock 锁
# 多进程与多线程最大的区别是 多进程中 同一个变量 各自有一份拷贝存在每个进程中 互不影响 而多线程中 所有变量由所有线程共享 所以 任何一个变量都可能被任何一个程序修改 因此 线程之间共享数据最大的危险在于多个线程将同一个变量修改 就给改乱了
# 先来一个例子
import time,threading
money = 0
def change_it(n):
global money
# 先加后减 最后money的结果应该为0
money = money + n
money = money - n
def run_thread(n):
for i in range(100000):
change_it(n)
t1 = threading.Thread(target=run_thread,args=(5,))
t2 = threading.Thread(target=run_thread,args=(8,))
t1.start()
t2.start()
t1.join()
t2.join()
print(money)
# 多次运行之后 该程序会偶尔出现money值不为0的情况 由于线程的调度是由操作系统决定的 当t1 t2交替执行时 只要循环的次数够多 money最后的结果就不一定是0了 因为在高级语言中 一条语句在执行的过程中可能会被分为多条语句 例如:
money = money + n # 会被分为2步 1、计算money+n 然后存到一个临时变量中 2、将临时变量的值赋给money
# 当t1 t2交替执行时
'''
初始值 balance = 0
t1: x1 = balance + 5 # x1 = 0 + 5 = 5
t2: x2 = balance + 8 # x2 = 0 + 8 = 8
t2: balance = x2 # balance = 8
t1: balance = x1 # balance = 5
t1: x1 = balance - 5 # x1 = 5 - 5 = 0
t1: balance = x1 # balance = 0
t2: x2 = balance - 8 # x2 = 0 - 8 = -8
t2: balance = x2 # balance = -8
结果 balance = -8
'''
# 为了确保money是正确的 就要给change_it上锁 当某个线程开始执行change_it()时其他线程不能同时执行change_it()只能等待锁被释放之后才能获得该锁然后去修改 无论多少线程 只有一个锁 所以不会造成修改的冲突
# 创建一个锁通过threading.lock()来实现
# 下面通过上锁优化上面的代码 确保money最后一定是等于0
import threading
money = 0
lock = threading.Lock()
def change_it(n):
global money
money = money + n
money = money - n
def run_thread(n):
for i in range(1000000):
lock.acquire() # 先获得锁
try:
change_it(n)
finally:
lock.release() # 释放锁
t1 = threading.Thread(target=run_thread, args=(10,))
t2 = threading.Thread(target=run_thread, args=(50,))
t1.start()
t2.start()
t1.join()
t2.join()
print(money) # 无论运行多少次 循环多少次 money输出结果都是0
# 锁的好处就是可以确保某段代码只能由一个线程从头到尾的执行 坏处当然也多 首先是阻止多线程的并发运行 包含锁的某段代码只能单线程的运行
# ThreadLocal 快速获取当前线程的局部变量
import threading
local_student = threading.local()
def process_student():
# 获取当前线程关联的student:
std = local_school.student
print('Hello, %s (in %s)' % (std, threading.current_thread().name))
def process_thread(name):
# 绑定ThreadLocal的student:
local_school.student = name
process_student()
t1 = threading.Thread(target= process_thread, args=('Alice',), name='Thread-A')
t2 = threading.Thread(target= process_thread, args=('Bob',), name='Thread-B')
t1.start()
t2.start()
t1.join()
t2.join()
# 常用内建模块
# datetime datetime是Python处理日期与时间的标准库
# 获取当前日期与时间
from datetime import datetime
now = datetime.now()
print(now) # 输出2020-06-22 21:06:30.563283
# 获取指定日期与时间
dt = datetime(2020,6,22,19,7,59)
print(dt) # 输出2020-06-22 19:07:59
# datetime转成timestamp 用datestamp()方法
# timestamp转成datetime 用fromtimestamp()方法
# collections cellections是Python内建的一个集合模块 提供了许多有用的集合类
# namedtuple
# 我们知道tuple可以用来表示一个不变集合 例如一个点的二位坐标可以表示为
p = (1,2)
# 但是这看起来不像一个坐标 并且tuple要通过索引来获取元素 很麻烦 可以用namedtuple来试试
from collections import namedtuple
Point = namedtuple('Point',['x','y'])
p = Point(1,2)
print(p.x) # 输出1
print(p.y) # 输出2
# namedtuple是一个函数 我们用它来创建一个自定义的tuple对象 并且可以通过属性的方式而不是索引的方式去引用tuple的某个元素
# 创建的Point对象tuple的子类
# deque
# 使用list存储数据时 按索引访问元素很快 但是插入和删除元素就很慢了 因为list是线性存储 数据量大的时候 插入与删除效率都很低
# deque是为了高效实现插入与删除操作的双向列表 适用于队列与栈
from collections import deque
q = deque(['a','b','c'])
q.append('v')
q.appeenleft('y')
print(q) # 输出 deque(['y', 'a', 'b', 'c', 'v'])
# deque除了实现list的append与pop之外 还实现了appendleft 与popleft 这样就可以很高效的往头部添加与删除元素了
# defaultdict
# 使用dict时 如果一个引用的key不存在 就会报错 希望key不存在时 返回一个默认值就用defaultdict
from collections import defaultdict
dd = defaultdict(lambda: '不存在的')
dd['key1'] = '手动赋值'
print(dd['key1']) # 输出手动赋值
print(dd['key2']) # 输出 不存在的
# orderdict
# dict的key是无序的 对dict做迭代时 我们无法确认key的顺序 如果要保持key的顺序 可以用orderdict
from collections import OrderedDict
d = OrderedDict([('a',1),('b',2]) # Orderdict的key是按照插入的顺序排序 而不是key之间的排序
# Orderdict可以实现一个先进先出的dict 当超出容量时 删除最早添加的key
# ChainMap
# Counter Counter是一个简单的计数器 例如 统计字符出现的个数
from collections import Counter
c = Counter()
for ch in 'hello':
c[ch] = c[ch] + 1
print(c) # 输出 Counter({'l': 2, 'h': 1, 'e': 1, 'o': 1})
c.update('hi')
print(c) # 输出 Counter({'h': 2, 'l': 2, 'e': 1, 'o': 1, 'i': 1})
# hashlib Python的hashlib提供了常用的摘要算法 如果md5 sha1等
import hashlib
md5 = hashlib.md5()
pwd = '123456'
md5.update(pwd.encode('utf-8'))
hashPwd = md5.hexdigest()
print(hashPwd) # 输出 e10adc3949ba59abbe56e057f20f883e
sha1 = hashlib.sha1()
sha1.update(pwd.encode('utf-8'))
newPwd = sha1.hexdigest()
print(newPwd) # 输出 7c4a8d09ca3762af61e59520943dc26494f8941b
# urllib urllib提供了一系列用于操作url的功能
# Get urllib的request模块可以很方便的抓取url内容 也就是发生一个get请求到具体的页面 返回http的响应
from urllib import request
url = 'https://recsidebar.csdn.net/getSideBarRecommend.html'
with request.urlopen(url) as f:
data = f.read()
print(f.status,f.reason)
for k,v in f.getheaders():
print('%s:%s' %(k,v))
print(data.decode('utf-8'))
# 模拟浏览器发生get请求
from urllib import request
req = request.Request(url)
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
print('Status:', f.status, f.reason)
for k, v in f.getheaders():
print('%s: %s' % (k, v))
print('Data:', f.read().decode('utf-8'))
# POST
from urllib import request,parse
post_data = parse.urlencode([
('name','12345'),
('pwd','12456')
])
req = request.Request(url)
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent', 'Mozilla/6.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
req.add_header('Referer', 'https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')
with request.urlopen(req,data=post_data.encode('utf-8')) as f:
print('status',f.status)
# 常用第三方模块
# Pillow
from PIL import Image
im = Image.open('test.jpg')
w,h = im.size
print('原画尺寸为%s %s'%(w,h)) # 输出 原画尺寸为500 300
# 缩小一半
im.thumbnail((w//2,h//2))
print('Resize image to: %sx%s' % (w//2, h//2))
# PIL的ImageDraw提供了一系列的绘图方法 让我们可以直接绘图
'''
2020年6-22 23:03 很多知识都要写了实际的案例才能真正体会其用处、以及踩它的坑
'''