python100天1-15

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 01-15python基础

# 16-20python进阶

# 21-30前端概述

# 31-35Linux

# 36-40MySQL

# 41-55Django

# 56-60FaskAPI

# 61-65爬虫与并发编程

# 66-80numpy&pandas

# 81-90机器学习&pytorch

# 91-100项目

Python100天学习1-15

资料连接

第一天-初识python

1
2
3
4
5
6
7
8
9
10
# 1. python历史
# 2. python优缺点
# 3. python安装
# 4. print的简单使用
# print函数可以输出多个值,多个值之间可以用 , 进行分隔,输出的内容之间默认以空格分开。
print('你好', '世界')
print('hello', 'world', sep=', ', end='!')
print('goodbye, world', end='!\n')

# 5.turtle画国旗和佩奇

第二天-语言元素

1
2
3
4
5
6
7
8
9
10
# 1. 程序,变量和类型
# 2. 变量命名原则
# 3. 类型转换

- chr():将整数转换成该编码对应的字符串(一个字符)。
- ord():将字符串(一个字符)转换成对应的编码(整数)。
- int(): 将字符串表示的n进制数字转换为十进制表示
- bin(), oct(), hex(): 将十进制数字转为2/8/16进制字符串表示

# 4. 运算符及其优先级

# 3. 类型转换

类型转换

# 4. 运算符及其优先级

运算符 描述
[] [:] 下标,切片
** 指数
~ + - 按位取反, 正负号
* / % // 乘,除,模,整除
+ - 加,减
>> << 右移,左移
& 按位与
^ | 按位异或,按位或
<= < > >= 小于等于,小于,大于,大于等于
== != 等于,不等于
is is not 身份运算符
in not in 成员运算符
not or and 逻辑运算符
= += -= *= /= %= //= **= &= ` =^=>>=<<=`

说明: 在实际开发中,如果搞不清楚运算符的优先级,可以使用括号来确保运算的执行顺序。

第三天-分支结构

第四天-循环结构

第五天-构造程序逻辑

第六天-函数和模块的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 1.可变参数
可变参数允许传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple

# 2.关键字参数
关键字参数允许传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict


# 3.导入模块
如果导入的模块除了定义函数之外还有可以执行代码,那么Python解释器在导入这个模块时就会执行这些代码

# 4.变量作用域
if __name__ == '__main__':
# 这里声明的变量属于全局作用域

def a():

def b():

# 这里修改全局变量需要声明global
# 这里修改a函数里面的变量需要声明nonlocal

# 仅仅使用不需要声明

# 如果没有全局变量但是声明了,会新建一个全局变量
# 如果没有nonlocal但是声明了,会报错

第七天-字符串和常用数据结构

字符串函数

可以使用*复制字符串

因此a=[[0] * 3]*5 a里面的list都是同一个地址,修改一个就会修改全部
但是[0] * 3 数字是直接存的对象 修改这个就是直接换了个对象 不糊修改对象的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
str1 = 'hello, world!'
# 通过内置函数len计算字符串的长度
# len() 复杂度为O(1) 调用__len__
print(len(str1)) # 13
# 获得字符串首字母大写的拷贝
print(str1.capitalize()) # Hello, world!
# 获得字符串每个单词首字母大写的拷贝
print(str1.title()) # Hello, World!
# 获得字符串变大写后的拷贝
print(str1.upper()) # HELLO, WORLD!
# 从字符串中查找子串所在位置,rfind 最后一次出现的位置
print(str1.find('or')) # 8
print(str1.find('shit')) # -1
# 与find类似但找不到子串时会引发异常 rindex最后一次出现的位置
# print(str1.index('or'))
# print(str1.index('shit'))
# 检查字符串是否以指定的字符串开头
print(str1.startswith('He')) # False
print(str1.startswith('hel')) # True
# 检查字符串是否以指定的字符串结尾
print(str1.endswith('!')) # True
# 将字符串以指定的宽度居中并在两侧填充指定的字符
print(str1.center(50, '*'))
# 将字符串以指定的宽度靠右(左:ljust)放置左侧填充指定的字符
print(str1.rjust(50, ' '))
str2 = 'abc123456'
# 检查字符串是否由数字构成
print(str2.isdigit()) # False
print(str2.isdecimal()) # False
print(str2.isnumeric()) # False
# 检测字符串中所有的单词拼写首字母是否为大写,且其他字母为小写。
print(str2.istitle())
# 检测字符串是否只由空格组成。
print(str2.isspace())
# 检查字符串是否以字母构成
print(str2.isalpha()) # False
# 检查字符串是否以数字和字母构成
print(str2.isalnum()) # True
str3 = ' jackfrued@126.com '
print(str3)
# 获得字符串修剪左右(lstrip,rstrip)两侧空格之后的拷贝
print(str3.strip())
# 根据指定的分隔符将字符串进行分割。
# 如果字符串包含指定的分隔符,则返回一个3元的元组,第一个为分隔符左边的子串,第二个为分隔符本身,第三个为分隔符右边的子串。 rpartition 最右边一个
print(str3.partition('@')) #(' jackfrued', '@', '126.com ')
# 大小写字符的转换
print(str3.swapcase())

字符串格式化

1
2
3
4
5
6
7
8
9
10
11
# 1.
a, b = 5, 10
print('%d * %d = %d' % (a, b, a * b))
# 2.
a, b = 5, 10
print('{} * {} = {}'.format(a, b, a * b))
print('{0} * {1} = {2}'.format(a, b, a * b))
print('{aaa} * {bbb} = {ccc}'.format(aaa=a, bbb=b, ccc=a * b))
# 3.
a, b = 5, 10
print(f'{a} * {b} = {a * b}')

列表

列表容器中并没有保存真正的对象,它保存的仅仅是对象的引用(堆中的地址)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
list1 = [1, 3, 5, 7, 100]
# 添加元素
list1.append(200)
list1.insert(1, 400)
# 合并两个列表
list1.extend([1000, 2000])
list1 += [1000, 2000]
# 根据值删除元素 删除第一个
list1.remove(1234)
# 根据下标删除元素
list1.pop(0)

# 切片返回的是拷贝,修改新数组,原数组不动
# https://pythontutor.com/python-debugger.html#mode=edit
fruits = [ [66666,77777777], 'apple', 'strawberry', 'waxberry']
fruits3 = fruits[:4]
print(fruits3)
# 数组里面存的是列表的地址,拷贝的也是列表的地址,修改还是到列表的地址去修改,所以会变
fruits3[0][0]=000
fruits3[2]='aaaaaaaaa'
print(fruits3)
print(fruits)
# [[66666, 77777777], 'apple', 'strawberry', 'waxberry']
# [[0, 77777777], 'apple', 'aaaaaaaaa', 'waxberry']
# [[0, 77777777], 'apple', 'strawberry', 'waxberry']

什么时候不用数组

1
2
3
# array 类似C的数组
# 必须指定类型

生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import sys
# 用列表的生成表达式语法创建列表容器
# 用这种语法创建列表之后元素已经准备就绪所以需要耗费较多的内存空间
f = [x ** 2 for x in range(1, 1000)]
print(sys.getsizeof(f)) # 查看对象占用内存的字节数
# 请注意下面的代码创建的不是一个列表而是一个生成器对象
# 通过生成器可以获取到数据但它不占用额外的空间存储数据
# 每次需要数据的时候就通过内部的运算得到数据(需要花费额外的时间)
f = (x ** 2 for x in range(1, 1000))
print(sys.getsizeof(f)) # 相比生成式生成器不占用存储数据的空间
for val in f:
print(val)

yield:生成函数

元组

元组在创建时间和占用的空间上面都优于列表

集合

字典

序列的抽象基类

MutavleSequence:可变序列抽象基类(setitem,delitem)
Sequence:不可变序列抽象基类

+,+=,extend区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# +=实际上是调用了extend方法
# +=返回的本身,在原地址上修改
# a=a+ 会返回一个新对象
# append会把参数当成一个对象加进去
# extend参数必须是可迭代对象,一个个加进去
a=[1,2]
print(id(a))

a.extend((777,))
a+=[666]
# 报错
# a+=(777)
print(id(a))

a=a+[666]
print(id(a))

a.append([666,777])
print(id(a))
# 2358526812672
# 2358526812672
# 2358526332032
# 2358526332032

可切片对象

1
2
3
4
5
6
7
8
9
10

alist[len(alist):]=[9]
# 末尾追加元素
alist[:0]=[1,2]
# 开头追加元素
alist[3:3]=[1,2]
# 索引位置追加元素
# 结束位置大于长度会返回长度
# 开始位置大于长度会返回空列表
# 切片赋值长度必须相等

第八天-面向对象编程基础

python三个知识点:is和==,嵌套列表,类的私有属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 1.类的私有属性可以在属性名前面加两个下划线
# __len__不是私有成员,因为后面也有__
class Test:

def __init__(self, foo):
self.__foo = foo

def __bar(self):
print(self.__foo)
print('__bar')


def main():
test = Test('hello')
# AttributeError: 'Test' object has no attribute '__bar'
test.__bar()
# AttributeError: 'Test' object has no attribute '__foo'
print(test.__foo)


test = Test('hello')
test._Test__bar()
print(test._Test__foo)


if __name__ == "__main__":
main()

# 2.Python并没有从语法上严格保证私有属性或方法的私密性,它只是给私有的属性和方法换了一个名字来妨碍对它们的访问,更换名字的规则仍然可以访问到它们

第九天-面向对象进阶

class用于声明一个类,用type创建类
object是所有类的父类,所有类是type的实例

类的属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 1.@property装饰器
class Person(object):
def __init__(self, name, age):
self._name = name
self._age = age
# 访问器 - getter方法
@property
def name(self):
return self._name
# 访问器 - getter方法
@property
def age(self):
return self._age
# 修改器 - setter方法
@age.setter
def age(self, age):
self._age = age

# 属性名字和@property修饰的方法名字不能一样,不然会死循环
# 把一个getter方法变成属性,只需要加上@property就可以了
# @property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
# 上面name是只读属性,age是读写属性


# 2.__slots__魔法 ,只有slots内的属性才能被添加,对子类没有用,如果子类有,就是父类和子类的并集
class Person(object):
# 限定Person对象只能绑定_name, _age和_gender属性
__slots__ = ('_name', '_age', '_gender')
def __init__(self, name, age):
self._name = name
self._age = age
# 会报错
# self.hhhh=666
Person._gender = '男'
# 这样能绑定?
Person.sex = '?'
person = Person('王大锤', 22)
# 这样会报错,但是加上Person._sex = '?' 就变成了只读,不能修改
person.sex=66

类的方法

1
2
3
4
5
6
7
8
9
10
11
12
# 1.静态方法

# @staticmethod修饰,不用self,和C++类似

# 2.类方法
# @classmethod修饰,默认传递了cls参数,调用类本身,
@classmethod
def now(cls):
print(cls)

# 3.实例方法
# self 就是实例本身

继承和多态

1
2
3
4
5
6
7
8
9
10
11
12
13

# 子类在继承了父类的方法后,可以对父类已有的方法给出新的实现版本,这个动作称之为方法重写(override)。通过方法重写我们可以让父类的同一个行为在子类中拥有不同的实现版本,当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态


# 抽象类
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
pass

定制类-魔法函数(不是继承,python自带)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# __str__打印输出变成自定义字符串
# __repr__ 直接调用类时打印(jupyter)
def __str__(self):
return '6666'
__repr__ = __str__
# __iter__可用for循环迭代
# __next__去下一个对象
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1 # 初始化两个计数器a,b
def __iter__(self):
return self # 实例本身就是迭代对象,故返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b # 计算下一个值
if self.a > 100000: # 退出循环的条件
raise StopIteration()
return self.a # 返回下一个值
# __getitem__像列表一样取值 也可以改成字典形式 也可以用for循环
if isinstance(n, int): # n是索引
if isinstance(n, slice): # n是切片

# 如果这个对象被for时,会首先调用__iter__方法返回一个iterator,然后再对这个iterator循环调用__next__方法,直到碰到StopIteration时则停止退出。

# 如果for的对象没有__iter__方法,则无法获得一个迭代器,那么就会报错,但是,如果这个类实现了__getitem__方法,会从0开始依次读取相应的下标,直到发生IndexError为止

# __iter__是优先读取的

# __getattr__获取类的属性,已经定义的属性不会调用,使用没有定义的属性才会调用
# __call__ 可以直接对实例进行调用
# __bases__查看父类
# __enter__ with进入
# __exit__with退出
class Sample:
def __enter__(self):
print( "enter")
return self
def __exit__(self, exc_type,exc_val,exc_tb):
print ( "exit")
def do_something(self):
print ( "doing something" )
with Sample() as sample:
sample.do_something()
# @contextlib.contextmanger

# __dict__与dir()的区别:
# dir()是一个函数,返回的是list;
# __dict__是一个字典,键为属性名,值为属性值(类和实例不一样,可以通过修改这个增加属性);
# dir()用来寻找一个对象的所有属性,包括__dict__中的属性,__dict__是dir()的子集;

如果要获得一个对象的所有属性和方法,可以使用dir()函数

dir('abc')

第十天-图形用户界面和游戏开发

第十一天-文件和异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 1.json
import json
# 字符串处理
data = {
'name' : 'ACME',
'shares' : 100,
'price' : 542.23
}
json_str = json.dumps(data)
data = json.loads(json_str)
# 文件处理
# Writing JSON data
with open('data.json', 'w') as f:
json.dump(data, f)

# Reading data back
with open('data.json', 'r') as f:
data = json.load(f)


# 2.异常
# 1.except语句不是必须的,finally语句也不是必须的,但是二者必须要有一个,否则就没有try的意义了。
# 2.except语句可以有多个,Python会按except语句的顺序依次匹配你指定的异常,如果异常已经处理就不会再进入后面的except语句。
# 3.except语句可以以元组形式同时指定多个异常,参见实例代码。
# 4.except语句后面如果不指定异常类型,则默认捕获所有异常,你可以通过logging或者sys模块获取当前异常。
# 5.如果要捕获异常后要重复抛出,请使用raise,后面不要带任何参数或信息。
# 6.不建议捕获并抛出同一个异常,请考虑重构你的代码。
# 7.不建议在不清楚逻辑的情况下捕获所有异常,有可能你隐藏了很严重的问题。
# 8.尽量使用内置的异常处理语句来替换try/except语句,比如with语句,getattr()方法。

第十二天-字符串和正则表达式

正则表达式练习
正则表达式规则

1
2
3
4
5
6
# re模块处理

# pattern:r'自己写的表达式'

# str:待匹配字符串

函数 说明
compile(pattern, flags=0) 编译正则表达式返回正则表达式对象
match(pattern, string, flags=0) 用正则表达式匹配字符串 成功返回匹配对象 否则返回None
search(pattern, string, flags=0) 搜索字符串中第一次出现正则表达式的模式 成功返回匹配对象 否则返回None
split(pattern, string, maxsplit=0, flags=0) 用正则表达式指定的模式分隔符拆分字符串 返回列表
sub(pattern, repl, string, count=0, flags=0) 用指定的字符串替换原字符串中与正则表达式匹配的模式 可以用count指定替换的次数
fullmatch(pattern, string, flags=0) match函数的完全匹配(从字符串开头到结尾)版本
findall(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回字符串的列表
finditer(pattern, string, flags=0) 查找字符串所有与正则表达式匹配的模式 返回一个迭代器
purge() 清除隐式编译的正则表达式的缓存
re.I / re.IGNORECASE 忽略大小写匹配标记
re.M / re.MULTILINE 多行匹配标记

第十三天-进程和线程

进程线程知识参考操作系统

多进程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# Unix和Linux操作系统上提供了 `fork()`系统调用来创建进程,调用 `fork()`函数的是父进程,创建出的是子进程
# Windows没有fork调用
from multiprocessing import Process
from os import getpid
from random import randint
from time import time, sleep
def download_task(filename):
print('启动下载进程,进程号[%d].' % getpid())
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))
def main():
start = time()
p1 = Process(target=download_task, args=('Python从入门到住院.pdf', ))
p1.start()
p2 = Process(target=download_task, args=('Peking Hot.avi', ))
p2.start()
p1.join()
p2.join()
end = time()
print('总共耗费了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()

# 进程池
def main():
start = time()
p = Pool(4)
# 这里进程池有四个进程但是用了五个任务
# task 0,1,2,3是立刻执行的,而task 4要等待前面某个task完成后才执行
for i in range(5):
p.apply_async(download_task, args=(i,))
p.close()
p.join()
print('总共耗费了%.2f秒.' % (end - start))

# 进程通信
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
print('Process to write: %s' % os.getpid())
for value in ['A', 'B', 'C']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
print('Process to read: %s' % os.getpid())
while True:
value = q.get(True)
print('Get %s from queue.' % 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()
'''
Process to write: 50563
Put A to queue...
Process to read: 50564
Get A from queue.
Put B to queue...
Get B from queue.
Put C to queue...
Get C from queue.
'''

多线程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
from random import randint
# 在Python早期的版本中就引入了thread模块(现在名为_thread)来实现多线程编程,然而该模块过于底层,而且很多功能都没有提供
# 因此目前的多线程开发我们推荐使用threading模块,该模块对多线程编程提供了更好的面向对象的封装。
from threading import Thread
from time import time, sleep
def download(filename):
print('开始下载%s...' % filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (filename, time_to_download))
def main():
start = time()
t1 = Thread(target=download, args=('Python从入门到住院.pdf',))
t1.start()
t2 = Thread(target=download, args=('Peking Hot.avi',))
t2.start()
t1.join()
t2.join()
end = time()
print('总共耗费了%.3f秒' % (end - start))
if __name__ == '__main__':
main()

# 继承 `Thread`类的方式来创建自定义的线程类
from random import randint
from threading import Thread
from time import time, sleep
class DownloadTask(Thread):
def __init__(self, filename):
# 可以穿name给线程命名
super().__init__()
self._filename = filename
def run(self):
print('开始下载%s...' % self._filename)
time_to_download = randint(5, 10)
sleep(time_to_download)
print('%s下载完成! 耗费了%d秒' % (self._filename, time_to_download))
def main():
start = time()
t1 = DownloadTask('Python从入门到住院.pdf')
t1.start()
t2 = DownloadTask('Peking Hot.avi')
t2.start()
t1.join()
t2.join()
end = time()
print('总共耗费了%.2f秒.' % (end - start))
if __name__ == '__main__':
main()

# 线程上锁
from time import sleep
from threading import Thread, Lock
# RLock 可重用锁,同一线程中可以多次调用acquire,但是release要调用一样的次数
class Account(object):
def __init__(self):
self._balance = 0
self._lock = Lock()
def deposit(self, money):
# 先获取锁才能执行后续的代码
self._lock.acquire()
try:
new_balance = self._balance + money
sleep(0.01)
self._balance = new_balance
finally:
# 在finally中执行释放锁的操作保证正常异常锁都能释放
self._lock.release()
@property
def balance(self):
return self._balance
class AddMoneyThread(Thread):
def __init__(self, account, money):
super().__init__()
self._account = account
self._money = money

def run(self):
self._account.deposit(self._money)
def main():
account = Account()
threads = []
for _ in range(100):
t = AddMoneyThread(account, 1)
threads.append(t)
t.start()
for t in threads:
t.join()
print('账户余额为: ¥%d元' % account.balance)
if __name__ == '__main__':
main()

# 线程通信
from queue import Queue

# queue.Queue:这是一个线程安全的队列,可以被用来在线程之间传递数据。

# queue.LifoQueue:这是一个线程安全的栈,可以被用来在线程之间传递数据。

# queue.PriorityQueue:这是一个线程安全的优先队列,可以被用来在线程之间传递数据。

# collections.deque:这是一个线程安全的双端队列,可以被用来在线程之间传递数据。

# multiprocessing.Queue:这是一个线程安全的队列,可以被用来在进程之间传递数据。

第十四天-网络编程入门和网络应用开发

计算机网络基础知识补充

发邮件

发短信

网络服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 多线程网络服务

# 服务器端

from socket import socket, SOCK_STREAM, AF_INET
from base64 import b64encode
from json import dumps
from threading import Thread
def main():
# 自定义线程类
class FileTransferHandler(Thread):
def __init__(self, cclient):
super().__init__()
self.cclient = cclient
def run(self):
my_dict = {}
my_dict['filename'] = 'guido.jpg'
# JSON是纯文本不能携带二进制数据
# 所以图片的二进制数据要处理成base64编码
my_dict['filedata'] = data
# 通过dumps函数将字典处理成JSON字符串
json_str = dumps(my_dict)
# 发送JSON字符串
self.cclient.send(json_str.encode('utf-8'))
self.cclient.close()

# 1.创建套接字对象并指定使用哪种传输服务
server = socket()
# 2.绑定IP地址和端口(区分不同的服务)
server.bind(('192.168.1.2', 5566))
# 3.开启监听 - 监听客户端连接到服务器
server.listen(512)
print('服务器启动开始监听...')
with open('guido.jpg', 'rb') as f:
# 将二进制数据处理成base64再解码成字符串
data = b64encode(f.read()).decode('utf-8')
while True:
client, addr = server.accept()
# 启动一个线程来处理客户端的请求
FileTransferHandler(client).start()
if __name__ == '__main__':
main()

# 客户端

from socket import socket
from json import loads
from base64 import b64decode
def main():
client = socket()
client.connect(('192.168.1.2', 5566))
# 定义一个保存二进制数据的对象
in_data = bytes()
# 由于不知道服务器发送的数据有多大每次接收1024字节
data = client.recv(1024)
while data:
# 将收到的数据拼接起来
in_data += data
data = client.recv(1024)
# 将收到的二进制数据解码成JSON字符串并转换成字典
# loads函数的作用就是将JSON字符串转成字典对象
my_dict = loads(in_data.decode('utf-8'))
filename = my_dict['filename']
filedata = my_dict['filedata'].encode('utf-8')
with open('/Users/Hao/' + filename, 'wb') as f:
# 将base64格式的数据解码成二进制数据并写入文件
f.write(b64decode(filedata))
print('图片已保存.')
if __name__ == '__main__':
main()

第十五天-图像和办公文档处理

图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
>>> from PIL import Image
>>>
>>> image = Image.open('./res/guido.jpg')
>>> image.format, image.size, image.mode
('JPEG', (500, 750), 'RGB')
>>> image.show()

# 裁剪图像
>>> image = Image.open('./res/guido.jpg')
>>> rect = 80, 20, 310, 360
>>> image.crop(rect).show()
# 略缩图
>>> image = Image.open('./res/guido.jpg')
>>> size = 128, 128
>>> image.thumbnail(size)
>>> image.show()
# 缩放粘贴图像
>>> image1 = Image.open('./res/luohao.png')
>>> image2 = Image.open('./res/guido.jpg')
>>> rect = 80, 20, 310, 360
>>> guido_head = image2.crop(rect)
>>> width, height = guido_head.size
>>> image1.paste(guido_head.resize((int(width / 1.5), int(height / 1.5))), (172, 40))
# 旋转和反转
>>> image = Image.open('./res/guido.png')
>>> image.rotate(180).show()
>>> image.transpose(Image.FLIP_LEFT_RIGHT).show()
# 操作像素
>>> image = Image.open('./res/guido.jpg')
>>> for x in range(80, 310):
... for y in range(20, 360):
... image.putpixel((x, y), (128, 128, 128))
...
>>> image.show()
# 滤镜
>>> from PIL import Image, ImageFilter
>>>
>>> image = Image.open('./res/guido.jpg')
>>> image.filter(ImageFilter.CONTOUR).show()

Excel

Word

B站视频总结

元类编程
元类:创建类的类

1.动态属性

1
2
3
4
5
6
7
8
9
10
#get
@property修饰
#set
@aaa.setter
#查找不到进入
__getattr__
#先进入这个
__getattribute__

getattr(类,属性)==类.属性

2.属性描述符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 数据描述符
class IntField:
def __get__( self, instance,owner):
return self.value
def __set__(self, instance, value):
if not isinstance(value, numbers.Integral):
raise ValueError( "int value need")
if value < 0:
raise ValueError( "positive value need")
self.value = value
def __delete__(self, instance):
pass

class User:
# 自定义类型检测
age = IntField()

3.类属性取值过程

如果user是某个类的实例,那么user.age(以及等价的getattr(user, ‘age’))首先调用__getattribute__。如果类定义了_getattr_方法,
那么在_getattribute__抛出 AttributeError的时候就会调用到_getattr_,而对于描述符(get)的调用,则是发生在__getattribute__内部的。

user = User(),那么user.age顺序如下:

(1) 如果"age”是出现在user或其基类的__dict__中,且age是data descriptor,那么调用其__get__方法 ,否则

(2) 如果"age"出现在obj的__dict__中,那么直接返回 obj.dict[ ‘age’],否则

(3) 如果"age"出现在User或其基类的__dict__中

(3.1) 如果age是non-data descriptor,那么调用其__get__方法,否则
(3.2) 返回__dict__[ ‘age’]

(4) 如果User有__getattr__方法,调用__getattr__方法,否则

(5) 抛出AttributeError

4.__new__和__init__区别

new传的类本身

init传的对象实例

先进new后进init

new不返回对象,不会进init

5.type动态创建类

type(“类名”,(父类),{属性,函数})

控制类的创建过程
class user(metaclass=自定义元类)

元类编程->封装

6.可迭代,迭代器,生成器

迭代器和迭代序列分离

iter 可迭代

next 迭代器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class company(object):
def _init_(self, employee_list):
self.employee = employee_list
def _iter_( self):
return MyIterator( self.employee)

class MyIterator(Iterator ) :
def _init_(self, employee_list):
self.iter_list = employee_listself.index = 0
def inext_(self):
#真正返回迭代值的逻辑
try:
word = self.iter_list[ self.index]
except IndexError:
raise stopIteration
self.index +=1
return word

生成器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def gen_fib(index):
n,a,b = 0,0,1
while n<index:
yie1d b
a,b = b,a+b
n += 1
for data in gen_fib(10):
print (data)
I
PyGenObject
gi_frame
gi_code
会保存上一次执行的位置和代码

大文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def myreadlines(f, newline) :buf = ""
while True:
while newline in buf:
pos = buf.index( newline)
yield buf[:pos]
buf = buf[pos + len(newline) : ]
chunk = f.read(4096*10)
if not chunk :
# 文件结尾
yield buf
break
buf += chunk

with open("input.txt" ) as f:
for line in myreadlines(f,"{"):
print (line)

7.socket编程

见网络编程

8.多线程

1.GIL
全局解释器锁
python中一个线程对应c语言的一个线程
gil使得同一时刻只有一个线程运行在一个cpu上运行字节码
不能把多个线程映射到多个cpu上
gil会根据执行的字节码行数及时间片释放gil
遇见io操作也会主动释放(适合io频繁)

2.线程同步,通信
多线程实现
使用线程传递函数
继承多线程类,实现run
线程通信
共享变量:不好
Queue:还有其他线程安全的数据结构
线程同步
Lock,RLock
Lock:获取两次就会死锁
RLock:允许多线程环境下多次acquire,但是release要一样的数量
condition:wait()和notify() 等待和唤醒
先等待才能唤醒
把waiter的锁放入一个双端队列
notify把队列弹一个出来释放
with condition 就是获取锁释放锁(默认RLock)
with之后才能wait和notify,wait把condition的锁释放掉
con’t wait on a un-acquire lock
Semaphore:用于控制进入数量的锁
threading.Semaphore(3)

3.线程池&进程池
from concurrent import futures

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
executor = ThreadPoo1Executor(max_workers=1)
#通过submit函数提交执行的函数到线程池中,submit是立即返回
task1 = executor. submit(get_htm1,(3))
task2 = executor. submit(get_htm1,(2))

# done用于判断是否完成
task1.done()


# result获取函数返回结果
task1.result()


#要获取已经成功的task的返回
urls = [3,2,4]
all_task = [executor. submit(get_html,(url)) for url in urls]
# yield已经完成的线程
for future in as_completed(all_task):
data = future.result()
print( "get ipage success".format(data))


#通过executor获取已经完成的task返回值,返回顺序一致
for data in executor.map(get_html, urls):
print( "get {fpage".format(data))

# 阻塞主线程,等全部还是等一个
wait()

进程适合计算密集
线程适合io密集

父进程和子进程各有数据

子进程会把创建进程下面的代码单独运行一遍

ProcessPoolExecutor用的multiprocessing

不能用queue.Queue
不能用共享变量

from queue import Queue
from multiprocessing import Queue
from multiprocessing.Manager import Queue
#Manager 有很多数据结构
pipe只能用于两个进程
性能高于Queue

9.IO复用

并发
并发是指一个时间段内有几个程序在同一个cpu运行,但是任意时刻只有一个程序在cpu上运行
并行
并行是指任意时刻点上,有多个程序同时运行在多个cpu

同步
同步是指代码调用IO操作时必须等待IO操作完成才返
回的调用方式。
异步
异步是指代码调用IO操作时,不必等IO操作完成就返回的调用方式。

阻塞
阻塞是指调用函数时候当前线程被挂起。
非阻塞
非阻塞是指调用函数时候当前线程不会被挂起,而是立即返回。

10.回调协程

11.asynch await

12.事件循环