多重继承
我们先来看一下代码:
class Father(object):
def __init__(self, name):
self._name = name
def drink(self):
print(self._name + '正在喝二锅头')
def gambal(self):
print(self._name + '正在赌博')
class Monk(object):
def __init__(self,nickname):
self._nickname = nickname
def eat_vegetable(self):
print(self._nickname + '正在吃斋饭')
class Musician(object):
def __init__(self,art_name):
self._art_name = art_name
def drink(self):
print(self._art_name + '正在喝白开水')
class Son(Father,Monk,Musician):
def __init__(self,name,nickname,art_name):
Father.__init__(self,name)
Monk.__init__(self,nickname)
Musician.__init__(self,art_name)
def main():
son = Son('王大锤','智障法师','小钢炮')
son.drink()
son.eat_vegetable()
son.gambal()
Musician.drink(son)
if __name__ == '__main__':
main()
王大锤正在喝二锅头
智障法师正在吃斋饭
王大锤正在赌博
小钢炮正在喝白开水
分析以上代码,所谓多重继承也就是一个子类同时继承了多个父类的属性。
上面代码中,Son这个子类同时同时继承了Father,Monk,Musician的属性。当创建对象的的时候,我们创建了三个,‘王大锤’首先继承了‘Father’这个父类,后面依次类推。所以,在Son中指定对父类时,时先后顺序是很重要的。
多重继承运用一般较少,原因是这种写法通常比较复杂,也不利于对代码的理解。
正则表达式
我们在拨打电话的时候,我们需要先输入号码,而电话号码是一串11位的数字,如果你输入的号码不是数字或者长度不符合,那么就无法匹配上,也就无法拨打。而正则表达式就是用来判断一个字符串是否符合命中匹配模式的。正则表达式是一个特殊的字符序列。
基本符号
正则表达式中有很多基本符号,这里为大家介绍几个常用的:
符号 | 解释 | 实例 | 说明 |
---|---|---|---|
. | 可以匹配任何字符 | a.c | abc,a5c,a#c等都可以匹配成功 |
\w | 可以匹配数字,字母,下划线 | a\wc | a2c,a_c,abc。但a#c无法匹配 |
\d | 匹配数字 | \d\d | 33,44等 |
\s | 匹配空格(包含换行符) | a\sc | a c |
^ | 匹配字符串开头 | ^\d | 只能以数字开头 |
$ | 匹配字符串结尾 | \d$ | 只能以数字结尾 |
\d{3} | 匹配三个数字 | ||
\d{3,} | 至少匹配个数字 | ||
\d{3,8} | 匹配三到八个数字 | 12345 | |
[0-9a-zA-Z_ | 可以匹配一个数字、字母或者下划线 | ||
[0-9a-zA-Z_]+ | 可以匹配至少由一个数字、字母或者下划线组成的字符串 | ‘a100’,’0_Z’,’Py3000’ | |
| | 分支 | foo|bar | 可以匹配foo或者bar |
转义
如果你想查找元字符本身的话,比如你查找.,或者*,就出现了问题:你没办法指定它们,因为它们会被解释成别的意思。这时你就得使用\来取消这些字符的特殊意义。因此,你应该使用.和*。当然,要查找\本身,你也得用\.
例如:unibetter.com匹配unibetter.com,C:\Windows匹配C:\Windows。
所以我们为了避免麻烦,一般使用python中的r前缀,这样就避免了转义的问题。例如:r’abc\001’
re.match((pattern, string, flags=0)
这个方法用于判断用正则表达式匹配字符串 成功返回匹配对象 否则返回None。例如;
test = '用户输入的字符串'
if re.match(r'正则表达式', test):
print('ok')
else:
print('failed')
re.compile(pattern, flags=0)
编译正则表达式返回正则表达式对象
re.search(pattern, string, flags=0)
re.search 扫描整个字符串并返回第一个成功的匹配。
import re
print(re.search('www', 'www.runoob.com').span()) # 在起始位置匹配
print(re.search('com', 'www.runoob.com').span()) # 不在起始位置匹配
(0, 3)
(11, 14)
例子1
就用电话号码这个例子,这个例子中就用到了上面介绍的所有方法。我们写下这段代码:
import re
def is_number(phone_number):
pattern1 = re.compile(r'^13[0-9]{9}$')
pattern2 = re.compile(r'^14[57][0-9]{8}$')
if pattern1.match(phone_number) :
return '有效号码'
else:
return '无效号码'
def main():
phone_number = input('请输入电话号码: ')
print(is_number(phone_number))
if __name__ == '__main__':
main()
请输入电话号码: 13566666666
有效号码
替换
import re
def main():
sentence = '傻逼帅的爆是个傻吊虽然长得帅XXZ也是个傻屌但是他没有帅的爆帅Fuck'
pure = re.sub('[逼吊屌]|fuck','*',sentence,flags=re.IGNORECASE)#sub命令为替换
print(pure)
sentence = 'You go your way, I will go mine!'
mylist = re.split(r'[ ,!]',sentence)#表示拆分
print(mylist)
if __name__ == '__main__':
main()
傻*帅的爆是个傻*虽然长得帅XXZ也是个傻*但是他没有帅的爆帅*
['You', 'go', 'your', 'way', '', 'I', 'will', 'go', 'mine', '']
以上这段代码实现了对原字符串中某些字符的替换,其中sub命令就是替换的命令。同时也实现了拆分这一功能,split表示拆分。
多线程与多进程
进程:操作单位分配内存的基本单位,进程之间的内存是相互隔离的。如果进程之间要联系需要依靠IPC机制。
线程:一个进程可以划分为多个线程,线程是进程的执行单元,也是操作系统分配CPU的基本单元。
多线程是为了得到更多的CPU调度。如果一个任务执行时间较长,我们可以将这个任务分为多个子任务。缩短程序执行时间,提高程序执行效率,改善程序性能。同时为了改善用户体验。
多进程
以下这个代码就是一个很简单的实现多进程的代码。
from multiprocessing import Process
import os
#process = 进程
#threod = 线程
def output():
print(os.getpid())#拿到当前正在执行的进程的执行号
while True:
print('太帅了',end='',flush=True)
def main():
print(os.getpid())
p = Process(target=output)#target -- 起进程目的
p.start()
while True:
print('帅的爆', end='', flush=True)
if __name__ == '__main__':
main()
这段代码模拟了一个同时下载多个文件的多进程任务。
import time
from random import randint
from multiprocessing import Process#导入多进程模块
#如果多个任务之间没有任何的关联(独立子任务)而且希望利用cpu的多核特性
#那么我们推荐使用更多进程
def download(filename):
print('开始下载%s...' % filename)
delay = randint(5, 15)
time.sleep(delay)
print('%s下载完成,用时%d秒' % (filename,delay))
def main():
start = time.time()
p1 = Process(target=download,args=('sjy',))
p1.start()
p2 = Process(target=download,args=('sdb',))
p2.start()
p1.join()#等待p1结束
p2.join()
end = time.time()
print('总共耗费了%f秒' % (end - start))
开始下载sdb...
开始下载sjy...
sdb下载完成,用时8秒
sjy下载完成,用时12秒
总共耗费了12.283703秒
多线程
创建线程的两种方法
1.直接创建Thread对象来并通过target参数指定线程启动后要执行的任务
以下这个代码就是使用第一种方法创建多线程:
from threading import Thread
from time import sleep
def output(string):
while True:
print(string, end='', flush=True)
sleep(1)
def main():
#守护线程 - 不值得保留的线程 - 其他线程如果都执行完毕了那么守护线程自动结束
#daemo=True - 将线程设置为守护线程
t1 = Thread(target=output,args=('帅的爆', ),daemon=True)
t1.start()
t2 = Thread(target=output,args=('傻', ),daemon=True)
t2.start()
if __name__ == '__main__':
main()
2.继承Thread自定义线程 通过重写run方法制动线程启动后执行的任务
以下就是使用面向对象来创建类,然后通过重写run方法来创建多线程(打出100个帅的爆和100个傻子):
from threading import Thread#导入模块
class PrintThread(Thread):#创建类
def __init__(self,string,count):
super().__init__()
self._string = string
self._count = count
def run(self): #重写run方法
for _ in range(self._count):
print(self._string,end='',flush=True)
def main():
PrintThread('帅的爆',100).start()
PrintThread('傻子',100).start()
if __name__ == '__main__':
main()
网络编程基础
TCP
TCP是面向连接的通信协议,通过三次握手建立连接,通讯完成时要拆除连接,由于TCP是面向连接的所以只能用于端到端的通讯。
TCP提供的是一种可靠的数据流服务,采用“带重传的肯定确认”技术来实现传输的可靠性。TCP还采用一种称为“滑动窗口”的方式进行流量控制,所谓窗口实际表示接收能力,用以限制发送方的发送速度。
如果IP数据包中有已经封好的TCP数据包,那么IP将把它们向‘上’传送到TCP层。TCP将包排序并进行错误检查,同时实现虚电路间的连接。TCP数据包中包括序号和确认,所以未按照顺序收到的包可以被排序,而损坏的包可以被重传。
TCP将它的信息送到更高层的应用程序,例如Telnet的服务程序和客户程序。应用程序轮流将信息送回TCP层,TCP层便将它们向下传送到IP层,设备驱动程序和物理介质,最后到接收方。
面向连接的服务(例如Telnet、FTP、rlogin、X Windows和SMTP)需要高度的可靠性,所以它们使用了TCP。DNS在某些情况下使用TCP(发送和接收域名数据库),但使用UDP传送有关单个主机的信息。
UDP
UDP是面向无连接的通讯协议,UDP数据包括目的端口号和源端口号信息,由于通讯不需要连接,所以可以实现广播发送。
UDP通讯时不需要接收方确认,属于不可靠的传输,可能会出现丢包现象,实际应用中要求程序员编程验证。
UDP与TCP位于同一层,但它不管数据包的顺序、错误或重发。因此,UDP不被应用于那些使用虚电路的面向连接的服务,UDP主要用于那些面向查询—应答的服务,例如NFS。相对于FTP或Telnet,这些服务需要交换的信息量较小。使用UDP的服务包括NTP(网络时间协议)和DNS(DNS也使用TCP)。
欺骗UDP包比欺骗TCP包更容易,因为UDP没有建立初始化连接(也可以称为握手)(因为在两个系统间没有虚电路),也就是说,与UDP相关的服务面临着更大的危险。
利用TCP建立一个现实时间的服务器和客户端
首先是建立服务器,其标准步骤,首先导入socket模块(Socket又称”套接字”,应用程序通常通过”套接字”向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯)。第二步,创建套接字。第三步,绑定IP地址和端口。第四步监听客户端连接,设置等待队列长度。最后,使用accept来接受客户端连接,发送消息。
import datetime
from socket import socket,AF_INET,SOCK_STREAM
# 在CMD中输入netstat -na 可以查看当前已经建立好连接的网络地址
# 在CMD中输入telnet + ip地址 就可以连接到这个网络地址
# 在CMD中输入ipcofig 查看ip地址
def main():
server = socket()
# 创建一个基于TCP协议的套接字对象,默认TCP
# 因为我们做的是应用级的产品或服务所以可以利用现有的传输服务来实现数据传输
server.bind(('10.7.189.94',6789))
# 绑定IP地址(网络上主机的身份标识)和端口(用来区分不同服务的IP地址的扩展)
# 前面为本机IP地址,6789位端口号(自己设置)
server.listen(512)
# 开始监听客户端的连接
# 设置连线队列,最多同时连线512位,512是一个经验值。可以自己写,不过只能写2的次方数
print('服务器已经启动正在监听...')
while True:
client, addr = server.accept()
# 通过accept方法接受客户端连接
# accept方法是一个阻塞式方法,如果没有客户端连接上来
# 那么accept方法就会让代码阻塞,知道有客户端连接成功猜返回
# accept方法返回一个元组,元组中的第一个值代表客户端的对象
# 元组中的第二个值又是一个元组,其中有客户端的IP地址和客户端的端口
print(addr, '连接成功.')
curr_time = datetime.datetime.now()
time = curr_time.__str__()
client.send(time.encode('utf-8'))
client.close()
if __name__ == '__main__':
main()
现在建立客户端:
from socket import socket
def main():
client = socket()
client.connect(('10.7.189.94', 6789))
data = client.recv(1024)
print(data.decode('utf-8'))
if __name__ == '__main__':
main()