Python 面向对象
python是一门面向对象的语言
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class myclass: # 创建类
num = 10 # 定义类的属性(类的变量)
def __init__(self,name,age): # 构造函数 在实例化该类的时候自动调用该函数
self.name = name
self.age = age
def myfun(self):
return ('姓名:',self.name,'年龄:',self.age)
#创建类对象
newClass = myclass('mike','18')
#对象访问类的属性
print(newClass.name)
#对象访问类的方法
print(newClass.myfun())
Python内置类属性
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class myclass: # 创建类
"""
这里是备注的文档字符串
"""
num = 10 # 定义类的属性(类的变量)
def __init__(self,name,age): # 构造函数 在实例化该类的时候自动调用该函数
self.name = name
self.age = age
def myfun(self):
return ('姓名:',self.name,'年龄:',self.age)
#创建类对象
newClass = myclass('mike','18')
print(newClass.__dict__) # 类的属性(包含一个字典,由类的数据属性组成) #OUTPUT {'name': 'mike', 'age': '18'}
print(newClass.__doc__) # 类的文档字符串
# print(newClass.__name__) # python3的类没有__name__这个属性
print(newClass.__module__) # 类定义所在的模块
# print(newClass.__bases__) # python3的类没有__bases__这个属性
python对象销毁(垃圾回收)
引用计数器 :
- python 和java,php等语言一样,采用引用技术的技术来追踪对象
- 在python内部记录着所有使用中的对象各有多少引用
- 一个内部跟踪变量,称为一个引用计数器
- 当对象被创建时, 就创建了一个引用计数, 当这个对象不再需要时, 也就是说, 这个对象的引用计数变为0 时, 它被垃圾回收。但是回收不是"立即"的, 由解释器在适当的时机,将垃圾对象占用的内存空间回收
循环垃圾收集器:
- 循环引用指的是,两个对象相互引用,但是没有其他变量引用他们
- python 的垃圾收集器实际上是一个引用计数器和一个循环垃圾收集器
- 作为引用计数的补充, 垃圾收集器也会留心被分配的总量很大(及未通过引用计数销毁的那些)的对象。 在这种情况下, 解释器会暂停下来, 试图清理所有未引用的循环
感觉循环垃圾收集器有点像时刻处于监听状态
析构函数 del del在对象消逝的时候被调用,当对象不再被使用时,del方法运行
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Point:
def __init( self, x=0, y=0):
self.x = x
self.y = y
def __del__(self):
class_name = self.__class__.__name__
print(class_name, "destroyed")
pt1 = Point()
pt2 = pt1
pt3 = pt1
print(id(pt1), id(pt2), id(pt3))# 打印对象的id
del pt1
del pt2
del pt3
# OUTPUT 315754144 315754144 315754144 Point destroyed
类的继承
类的继承机制在面向对象编程过程中可以使代码的共用型大大提高,提高了系统的可维护性
python继承中的特点:
- 在继承中基类的构造(init()方法)不会被自动调用,它需要在其派生类的构造中亲自专门调用
- 在调用基类的方法时,需要加上基类的类名前缀,且需要带上self参数变量。区别于在类中调用普通函数时并不需要带上self参数
- Python总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
parentInfo = '父类属性168'
def __init__(self):
print('调用父类的构造函数')
def parentMethod(self):
print('调用父类parentMethod方法')
def setParentInfo(self,info):
Parent.parentInfo = info
def getParentInfo(self):
return (Parent.parentInfo)
class Child(Parent): # 定义子类 继承父类Parent
childInfo = '子类属性168'
def __init__(self):
print('调用子类构造函数')
# Parent.__init__(self) # 子类调用父类构造函数需要加上self参数
def childMethod(self):
print('调用子类childMethod方法')
childClass = Child() # OUTPUT 调用子类构造函数 当实例化子类对象的时候 自动调用子类的构造函数 但是不会自动调用父类的构造函数 如果实例化子类的时候调用父类的构造函数 需要 在子类构造函数中调用一次父类的构造函数
childClass.childMethod() # OUTPUT 调用子类childMethod方法
print(childClass.parentInfo) # OUTPUT 父类属性168 Child子类继承Parent父类 实例化Child子类对象可以访问Parent父类的属性
childClass.setParentInfo('访问父类属性')
print(childClass.getParentInfo()) # 访问父类属性 实例化子类对象 调用父类的getParentInfo方法
方法重写
当父类的方法无法满足现有的业务需求的时候可以在子类重写父类的方法
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
def myfun(self):
print('调用父类方法')
class Child(Parent):
def myfun(self):
print('子类重新父类myfun方法')
childClass = Child()
childClass.myfun() # OUTPUT 子类重新父类myfun方法
基础重载方法
方法 | 描述 | 简单的调用 |
---|---|---|
init ( self [,args...] ) | 构造函数 | 简单的调用方法: obj = className(args) |
del( self ) | 析构方法, 删除一个对象 | 简单的调用方法 : dell obj |
repr( self ) | 转化为供解释器读取的形式 | 简单的调用方法 : repr(obj) |
str( self ) | 用于将值转化为适于人阅读的形式 | 简单的调用方法 : str(obj) |
cmp ( self, x ) | 对象比较 | 简单的调用方法 : cmp(obj, x) |
add | 运算符重载算法+ | 简单的调用方法 : add(obj, x) |
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self, other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2, 10)
print(v1) #OUTPUT Vector (2, 10)
v2 = Vector(5, -2)
print(v2) #OUTPUT Vector (5, -2)
print(v1 + v2) #OUTPUT Vector (7, 8)
python类的私有属性与私有方法
类的私有属性
- __private_attrs:两个下划线开头,声明该属性为私有,不能在类地外部被使用或直接访问。在类内部的方法中使用时 self.__private_attrs
类的使用方法
- __private_method:两个下划线开头,声明该方法为私有方法,不能在类地外部调用。在类的内部调用 self.__private_methods
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Test:
publicInfo = 10
__privateInfo = 20
def getPrivateInfo(self):
print(self.__privateInfo)
def publicFun(self):
print('调用公共方法')
def __privateFun(self):
print('调用私有方法')
testClass = Test()
print(testClass.publicInfo) # OUTPUT 10 访问共用属性
# print(testClass.__privateInfo) # 会报错 类的外部 实例化该类的对象不能访问类的私有属性
print(testClass.getPrivateInfo()) # 20 如果 在外部实例化类对象 想访问类的私有属性 需要通过访问 类的公共对象 通过类内部的公共方法 通过该方法来间接访问类的私有属性
# print(testClass.__privateFun()) # 会报错 类的外部 实例化该类的对象不能访问类的私有方法 得借助类内部的公共方法来间接访问
Python正则表达式
- 正则表达式是一个特殊的字符序列,它能帮助你方便的检查一个字符串是否与某种模式匹配
- re 模块使 Python 语言拥有全部的正则表达式功能
- compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象。该对象拥有一系列方法用于正则表达式匹配和替换
- re 模块也提供了与这些方法功能完全一致的函数,这些函数使用一个模式字符串做为它们的第一个参数
re.match函数
re.match 尝试从字符串的开始匹配一个模式 匹配成功re.match方法返回一个匹配的对象,否则返回None
函数语法:re.match(pattern, string, flags=0)
参数 | 描述 |
---|---|
pattern | 匹配的正则表达式 |
string | 要匹配的字符串 |
flags | 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等 |
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
pattern = '^[1-9]{2,3}[a-z]$'
string = '19a'
res = re.match(pattern,string,flags=0)
print(res) # OUTPUT <_sre.SRE_Match object; span=(0, 1), match='1'> 匹配成功返回一个对象 反之返回none
re.search方法
re.search 会在字符串内查找模式匹配,直到找到第一个匹配
函数语法:re.search(pattern, string, flags=0)
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
pattern = '^[1-9]{2,3}[a-z]$'
string = '19a'
data = re.search(pattern,string,flags=0)
print(data) # OUTPUT <_sre.SRE_Match object; span=(0, 1), match='1'> 匹配成功返回一个对象 反之返回none
获取匹配表达式 group(num) 或 groups()
匹配对象方法 | 描述 |
---|---|
group(num=0) | 匹配的整个表达式的字符串,group() 可以一次输入多个组号,在这种情况下它将返回一个包含那些组所对应值的元组 |
groups() | 返回一个包含所有小组字符串的元组,从 1 到 所含的小组号 |
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
pattern = '[1-9]{2,3}[a-z]'
string = '19a88b9999a69n'
res = re.search(pattern,string,flags=0)
if(res):
print(res.group())
else:
print('no matches')
re.match与re.search的区别
re.match只匹配字符串的开始,如果字符串开始不符合正则表达式,则匹配失败,函数返回None;而re.search匹配整个字符串,直到找到一个匹配
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
line = "Cats are smarter than dogs";
matchObj = re.match( r'dogs', line, re.M|re.I)
if matchObj:
print("match --> matchObj.group() : ", matchObj.group())
else:
print("No match!!")
matchObj = re.search( r'dogs', line, re.M|re.I)
if matchObj:
print("search --> matchObj.group() : ", matchObj.group())
else:
print("No match!!")
re.sub方法
检索与替换函数
函数语法:re.sub(pattern, repl, string, max=0)
返回的字符串是在字符串中用 RE 最左边不重复的匹配来替换。如果模式没有发现,字符将被没有改变地返回
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
pattern = r'\D'
phone = '10086-10086-10086'
print(re.sub(pattern,'',phone)) # OUTPUT 100861008610086
正则表达式修饰符 - 可选标志
修饰符 | 描述 |
---|---|
re.I | 使匹配对大小写不敏感 |
re.L | 做本地化识别(locale-aware)匹配 |
re.M | 多行匹配,影响 ^ 和 $ |
re.S | 使 . 匹配包括换行在内的所有字符 |
re.U | 根据Unicode字符集解析字符。这个标志影响 \w, \W, \b, \B. |
re.X | 该标志通过给予你更灵活的格式以便你将正则表达式写得更易于理解 |
正则表达式模式
正则表达式模式语法中的特殊元素
模式 | 描述 | |
---|---|---|
^ | 匹配字符串的开头 | |
$ | 匹配字符串的末尾 | |
. | 匹配任意字符,除了换行符,当re.DOTALL标记被指定时,则可以匹配包括换行符的任意字符 | |
[...] | 用来表示一组字符,单独列出:[amk] 匹配 'a','m'或'k' | |
[^...] | 不在[]中的字符:[^abc] 匹配除了a,b,c之外的字符 | |
re* | 匹配0个或多个的表达式 | |
re+ | 匹配1个或多个的表达式 | |
re? | 匹配0个或1个由前面的正则表达式定义的片段,非贪婪方式 | |
re{ n} | 匹配n个 | |
re{ n,} | 匹配n或者n个以上 | |
re{ n, m} | 匹配 n 到 m 次由前面的正则表达式定义的片段,贪婪方式 | |
a | b | 匹配a或b |
(re) | G匹配括号内的表达式,也表示一个组 | |
(?imx) | 正则表达式包含三种可选标志:i, m, 或 x 。只影响括号中的区域 | |
(?-imx) | 正则表达式关闭 i, m, 或 x 可选标志。只影响括号中的区域 | |
(?: re) | 类似 (...), 但是不表示一个组 | |
(?imx: re) | 在括号中使用i, m, 或 x 可选标志 | |
(?-imx: re) | 在括号中不使用i, m, 或 x 可选标志 | |
(?#...) | 注释 | |
(?= re) | 前向肯定界定符。如果所含正则表达式,以 ... 表示,在当前位置成功匹配时成功,否则失败。但一旦所含表达式已经尝试,匹配引擎根本没有提高;模式的剩余部分还要尝试界定符的右边 | |
(?! re) | 前向否定界定符。与肯定界定符相反;当所含表达式不能在字符串当前位置匹配时成功 | |
(?> re) | 匹配的独立模式,省去回溯 | |
\w | 匹配字母数字 | |
\W | 匹配非字母数字 | |
\s | 匹配任意空白字符,等价于 [\t\n\r\f] | |
\S | 匹配任意非空字符 | |
\d | 匹配任意数字,等价于 [0-9] | |
\D | 匹配任意非数字 | |
\A | 匹配字符串开始 | |
\Z | 匹配字符串结束,如果是存在换行,只匹配到换行前的结束字符串 | |
\z | 匹配字符串结束 | |
\G | 匹配最后匹配完成的位置 | |
\b | 匹配一个单词边界,也就是指单词和空格间的位置。例如, 'er\b' 可以匹配"never" 中的 'er',但不能匹配 "verb" 中的 'er' | |
\B | 匹配非单词边界。'er\B' 能匹配 "verb" 中的 'er',但不能匹配 "never" 中的 'er' | |
\n, \t, 等 | 匹配一个换行符。匹配一个制表符。等 | |
\1...\9 | 匹配第n个分组的子表达式 | |
\10 | 匹配第n个分组的子表达式,如果它经匹配。否则指的是八进制字符码的表达式 |
python正则匹配电话号码 邮箱
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import re
# 移动号段:134、135、136、137、138、139、150、151、152、157、158、159、187、188、147(数据卡)
# 联通号段: 130、131、132、155、156、185、186
# 电信号段:133、180、189
#匹配电话号码
def match_phone_num(phone):
pattern = '^1(3[0-9]|5[0-9]|8[0-9]|1[4])\d{8}$'
res = re.match(pattern,phone,flags=0)
if(res):
return(1)
else:
return(0)
# 匹配邮箱
def match_email(email):
pattern = "^([0-9A-Za-z\\-_\\.]+)@([0-9a-z]+\\.[a-z]{2,3}(\\.[a-z]{2})?)$"
res = re.match(pattern,email,flags=0)
if(res):
return(1)
else:
return(0)
phone = '15013884809'
print(match_phone_num(phone))
email = '301858962@qq.com'
print(match_email(email))
Python使用SMTP发送邮件
- SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式
- python的smtplib提供了一种很方便的途径发送电子邮件。它对smtp协议进行了简单的封装
创建stmp对象语法:smtpObj = smtplib.SMTP( [host [, port [, local_hostname]]] )
参数说明:
- host: SMTP 服务器主机。 你可以指定主机的ip地址或者域名如:w3cschool.cn,这个是可选参数
- port: 如果你提供了 host 参数, 你需要指定 SMTP 服务使用的端口号,一般情况下SMTP端口号为25
- local_hostname: 如果SMTP在你的本机上,你只需要指定服务器地址为 localhost 即可
sendmail方法
语法:SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options]
参数说明:
- from_addr: 邮件发送者地址
- to_addrs: 字符串列表,邮件发送地址
- msg: 发送消息
使用Python发送HTML格式的邮件
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
def sendEmail(to_list,sub,content,send_name):
#定义邮箱配置信息 暂时没有用到类常量
mail_host = "smtp.qq.com" # 设置服务器
mail_user = "168168168@qq.com" # 用户名
mail_pass = "ojvabcreejiuddhf" # 口令
mail_postfix = "qq.com" # 发件箱的后缀
#发件人格式 发送标题 发送邮件内容格式 字符集信息设置
me = send_name + "<" + mail_user + "@" + mail_postfix + ">" # 这里的hello可以任意设置,收到信后,将按照设置显示
msg = MIMEText(content, _subtype='html', _charset='gb2312') # 创建一个实例,这里设置为html格式邮件
msg['Subject'] = sub # 设置主题
msg['From'] = me
msg['To'] = ";".join(to_list)
try:
s = smtplib.SMTP() # 创建 stmp对象
s.connect(host=mail_host, port=25,source_address=None) # 连接smtp服务器 # def connect(self, host='localhost', port=0, source_address=None):
s.starttls()
s.login(mail_user, mail_pass) # 登陆服务器
res = s.sendmail(mail_user, to_list,msg.as_string()) # def sendmail(self, from_addr, to_addrs, msg, mail_options=[],rcpt_options=[])
except:
print('发送失败')
else:
print('发送成功')
# 调用发送邮件方法
to_list = ['1698562426@qq.com']
sub = '网上购票系统--用户支付通知'
content = "<a href='http://www.12306.cn' target='_blank'>点击查看详情</a>"
send_name = 'mike'
sendEmail(to_list,sub,content,send_name)
发送带附件邮件
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
def sendEmail(to_list,sub,content,send_name,attchment = []):
"""
发送邮件方法
:param to_list: list 收件人列表
:param sub: string 主体
:param content: string 内容
:param send_name: string 发送人名字
:param attchment: list 附件[['附件地址','附件名称(含后缀)'],]
:return: int 成功 1 失败 0
"""
#定义邮箱配置信息 暂时没有用到类常量
mail_host = "smtp.qq.com" # 设置服务器
mail_user = "3169464903@qq.com" # 用户名
mail_pass = "ojvekihaejiuddhf" # 口令
mail_postfix = "qq.com" # 发件箱的后缀
#发件人格式 发送标题 发送邮件内容格式 字符集信息设置
me = send_name + "<" + mail_user + ">" # 这里的hello可以任意设置,收到信后,将按照设置显示
msg = MIMEMultipart() # 创建MIMEMultipart对象
htmltext = MIMEText(content, _subtype='html', _charset='gb2312') # 创建一个实例,这里设置为html格式邮件
msg.attach(htmltext) # 将html正文文本添加到msg
msg['Subject'] = sub # 设置主题
msg['From'] = me # 设置发件人格式
msg['To'] = ";".join(to_list) # 设置收件人list表
# 含附件的情况
if(len(attchment)):
for val in attchment: #构造附件
att = MIMEText(open(val[0], 'rb').read(), 'base64', 'gb2312')
att["Content-Type"] = 'application/octet-stream'
att["Content-Disposition"] = 'attachment; filename= ' + val[1]#这里的filename可以任意写,写什么名字,邮件中显示什么名字
msg.attach(att)
else:
pass
try:
s = smtplib.SMTP() # 创建 stmp对象
s.connect(host=mail_host, port=25,source_address=None) # 连接smtp服务器 # def connect(self, host='localhost', port=0, source_address=None):
s.starttls()
s.login(mail_user, mail_pass) # 登陆服务器
res = s.sendmail(mail_user, to_list,msg.as_string()) # def sendmail(self, from_addr, to_addrs, msg, mail_options=[],rcpt_options=[])
except:
print('发送失败')
return (0)
else:
print('发送成功')
return (1)
# 调用发送邮件方法
to_list = ['1536592426@qq.com']
sub = '网上购票系统--用户支付通知'
content = "<a href='http://www.12306.cn' target='_blank'>点击查看详情</a>"
send_name = 'mike'
attchment = [['E:\\demo.jpg','123.jpg'],] # 二维列表 [['文件地址','文件名称(含后缀)']]
sendEmail(to_list,sub,content,send_name,attchment)
Python 网络编程
Python 提供了两个级别访问的网络服务:
- 低级别的网络服务支持基本的 Socket,它提供了标准的 BSD Sockets API,可以访问底层操作系统Socket接口的全部方法
- 高级别的网络服务模块 SocketServer, 它提供了服务器中心类,可以简化网络服务器的开发
Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯
socket()函数:
Python 中,我们用 socket()函数来创建套接字
语法:socket.socket([family[, type[, proto]]])
参数:
- family: 套接字家族可以使AF_UNIX或者AF_INET
- type: 套接字类型可以根据是面向连接的还是非连接分为SOCK_STREAM或SOCK_DGRAM
- protocol: 一般不填默认为0
Socket 对象(内建)方法
函数 | 描述 |
---|---|
服务器端套接字 | |
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了 |
s.accept() | 被动接受TCP客户端连接,(阻塞式)等待连接的到来 |
客户端套接字 | |
s.connect() | 主动初始化TCP服务器连接,。一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误 |
s.connect_ex() | connect()函数的扩展版本,出错时返回出错码,而不是抛出异常 |
公共用途的套接字函数 | |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常 |
s.recvform() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数 |
s.close() | 关闭套接字 |
s.getpeername() | 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port) |
s.getsockname() | 返回套接字自己的地址。通常是一个元组(ipaddr,port) |
s.setsockopt(level,optname,value) | 设置给定套接字选项的值 |
s.getsockopt(level,optname[.buflen]) | 返回套接字选项的值 |
s.settimeout(timeout) | 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如connect()) |
s.gettimeout() | 返回当前超时期的值,单位是秒,如果没有设置超时期,则返回None |
s.fileno() | 返回套接字的文件描述符 |
s.setblocking(flag) | 如果flag为0,则将套接字设为非阻塞模式,否则将套接字设为阻塞模式(默认值)。非阻塞模式下,如果调用recv()没有发现任何数据,或send()调用无法立即发送数据,那么将引起socket.error异常 |
s.makefile() | 创建一个与该套接字相关连的文件 |
服务端
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
host = socket.gethostname() # 获取本地主机名
port = 12309 # 设置端口
s.bind((host, port)) # 绑定端口
s.listen(5) # 等待客户端连接
while True:
c, addr = s.accept() # 建立客户端连接。
print('连接地址:', addr)
c.send('大数据的前景还可以,加油,骚年!!!'.encode())
c.close() # 关闭连接
客户端
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import socket # 导入 socket 模块
s = socket.socket() # 创建 socket 对象
host = socket.gethostname() # 获取本地主机名
port = 12309 # 设置端口好
s.connect((host, port))
print(s.recv(1024).decode())
s.close()
Python Internet 模块
协议 | 功能用处 | 端口号 | Python 模块 |
---|---|---|---|
HTTP | 网页访问 | 80 | httplib, urllib, xmlrpclib |
NNTP | 阅读和张贴新闻文章,俗称为"帖子" | 119 | nntplib |
FTP | 文件传输 | 20 | ftplib, urllib |
SMTP | 发送邮件 | 25 | smtplib |
POP3 | 接收邮件 | 110 | poplib |
IMAP4 | 获取邮件 | 143 | imaplib |
Telnet | 命令行 | 23 | telnetlib |
Gopher | 信息查找 | 70 | gopherlib, urllib |
Python 多线程
多线程类似于同时执行多个不同程序,多线程运行有如下优点:
- 使用线程可以把占据长时间的程序中的任务放到后台去处理
- 用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
- 程序的运行速度可能加快
- 在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下我们可以释放一些珍贵的资源如内存占用等等
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
每个线程都有他自己的一组CPU寄存器,称为线程的上下文,该上下文反映了线程上次运行该线程的CPU寄存器的状态。
指令指针和堆栈指针寄存器是线程上下文中两个最重要的寄存器,线程总是在进程得到上下文中运行的,这些地址都用于标志拥有线程的进程地址空间中的内存
- 线程可以被抢占(中断)
- 在其他线程正在运行时,线程可以暂时搁置(也称为睡眠) -- 这就是线程的退让
什么是进程:
进程是指在操作系统中正在运行的一个应用程序,线程是指进程内独立执行某个任务的一个单元
image.png
Python中使用线程的两种方式:函数或者用类来包装线程对象
函数式:调用thread模块中的start_new_thread()函数来产生新线程
语法:thread.start_new_thread ( function, args[, kwargs] )
参数说明:
- function - 线程函数
- args - 传递给线程函数的参数,他必须是个tuple类型
- kwargs - 可选参数
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import _thread # python3 改成用_thread模块使用进程,thread已丢弃使用
import time
# 为线程定义一个函数
def print_time( threadName, delay):
count = 0
while count < 5:
time.sleep(delay)
count += 1
print("%s: %s" % ( threadName, time.ctime(time.time()) ))
# 创建两个线程
try:
_thread.start_new_thread( print_time, ("Thread-1", 2, ) )
_thread.start_new_thread( print_time, ("Thread-2", 4, ) )
except:
print("Error: unable to start thread")
while 1: # 定义一个无限循环避免脚本执行结束
pass
线程的结束一般依靠线程函数的自然结束;也可以在线程函数中调用thread.exit(),他抛出SystemExit exception,达到退出线程的目的
线程模块
Python通过两个标准库thread和threading提供对线程的支持。thread提供了低级别的、原始的线程以及一个简单的锁。threadding相当于是thread的升级版,python3中丢弃了thread用_thread替代
thread 模块提供的其他方法:
- threading.currentThread(): 返回当前的线程变量
- threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程
- threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果
除了使用方法外,线程模块同样提供了Thread类来处理线程,Thread类提供了以下方法:
- run(): 用以表示线程活动的方法
- start():启动线程活动
- join([time]): 等待至线程中止。这阻塞调用线程直至线程的join() 方法被调用中止-正常退出或者抛出未处理的异常-或者是可选的超时发生
- isAlive(): 返回线程是否活动的
- getName(): 返回线程名
- setName(): 设置线程名
使用Threading模块创建线程
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import threading
import _thread
import time
exitFlag = 0
class myThread (threading.Thread): #继承父类threading.Thread
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.counter = counter
def run(self): #把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
print("Starting " + self.name)
print_time(self.name, self.counter, 5)
print("Exiting " + self.name)
def print_time(threadName, delay, counter):
while counter:
if exitFlag:
_thread.exit()
time.sleep(delay)
print("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启线程
thread1.start()
thread2.start()
print("Exiting Main Thread")
线程同步
如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步。
使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire方法和release方法,对于那些需要每次只允许一个线程操作的数据,可以将其操作放到acquire和release方法之间。如下:
多线程的优势在于可以同时运行多个任务(至少感觉起来是这样)。但是当线程需要共享数据时,可能存在数据不同步的问题。
考虑这样一种情况:一个列表里所有元素都是0,线程"set"从后向前把所有元素改成1,而线程"print"负责从前往后读取列表并打印。
那么,可能线程"set"开始改的时候,线程"print"便来打印列表了,输出就成了一半0一半1,这就是数据的不同步。为了避免这种情况,引入了锁的概念。
锁有两种状态——锁定和未锁定。每当一个线程比如"set"要访问共享数据时,必须先获得锁定;如果已经有别的线程比如"print"获得锁定了,那么就让线程"set"暂停,也就是同步阻塞;等到线程"print"访问完毕,释放锁以后,再让线程"set"继续。
经过这样的处理,打印列表时要么全部输出0,要么全部输出1,不会再出现一半0一半1的尴尬场面
感觉有点像是mysql的锁机制
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import threading
import time
class myThread (threading.Thread):
def __init__(self, threadID, name, counter):
threading.Thread.__init__(self) # 继承的thread构造函数不会指定允许,需要在当前构造函数调用一次
self.threadID = threadID
self.name = name
self.counter = counter
def run(self):
print("Starting " + self.name)
# 获得锁,成功获得锁定后返回True
# 可选的timeout参数不填时将一直阻塞直到获得锁定
# 否则超时后将返回False
threadLock.acquire()
print_time(self.name, self.counter, 3)
# 释放锁
threadLock.release()
def print_time(threadName, delay, counter):
while counter:
time.sleep(delay)
print("%s: %s" % (threadName, time.ctime(time.time())))
counter -= 1
threadLock = threading.Lock()
threads = []
# 创建新线程
thread1 = myThread(1, "Thread-1", 1)
thread2 = myThread(2, "Thread-2", 2)
# 开启新线程
thread1.start()
thread2.start()
# 添加线程到线程列表
threads.append(thread1)
threads.append(thread2)
# 等待所有线程完成
for t in threads:
t.join()
print("Exiting Main Thread")
线程优先级队列( Queue)
Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步
Queue模块中的常用方法:
- Queue.qsize() 返回队列的大小
- Queue.empty() 如果队列为空,返回True,反之False
- Queue.full() 如果队列满了,返回True,反之False
- Queue.full 与 maxsize 大小对应
- Queue.get([block[, timeout]])获取队列,timeout等待时间
- Queue.get_nowait() 相当Queue.get(False)
- Queue.put(item) 写入队列,timeout等待时间
- Queue.put_nowait(item) 相当Queue.put(item, False)
- Queue.task_done() 在完成一项工作之后,Queue.task_done()函数向任务已经完成的队列发送一个信号
- Queue.join() 实际上意味着等到队列为空,再执行别的操作
#!/usr/bin/python
# -*- coding: UTF-8 -*-
from queue import Queue # 引入Queue队列模块
import threading # 引入线程模块
import time # 引入时间模块
exitFlag = 0 # 初始化属性
class myThread (threading.Thread): # 定义类 继承线程模块类
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self): # 把要执行的代码写到run函数里面 线程在创建后会直接运行run函数
print("Starting " + self.name)
process_data(self.name, self.q)
print("Exiting " + self.name)
def process_data(threadName, q):
while not exitFlag: # 只要 exitFlag不为0循环将继承
queueLock.acquire() # 获得锁,成功获得锁定后返回True
if not workQueue.empty(): # 队列不为空情况下执行下面操作
data = q.get() # 获取队列
# print(data)
# exit()
queueLock.release() # 释放锁
print("%s processing %s" % (threadName, data))
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock() # 创建锁对象
workQueue = Queue(10) # 创建队列对象设定队列最大大小
threads = [] # 数据初始化
threadID = 1 # 数据初始化
# 创建新线程
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# 填充队列
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# 等待队列清空
while not workQueue.empty():
pass
# 通知线程是时候退出
exitFlag = 1
# 等待所有线程完成
for t in threads:
t.join()
print("Exiting Main Thread")
什么是协成:
简单点说协程是进程和线程的升级版,进程和线程都面临着内核态和用户态的切换问题而耗费许多切换时间,而协程就是用户自己控制切换的时机,不需要再陷入系统的内核态
GIL线程全局锁:
线程全局锁(Global Interperter Lock),即Python为了保证线程安全而采用的独立线程运行的限制,说白了就是一个核只能在同一时刻运行一个线程。
解决办法就是多进程和协程(协程也只是单CPU,但是能减小切换代价提升性能)。
Python JSON
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写
JSON 函数
使用 JSON 函数需要导入 json 库:import json
函数 | 描述 |
---|---|
json.dumps | 将 Python 对象编码成 JSON 字符串 |
json.loads | 将已编码的 JSON 字符串解码为 Python 对象 |
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import json
# python字典
data = {
'id': 1,
'name': 'test1',
'age': '1'
}
# python列表
data2 = [{
'id': 1,
'name': 'test1',
'age': '1'
}, {
'id': 2,
'name': 'test2',
'age': '2'
}]
# python 字典转json
json_str = json.dumps(data)
print(type(json_str))
print("python原始字典数据:", repr(data)) # repr() 的作用是是将一个对象转成字符串显示,只做显示用,repr()输出对 Python比较友好,repr()之后的字符串保证可以用eval()还原
print("字典转成的json对象:", json_str)
# python 列表转json
json_str2 = json.dumps(data2)
print(type(json_str2))
print("python原始列表数据:", repr(data2)) # repr() 的作用是是将一个对象转成字符串显示,只做显示用,repr()输出对 Python比较友好,repr()之后的字符串保证可以用eval()还原
print("列表转成的json对象:", json_str2)
# 将json对象转换为python字典
data3 = json.loads(json_str)
print(data3)
# 将json对象转换为python列表
data4 = json.loads(json_str2)
print(data4)
使用第三方库:Demjson
如果没有内置Demjson库,则需要通过pip安装
JSON 函数
函数 | 描述 |
---|---|
encode | 将 Python 对象编码成 JSON 字符串 |
decode | 将已编码的 JSON 字符串解码为 Python 对象 |
#!/usr/bin/python
# -*- coding: UTF-8 -*-
import demjson # 引入 demjson模块
# 列表
datalist = [ { 'a' : 1, 'b' : 2, 'c' : 3, 'd' : 4, 'e' : 5 } ]
# 字典
datadict = {'name':'mike','age':18}
# 列表转json
jsonlist = demjson.encode(datalist)
print(jsonlist)
# 字典转json
jsondict = demjson.encode(datadict)
print(jsondict)
Python XML
备注:xml有点麻烦,而且在目前前后端对接的过程中基本不用,就不展开了
网友评论