面向对象 - 多重继承(一个类继承多个类)
- 如果一个类有多个父类,而多个父类又有公共的父类(菱形/砖石继承)
那么在搜索属性和方法时搜索的依据是c3算法(类似于广度优先搜索)
这个是Python3中的一个改进,在此之前搜索的额算法是深度优先搜索(DFS) - 在实际开发尽量避免多重继承,无法避免的时候可以把除第一父类外的父类设定为抽象类,子类在继承的时候重写方法
from abc import ABCMeta,abstractmethod
class Father(object):
def __init__(self, name):
self._name = name
def drink1(self):
print(self._name + '正在喝酒')
def gamble(self):
print(self._name + '正在赌博')
class Monk(object, metaclass=ABCMeta):
def __init__(self, name):
self._name = name
@abstractmethod
def eat_vegetable(self):
pass
@abstractmethod
def chant(self):
pass
class Musicion(object, metaclass=ABCMeta):
def __init__(self, name):
self._name = name
@abstractmethod
def drink2(self):
pass
@abstractmethod
def play_piano(self):
pass
class Son(Father, Monk, Musicion):
def __init__(self, name, nickname, artname):
Father.__init__(self, name)
self._nickname = nickname
self._artname = artname
def play_piano(self):
print(self._artname + '正在弹钢琴')
def read(self):
print(self._nickname + '正在念经')
def drink1(self):
print(self._name + '正在喝五粮液')
def drink2(self):
print(self._artname + '正在喝王老吉')
def main():
son = Son('盖小伦', '智空', '银河之力')
son.drink()
# Musicion.drink(son)
son.chant()
son.play_piano()
if __name__ == '__main__':
main()
版本控制Subversion(集中控制) / Git(分布控制)
- 使用Git版本控制操作步骤:
命令提示符进入需要版本控制的文件夹
git init # 初始化,建成仓库,可以记录历史版本
git add .(导入当前文件夹所有文件) # git add test007.py只导入test007.py这个文件
git status # 查看修改后的结果/状态
git commit -m ‘修正了一个bug’ #说明修改原因(本地版本控制)
git remote add origin https//…. # 与远端仓库建立联系
git push origin master # 推送到远程仓库
概要1:git init - git add . - git status - git commit -m ‘提交原因’ (本地版本控制)
2: git clone https…实际开发中可以先建好远程仓库,拷贝到本地后再开始编辑以及推送到远程仓库
3: 远端git remote add origin https//… - git pull https//…(远端仓库拉到本地)- git push origin master…(推送到远端仓库)
- 常用命令
git pull – cat test007.py # 查看当前文档内容
git branch查看分支 git branch new_function建立新分支 git merge new-function合并分支 git branch -d new-function rm
cls # 清屏
cd ./cd .. # 回到当前/上一级目录
pwd # print work d…打印当前工作目录
ls -a #查看仓库所有文件
git log # 查看历史版本/日志
git reset # 回到初始版本
git checkout data.json # 恢复删除的文件
git clon \http:…. # 克隆云端文件
正则表达式
正则表达式就是记录文本规则的代码,定义字符串的匹配模式。
常用元字符(代表字符串的开头和结尾,它只匹配一个位置)
. 匹配除换行符以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意的空白符
\d 匹配数字
\b 匹配单词的开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束常用限定符(指定数量的代码)
*重复零次或更多次
+重复一次或更多次
? 重复零次或一次
{n} 重复n次
{n,} 重复n次或更多次
{n,m} 重复n到m次常用反义符
\W 匹配任意不是字母,数字,下划线,汉字的字符
\S 匹配任意不是空白符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符常用分组语法
(exp) 匹配exp,并捕获文本到自动命名的组里
(?< name >exp) 匹配exp,并捕获文本到名称为name的组里,也可以写成(?’name’exp)
(?:exp) 匹配exp,不捕获匹配的文本,也不给此分组分配组号
(?=exp) 匹配exp前面的位置
(?<=exp) 匹配exp后面的位置
(?!exp) 匹配后面跟的不是exp的位置
(? < !exp) 匹配前面不是exp的位置
import re # 导入正则表达式模块
def main():
username = 'someone'
m = re.match(r'^\w{6,20}$', username)
print(m) # 如果匹配失败,返回None
if m:
print(m.span()) # 如果匹配成功,拿到匹配的范围
print(m.group()) # 把匹配到的范围取出来
if __name__ == '__main__':
main()
我们玩游戏的时候有些敏感字是不能被输出的,这时候就可以用*来代替
import re
def main():
re.sub # substitute替换
sentence = '赵信我操你大爷干你二爷Fuck你姑爷'
pure = re.sub('[艹草操日干肏]|赵信|fuck|shit|傻逼', '*', sentence,
flags=re.IGNORECASE) # |分支, flags标记IGNORECASE忽略大小写
print(pure) # 输出"*我*你大爷*你二爷*你姑爷"
if __name__ == '__main__':
main()
process进程,thread线程
进程是操作系统分配内存的基本单元,进程之间的内存是相互隔离的,通过icp机制/管道通信。
一个进程可以划分为多个线程,线程是进程的执行单元 ,也是操作系统分配cpu的执行单元;线程启用的越多,占用cpu越多。使用多线程/多进程可以提升执行效率,缩短程序执行时间;改善用户体验。
- python中使用多进程比多线程更好,因为多进程相互之间是独立的,程序执行效率更高。
进程
from multiprocessing import Process
import subprocess # subprocess子进程
import time
import os
def output():
print(os.getpid()) # 启用多进程
while True:
print('Pong', end = '', flush=True) # flush=True关闭缓存
time.sleep(0.001)
def main():
print(os.getpid) # 打印进程号
p = Process(target=output) # 这里传入函数名,表示进程启用后才在这个进程里面去执行函数
p.start()
while True:
print('Ping', end = '', flush=True)
time.sleep(0.001)
def main():
subprocess.call('calc') # call调用calc计算器
subprocess.call('notepad')
if __name__ == '__main__':
main()
线程
- 多线程是共享内存的,共享数据。
python不能用到cpu的多核特性,但是这不代表他的多进程、多线程是无用的。
实际开发中,多线程的程序不好写,也不好调试,因为cpu分配是随机的,运行时如果有bug那么就不知道它什么时候回出现问题。 - 创建线程的两种方式:
1,直接创建Thread对象并通过target参数指定线程启动后要执行的任务。
2,继承Thread自定义线程,通过重写run方法指定线程启动后执行的任务,推荐使用这种方法!
from threading import Thread # from thread是python2中使用的模块
from time import sleep
def output():
while True:
print('Pong', end='', flush=True)
sleep(0.001)
def main():
t1 = Thread(target=output)
t1.start()
while True:
print('Ping', end='', flush=True)
sleep(0.001)
if __name__ == '__main__':
main()
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# 这里应该使用元组,并且尽管只有一个元素,但是也要加上逗号,否则就是一个字符串
t1 = Thread(target=output, args=('Ping',))
t1.start()
t2 = Thread(target=output, args=('Pong',))
t2.start()
if __name__ == '__main__':
main(
from threading import Thread
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(0.001)
def main():
# daemon=True - 将线程设置为守护线程(不值得保留的线程),其他线程/主程序如果执行完了,那么守护线程自动结束
t1 = Thread(target=output, args=('Ping',),daemon=True)
t1.start()
t2 = Thread(target=output, args=('Pong',), daemon=True)
t2.start()
if __name__ == '__main__':
main()
多进程模拟下载文件
如果多个任务之间没有任何的关联(独立子任务),而且希望利用cpu的多核特性,那么我们推荐使用多进程,因为任务之间没有数据交换
import time
import random
from threading import Thread
def download(filename):
print('开始下载%s...' % filename)
delay = random.randint(5,15)
time.sleep(delay)
print('%s下载完成,用时%d秒' % (filename, delay))
# 如果要写多线程,推荐使用这种方法
class DownloadTask(Thread):
def __init__(self, filename):
super().__init__()
self._filename = filename
# 钩子函数(hook) / 回调函数(callback)(写了这个方法,但是从来没有调用它,它是让系统启动线程的时候自动回调这个方法)
# 写程序时启用线程用start,不能用run!!!
def run(self):
download(self._filename)
def main():
start = time.time()
t1 = DownloadTask('Python从入门到住院.pdf')
t1.start()
t2 = DownloadTask('Pekin Hot.avi')
t2.start()
t1.join() # join等待进程结束(然后再打印时间)
t2.join()
end = time.time()
print('总共耗费了%f秒' % (end - start))
if __name__ == '__main__':
main()
网络编程
- 计算机网络:是多台独立自主的计算机形成的一个系统。
连接起来的目的是计算机之间共享资源。
使用TCP(能做到数据不传丢、流量控制、拥塞控制)/ICP连接起来的叫互联网。
# 创建一个无功能的服务器
from socket import socket, AF_INET, SOCK_STREAM
# SOCK_STREAM使用tcp,SOCK_DGRAM使用udp
def main():
# 创建一个基于TCP协议的套接字对象
# 因为我们做的是应用级的服务/产品,所以可以利用现有的传输服务来实现数据传输
server = socket() # AF_INET, SOCK_STREAM IPv4联网,只能这么写
# 绑定IP地址(网络上主机的身份标识)和端口(用来区分不同服务的IP 地址的扩展,一个端口对应一个服务)(端口不是一个设备)
server.bind(('10.7.189.75', 6543)) # ip写成localhost表示本地,6543表示端口号
# 开始监听客户端的连接
server.listen(512) # 512表示队列大小
print('服务器已经启动正在监听...')
while True:
# 通过accept方法接收客户端的连接
# accept方法是一个阻塞式的方法,如果没有客户端连上来
# 那么accept方法就会让代码阻塞,知道有客户端连接成功才返回
# accept方法返回一个元组,元组中的第一个值代表客户端的对象
# 元组中的第二个值又是一个元组,其中有客户端的IP地址和客户端的端口
# client = server.accept()
# print(client)
client, addr = server.accept()
print(addr, '连接成功.')
client.send('hello789'.encode('utf-8'))
client.close()
if __name__ == '__main__':
main()
模拟一个聊天服务器
from socket import socket
from threading import Thread
# TCP - Transfer Control Protocol
# UDP - User Datagram Protocol
def main():
class ClientHandler(Thread):
def __init__(self, client):
super().__init__()
self._client = client
def run(self):
while True:
try:
data = self._client.recv(1024) # 返回的是二进制数据
for client in clients:
# if client != self._client 不给自己转发消息
client.send(data) # 转发消息
if data.decode('utf-8') == 'byebye':
clients.remove(self._client)
self._client.close() # 与说‘byebye’的客户端断开连接
break
except Exception as e: # 获取异常消息
print(e) # 打印异常消息
clients.remove(self._client) # 移除异常客户端
break
server = socket()
# 这里可以使用Python命令行参数 - sys.argv
server.bind(('10.7.189.75', 54321)) # 端口号不要跟敏感号重复,建议取1025-65536区间
# 开始监听
server.listen(512)
clients = []
while True:
# 接收用户请求
client, addr = server.accept()
clients.append(client)
ClientHandler(client).start()
if __name__ == '__main__':
main()