《从Python开始学编程》第5章 对象带你飞

在上一章,我们了解到Python一切皆对象,那么在这一章,我们将了解更多的Python对象。同时,我们还将了解几个常用的Python库。

1 存储

在电脑中的操作系统中,一般都是以文件的形式存储数据。所以我们利用Python来存储对象,就需要先创建文件对象:

f = open(文件位置, 读取方法)

这里文件位置是指文件放置的相对路径或绝对路径。读取方法分为:'r'为只读;'w'为写入,如果当前位置没有改文件则新建文件,如果存在重名文件,则对其覆盖;'a'和'w'相似,只是如果存在重名文件,则在文件的末尾添加内容。比如我们在项目路径内创建一个只读对象:

f = open('sample.txt', 'r')

有了文件后,如果该文件确实在路径中存在,且有内容,我们可以利用文件对象中的三种方法读取文件内容:

words = f.read(10)  # 读取该文件的10个字节
words = f.readline()  # 读取该文件一行
words = f.readlines()  # 读取文件所有内容,按列表存储,每个元素为一行

如果为新创建文件,我们想往文件中写入内容,我们可以利用文件对象的wirte方法,且字符创串中用特殊字符表示换行:

f.write('the content write in document')  # 写入文件
f.write('the content write in document \n')  # UNIX系统的换行符
f.write('the content write in document \r\n')  # Windows下的换行符

因为创建文件对象需要花费计算机资源,所以在使用完毕后要利用文件的close方法关闭文件:

f.close()  # 关闭文件

其实纯使用上述的文件对象控制方法,在做较大工程时容易忘记关闭文件,经常使程序崩溃。Python提供上下文管理器,将打开文件的操作限制在一个缩进的范围内,一旦出去范围,便自动关闭文件对象。上下文管理器采用withas两个关键字组合。假设现在我们要把内容写入文件,如果用之前的方法应当这么写:

f = open('text.txt', 'w')
print(f.closed)
f.wirte('hello world')

f.close()
print(f.close())

利用上下文管理器可以简化代码这么写:

with open('text.txt', 'w') as f:
    f.write('hello world')
    print(f.closed)

这里,当执行完毕第二行代码时,文件便自动关闭。其实上下文管理器和函数等类似,其在类中有__exist__(), __enter__()这两个内置方法,下面举个例子:

class task(object):

def __init__(self, text):  # 初始化对象调用方法
    self.text = text

def __enter__(self):  # 打开文件时调用方法
    self.text = self.text
    return self

def __exit__(self, exc_type, exc_value, traceback):  # 关闭文件调用方法
    self.text = self.text+'!'


with task('I'm fine') as my_task:
    print(my_task.text)
    print(my_task.text)
# 输出结果:
# I'm fine
# I'm fine!

只要类中有enterexit这两个方法定义,就可以使用上下文。在使用with.as.时,首先调用init方法。之后调用enter方法,将enter的返回对象将作为as后指代的变量,这里写的是self,也就是自己类。最后关闭文件时调用exit方法,除了self,后三个参数exc_type, exc_value, traceback都是程序异常的变量,如果运行正常,它们的值为None。

之前我们讲过函数的定义存储和调用,在直到Python有许多对象后,应当了解,类也可以储存和调用。Python提供pickle函数包,利用其dumps方法可以把对象转换为文本流,再将其写入文件中。

import pickle

class Bird(object):
feather = True
reproduction = 'egg'
spring = Bird()
pickle_string = pickle.dump(spring)  # 转换成文本流

with open('sample.pkl', 'wb') as f:  # 写入文件
    f.write(pickle_string)

上述两个步骤也可以一步完成,在定义好类后,可以这么写:

spring = Bird()
with open('sample.pkl, 'w') as f:
    pickle.dump(spring, f)  # 序列化后保存对象

这个类已经保存在磁盘,现在只需要反向调用就好,我们可以使用open打开.pkl文件后利用pikle的loads方法将字节流转换成对象。光反向恢复对象还不行,Python要求程序中必须有其对应的已经定义的类。所以我们需要再把类定义一遍,就可以引用了:

import pickle

class Bird(object):  # 重新定义一遍类
feather = True
reproduction = 'egg'

with open('spring.pkl','rb') as f:  # 引用保存的对象
    spring = pickle.load(f)
print(spring.feather)

2 time和datetime库

这两个库是Python的内置库,可以调用系统的时间。在计算机的主板上有一个计时表,它会不停的计算时间,依据这个硬件,计算机系统便有了挂钟时间,它是一个固定时间到现在的时间间隔。此外,计算机还可以测量CPU运行时间,也即处理器时间。当CPU空闲时,事件处理器也会暂停。而Python的time库是可以调用这两个东西的,我们接下来详细讲讲。

首先是挂钟时间,我们可以使用time方法得到,单位是秒,可以利用它测量程序运行时间。我们还可以利用clock方法得知程序的运行速度。下面举个例子:

import time

print(time.time())  # 查看挂钟时间
start = time.clock()

for i in range(10000):
    j = 1

end = time.clock()
print(end-start)

每使用一次clock,就会记录一次当前的时间,UNIX系统记录的是CPU时间,而Windows系统记录挂钟时间。也就是说在Windows系统,使用clock方法和time方法是一样的。但请注意,clock方法在3.8后的版本已经被废除不能使用,需要改用perf_counterprocess_time才可以。

我们还可以利用`time`包设置时间格式。利用`struct_time`对象,我们可以得到`tm_year`, `tm_ month`等属性。下面的方法可以将挂钟时间转换成`struct_time`对象:
st = time.gmtime()  # 返回struct_time的UTC时间
st = time.localtime()  # 返回当地时间,有系统所在环境决定

也可以反过来,经struct_time转换成time对象:

t = time.mktime(st)

在了解time库后,我们来学习datetime库。其实它是比time更牛的库,能够更加方便的获取时间。顾名思义,它是由date和time两个对象组成,更有将两者融合的datetime对象,我着重讲解这个,其他的用法类似。我们现在就来写写,比如我现在要输出2019年7月13日22点35分,可以这么写:

import datetime

t = datetime.datetime(2019, 7, 13, 22, 35)
print(t)

datetime对象有hour, minute, second, millisecond, microsecond对应time的小时、分、秒、毫秒、微妙,有year, month, day,``weekday对应date的年、月、日、星期,这些属性。借助这些属性,我们可以进行时间的数学运算,得到时间间隔。举个例子:

import datetime

t = datetime.datetime(2019, 7, 13, 22, 35)
t_next = datetime.datetime(2019, 7, 13, 23, 35)
delta1 = datetime.timedelta(seconds = 600)
delta2 = datetime.timedelta(weeks = 3)
print(t+delta1)
print(t+delta2)
print(t_next-t)

timedelta就是时间间隔,里面的属性就是刚才列出的那些,加上s即可。此外利用datetime对象还可以做比较运算:

print(t>t_next)

datetime的强大之处在于可以设置时间格式,我们可以先设置一个format,再利用strptime方法改变格式。下面举个例子:

from datetime import datetime

str = 'output-2019-7-13-230300'  # 要识别的日期
format = 'output-%Y-%m-%d-%H%M%S'  # 日期格式
t = datetime.strptime(str,format)  # 使用方法

print(t)

可以看到format内使用了%转义,除了上面的年月日时分秒,还有其他转义:%A表示英文星期几,%a表示简写英文星期几,%I表示十二小时制,%p表示上午或下午(AM, PM),%f表示毫秒(2, 0014, 000001),%%表示百分号。

除此之外,我们还可以将datetime对象用strftime方法装换成指定格式的字符串。举个例子:

from datetime import datetime

format = '%Y-%m-%d %H:%M'
t = datetime(2019, 7, 13, 23, 50)
print(t.strftime(format))

这里,strftime方法会根据datetime的参数一次排入format%特殊字符中,形成指定格式的字符串时间输出。

3 正则表达式

正则表达式是一个定义好的字符串特定的模式,用于搜索指定格式的字符串内容。Python中可以使用re包处理正则表达式,我们可通过其search方法进行正则匹配。其中search的第一个参数是正则表达式,第二个是要寻找的字符串。然后在利用正则对象的group方法查看搜索结果。举个例子:

import re

m = re.search('[0-9]', 'abcde4f')
print(m.group(0))

如果找不到,search会返回None,可以通过条件判断检查。除了search,match方法也可以查找,唯一的区别是它会从头开始找是否符合,必须从第一个字符串开始就要匹配,否则就是不符合要求,返回None。

刚刚有一个正则表达式[0-9]是代表任意0-9数字字符串,下面将罗列常用的正则表达式:

.  # 任意字符
a|b  # 字符a或字符b
[afg]  # afg当中的一个字符
[0-4]  # 0-4范围的一个字符
[a-f]  # a-f中的一个字符
[^m]  # 不是m的字符
\s  # 一个空格
\S  # 一个非空格
\d  # 一个数字
\D  # 一个非数字,等价于[^0-9]
\w  # 数字或字母
\W  # 非数字或字母,等价于[^0-9a-zA-Z]

除此之外,正则表达式还有很多特殊符号,跟在一个字符后表示特殊意义:

*  # 重复超过0次
+  # 重复1次或超过1次
?  # 重复0次或1次
{m}  # 重复m次
{m,n}  # 重复m到n次

正则表达式用以下两个表示位置:

^  # 起始位置
$  # 结尾位置

下面我们来提取几个试试:

[0-9]{3, 5}  # 表示字符串有连续3到5个的1到9数字,如:87978
a?b  # 表示字符串有连续0或1个a,后连1个b,如:ab或b
a+b  # 表示字符串有连续1个或以上的a,后跟1个b,如:aaaab

我们可以通过更详细的表达获取字符串一部分,例如:

import re

str = 'aaaaaadsfdfwefseftime_2019sdkfuhwifsoidjaf'
str.search('time_(?P<year>\d{4})', str)
print(str.group(1))
print(str.group('year'))

这里有几个新内容需要解释。首先正则表达式出现'time_'意思就是寻找以这个开头的字符串,就是其一部分。正则后面的意思是连续4个数字,外面用小括号括起,代表这是提取中进一步筛选的信息。记得之前使用group(0)得到结果,其实这个得到的是整体结果,可以用group(1)得到第1个筛选结果,以此类推。在括号开头有'?p<year>',这是给筛选信息取名,这里的名字是year,利用group得到信息时可以使用year来提取。所以这两种输出方法是一样的。

4 Python网络编程

计算机可以通过网络进行信息交互,而最常用的网络交互协议就是HTTP协议。所以利用Python做网络编程,首先要学会使用HTTP协议。一般计算机会这么发送消息:

GET /index.html HTTP/1.1

Host: www.example.com

其中get方法是服务器获取信息的操作,后面带有/的是路径,1.1是HTTP协议的版本。之后服务器接到请求并回复:

HTTP/1.1 200 OK

Content-Type:text/plain

Content-length:12

Hello World!

回复中200是状态码,OK是状态码的具体描述,表示一切正常。还有其他的码,比如302代表要重定向,404代表找不到。type意为资源类型,text/plain是文本类型,此外还有text/html是HTML文本,image/jpeg是JPEG图片,image/gif是GIF图片,length是得到文本的长度。

在Python中,我们利用HTTP的client库实现HTTP通信,下面举个例子:

import http.client

conn = http.client.HTTPConnection('*www.example.com*')
conn.request('GET', '/')

response = conn.getresponse()
print(response.status, response.reason)

content = response.read()
print(connnect)

这里首先连接网址,并利用request方法,采用GET方法得到数据,/是路径位置。接着利用getresponse方法得到回复,而回复的对象又有很多属性,status是状态码,reason是状态描述。最后我们利用对象的read方法得到具体内容并输出。

虽然这是个简单的应用,但包括HTTP通信的全部步骤,包括获取信息和得到信息。

5 Python爬虫

利用前面所学知识,我们现在可以写一个网络爬虫进行综合运用。网络爬虫顾名思义就是像一只虫子一样在网络上爬取我们想要的信息。我们可以先通过网络通讯获取网页内容,再利用正则表达式筛选内容,利用datetime库获取相应时间,最后把这些信息总结保存到磁盘文件中。现在我们来试试吧。

import http.client
import re

# 网络通信
conn = http.client.HTTPSConnection('www.cnblogs.com')
conn.request('GET', '/vamei')
response = conn.getresponse()
content = response.read().decode('utf-8')
content = content.split('\n') # 将字符串分隔成序列

# 正则提取
for line in content:
    m = re.search('@', line)
    if m != None:
        print(line)

程序中,我们首先导入包。利用client包获取信息并利用split分隔,利用正则表达式,获取评论的时间,然后在列表中逐个字符串寻找并输出筛选信息。

实例代码请看我的码云:第五章样例代码

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 了解面向对象编程的基础之后,我们就可以利用Python中多种多样的对象。 1、存储 1)文件 磁盘以文件为单位...
    Guodw阅读 133评论 0 0
  • 5.1 存储 1.文件 为了长期持续的存储文件,可以用Python将数据文件保存。Python能够借助文本对象来读...
    D系鼎溜阅读 444评论 0 0
  • 5.1 存储 1. 文件 为了长期持续地存储数据,Python必须把数据以文件的方式存储在磁盘中。Python借助...
    尘濯阅读 299评论 1 2
  • 一、存储 .文本 。Python中的数据都保存在内存中,内存中的数据就会消失。而且,如果Python程序运行结束,...
    mAbbQi阅读 429评论 0 1
  • 5.1储存 1.文件 通过内置函数open来创建文件对象 f=open(文件名,方式) 打开文件的常用方式P107...
    lammmya阅读 129评论 0 0