【Python】编程笔记11

常用内置模块

一、datetime模块

datetime模块:处理日期和时间的标准库。
epoch time:1970 年 1 月 1 日 00:00:00 UTC+00:00 时区的时刻;
timestamp:当前时间相对于 epoch time 的秒数。

from datetime import datetime, timedelta, timezone
# tzinfo:时区属性

# 获取当前 datetime
now = datetime.now()
print(now)
print(type(now))

# 用指定日期和时间创建datetime
dt = datetime(2019,1,1,0,0)
print(dt)

# datetime 转换为 timestamp(浮点数,单位:秒)
# 若存在小数位,小数位表示毫秒数
dt = datetime(2019,1,1,8,8)
print(dt.timestamp())

## timestamp 转换为 datetime
# 时间转换是 timestamp 与本地时间做转换
t = 1546301280.0
print(datetime.fromtimestamp(t))    # 本地时间
## 转换到 UTC 标准时区的时间
print(datetime.utcfromtimestamp(t)) # UTC 时间

## str ==》datetime
cday = datetime.strptime('2019-1-1 18:28:30','%Y-%m-%d %H:%M:%S')
print(cday)

## datetime ==》str
now = datetime.now()
print(now.strftime('%a, %b %d %H:%M'))

## datetime 加减
now = datetime.now()
print(now)
print(now + timedelta(hours=10))
print(now - timedelta(days=1))
print(now + timedelta(days=2, hours=12))

## 强制设置时区:本地时间 ==》UTC 时间
# 本地时间:系统设定时区的时间
# UTC 时间:UTC+0:00 时区的时间
tz_utc_8 = timezone(timedelta(hours=10))
now = datetime.now()
print(now)
dt = now.replace(tzinfo=tz_utc_8)  # 强制设置为 utc+8:00
print(dt)

## 时区转换
# 步骤:1.utcnow()获取当前utc时间;2.astimezone()转换到任意时区时间
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt)
# astimezone()将转换时区为北京时间
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt)
# astimezone()将转换时区为东京时间
tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt)
# astimezone()将 bj_dt 转换时区为东京时间
tokyo_dt2 = bj_dt.astimezone((timezone(timedelta(hours=9))))
print(tokyo_dt2)

import re
def to_timestamp(dt_str, tz_str):
    dt = datetime.strptime(dt_str, "%Y-%m-%d %H:%M:%S")
    pattern = re.compile(r"UTC(.+?):")
    tzstr = pattern.match(tz_str).group(1)
    tz = timezone(timedelta(hours=int(tzstr)))
    dttz = dt.replace(tzinfo=tz)
    return dttz.timestamp()


t1 = to_timestamp('2015-6-1 08:10:30', 'UTC+7:00')
assert t1 == 1433121030.0, t1
t2 = to_timestamp('2015-5-31 16:10:30', 'UTC-09:00')
assert t2 == 1433121030.0, t2
print('Pass')

结果输出

2018-12-25 09:39:32.382525
<class 'datetime.datetime'>
2019-01-01 00:00:00
1546301280.0
2019-01-01 08:08:00
2019-01-01 00:08:00
2019-01-01 18:28:30
Tue, Dec 25 09:39
2018-12-25 09:39:32.385442
2018-12-25 19:39:32.385442
2018-12-24 09:39:32.385442
2018-12-27 21:39:32.385442
2018-12-25 09:39:32.385442
2018-12-25 09:39:32.385442+10:00
2018-12-25 01:39:32.385513+00:00
2018-12-25 09:39:32.385513+08:00
2018-12-25 10:39:32.385513+09:00
2018-12-25 10:39:32.385513+09:00
Pass

二、collections模块

集合模块,提供集合类

1、namedtuple() 函数

tuple的子类,用于创建自定义的 tuple 对象,并规定 tuple 元素的个数,可用属性来引用 tuple 的某个元素。

from collections import namedtuple
# namedtuple('名称', [属性list])
## 定义 Point
Point = namedtuple('Point',['x', 'y'])
p = Point(1, 2)
print(p.x)
print(p.y)
## 定义 Circle
Circle = namedtuple('Circle', ['x','y','r'])
c = Circle(3,5,9)
print(c.x, c.y, c.r)
print(isinstance(p, Point))
print(isinstance(p, tuple))

结果输出

1
2
3 5 9
True
True

2、deque() 函数

可高效实现插入和删除操作的双向列表,适用于队列和栈。

除了实现 list 的 append()和 pop()外,还支持 appendleft() 和 popleft() ==》非常高效地往头部添加或删除元素。

from collections import deque
q = deque(['a', 'b', 'c'])
q.append('x')
q.appendleft('y')
print(q)

结果输出

deque(['y', 'a', 'b', 'c', 'x'])

3、defaultdict() 函数

defaultdict()函数:当 Key 不存在时,返回一个默认值。其余与dict一样。

注意:默认值是调用函数返回的,而函数在创建 defaultdict 对象时传入。

from collections import defaultdict
dd = defaultdict(lambda : 'N/A')
dd['key1'] = 'abc'
print(dd['key1'])
print(dd['key2'])

结果输出

abc
N/A

4、OrderedDict() 函数

OrderedDict 的 Key 会按照插入的顺序排列,不是 Key 本身排序。

from collections import OrderedDict
d = dict([('a',1),('c',3),('b',2)])
print(d)
od = OrderedDict([('a',1),('c',3),('b',2)])
print(od)
od1 = OrderedDict()
od1['z'] = 1
od1['y'] = 2
od1['x'] = 3
print(list(od1.keys()))

结果输出

{'a': 1, 'c': 3, 'b': 2}
OrderedDict([('a', 1), ('c', 3), ('b', 2)])
['z', 'y', 'x']

使用 OrderedDict 实现一个 FIFO(先进先出)的 dict,当容量超出限制时,先删除最早添加的 Key。

from collections import OrderedDict

class LastUpdatedOrderedDict(OrderedDict):
    def __init__(self, capacity):
        super(LastUpdatedOrderedDict, self).__init__()
        self._capacity = capacity
        
    def __setitem__(self, key, value):
        containsKey = 1 if key in self else 0
        if len(self) - containsKey >= self._capacity:
            last = self.popitem(last=False)
            print('remove: ',last)
        if containsKey:
            del self[key]
            print('set:',(key, value))
        else:
            print('add:', (key, value))
        OrderedDict.__setitem__(self, key, value)

5、Counter() 函数

作用:计数器

## 统计字符出现的个数
from collections import Counter
c = Counter()
for ch in 'programming':
    c[ch] = c[ch] + 1
print(c)

结果输出

Counter({'r': 2, 'g': 2, 'm': 2, 'p': 1, 'o': 1, 'a': 1, 'i': 1, 'n': 1})

三、struct模块

作用:解决 bytes 和其他二进制数据类型的转换。

import struct
print(struct.pack('>I', 10240099))
# b'\x00\x9c@c'
# >IH 的说明,后面的 bytes 依次变为 I:4 字节无符号整数和
#  H: 2 字节无符号整数。
print(struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80'))

参数:pack第一个参数是处理指令。
‘>I’表示:>表示字节顺序是 big-endian,也就是网络序, I 表示 4 字节无符号整数。后面的参数个数要和处理指令一致。

四、hashlib模块

提供常见的摘要算法(哈希算法、散列算法),eg:MD5、SHA1等。修改一小点,结果完全不同。单向函数。

通过一个函数将任意长度的数据转换为一个长度固定的数据串(通常用16进制的字符串表示)。

1、MD5

MD5 是最常见的摘要算法,速度很快,生成结果是固定的 128 bit 字节,通常用一个 32 位的 16 进制字符串表示。

import hashlib
md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
## 多次调用 update()
md5 = hashlib.md5()
md5.update('how to use md5 in '.encode('utf-8'))
md5.update('python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
## 改动一个字母
md5.update('how to use md5 in python hashlid?'.encode('utf-8'))
print(md5.hexdigest())

## 结果输出
# d26a53750bc40b38b65a520292f69306
# d26a53750bc40b38b65a520292f69306
# 9ac2e3728468630f3d1aecc058e78dff

2、SHA1

结果是 160 bit 字节,通常用一个 40 位的 16 进制字符串表示。

sha1 = hashlib.sha1()
sha1.update('how to use md5 in '.encode('utf-8'))
sha1.update('python hashlib?'.encode('utf-8'))
print(sha1.hexdigest())

## 结果输出
# b752d34ce353e2916e943dc92501021c8f6bca8c

注意:可能出现两个不同的数据通过某个摘要算法得到相同的摘要,只是非常困难。

3、应用:密码存储与校验

摘要算法不是加密算法,不能用于加密(因为无法通过摘要反推明文),只能用于防篡改或者验证用户口令。

import hashlib
db = {
'michael': 'e10adc3949ba59abbe56e057f20f883e',
'bob': '878ef96e86145580c38c87f0410ad153',
'alice': '99b1c2188db85afee403b1536010c2c9'
}
def login(user, password):
    ps_md5 = hashlib.md5()
    ps_md5.update(password.encode('utf-8'))
    if ps_md5.hexdigest() == db[user]:
        return True
    else:
        return False
print(login('bob','abc999'))

更安全方法:通过对原始口令加一个复杂字符串来实现,俗称“加盐”
eg:添加固定字符串、将不变的用户名作为salt的一部分。

根据用户输入的登录名和口令模拟用户注册,计算更安全的 MD5

import hashlib, random

def get_md5(s):
    return hashlib.md5(s.encode('utf-8')).hexdigest()

class User(object):
    def __init__(self, username, password):
        self.username = username
        self.salt = ''.join([chr(random.randint(48, 122)) for i in range(20)])
        self.password = get_md5(password + self.salt)
db = {
        'michael': User('michael', '123456'),
        'bob': User('bob', 'abc999'),
        'alice': User('alice', 'alice2008')
    }

def login(username, password):
    user = db[username]
    return user.password == get_md5(password + user.salt)
assert login('michael', '123456')
assert login('bob', 'abc999')
assert login('alice', 'alice2008')
assert not login('michael', '1234567')
assert not login('bob', '123456')
assert not login('alice', 'Alice2008')
print('ok')
## ok

五、itertools 模块

itertools 模块提供用于迭代对象的函数。返回值为 Iterator,需要用 for 循环迭代获取元素。

1、“无限”迭代器

  • itertools.count(5):从5开始的自然数序列。
    ==》5,6,7,8,9,10,11,12,13…
  • itertools.cycle(‘ABC’):将一个序列无限重复下去。
    ==》‘A’,‘B’,‘C’,‘A’,‘B’,‘C’,‘A’,‘B’,‘C’…
  • itertools.repeat():将一个元素无限重复下去,第二个参数可以限定重复次数。
  • 注意无限序列只有在 for 迭代时才会无限迭代下去,但是通常通过 takewhile() 等函数根据条件判断来截取一个有限的序列。
import itertools
natuals = itertools.count(1)
ns = itertools.takewhile(lambda x: x <= 10, natuals)
print(list(ns))

结果输出

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

2、chain() 迭代器

可以将一组迭代对象串联起来,形成一个更大的迭代器

for c in itertools.chain('ABC', 'XYZ'):
	print(c)
# 迭代效果: 'A' 'B' 'C' 'X' 'Y' 'Z'

3、groupby() 迭代器

将相邻的重复元素挑出来放在一起。

for key, group in itertools.groupby('AAAaaaaaBBBbcCCAAa'):
    print(key, list(group))
print('---------------------------------------------')

## 忽略大小写
for key, group in itertools.groupby('AAAaaaaaBBBbcCCAAa', lambda c: c.upper()):
    print(key, list(group))

结果输出

A ['A', 'A', 'A']
a ['a', 'a', 'a', 'a', 'a']
B ['B', 'B', 'B']
b ['b']
c ['c']
C ['C', 'C']
A ['A', 'A']
a ['a']
---------------------------------------------
A ['A', 'A', 'A', 'a', 'a', 'a', 'a', 'a']
B ['B', 'B', 'B', 'b']
C ['c', 'C', 'C']
A ['A', 'A', 'a']

六、XML

1、DOM vs. SAX

两种操作XML方法:DOM 和 SAX。

  • DOM 会把整个 XML 读入内存,解析为树 ==》占用内存大,解析慢,优点是可以任意遍历树的节点。
  • SAX 是流模式,边读边解析,占用内存小,解析快,缺点是我们需要自
    己处理事件
  • 正常情况下:优先考虑SAX(DOM太占内存)

2、SAX

关键函数:start_element 、end_element 和 char_data

from xml.parsers.expat import ParserCreate

class DefaultSaxHandler(object):
    def start_element(self, name, attrs):
        print('sax: start_element: %s, attrs: %s' % (name, str(attrs)))

    def end_element(self, name):
        print('sax: end_element: %s' % name)

    def char_data(self, text):
        print('sax: char_data: %s' % text)

xml = r'''<?xml version="1.0"?>
<ol>
    <li><a herf="/python">Python</a></li>
    <li><a herf="/ruby">Ruby</a></li>
</ol>
'''
handler = DefaultSaxHandler()
parser = ParserCreate()
parser.StartElementHandler = handler.start_element
parser.EndElementHandler = handler.end_element
parser.CharacterDataHandler = handler.char_data
parser.Parse(xml)

结果输出

sax: start_element: ol, attrs: {}
sax: char_data: 

sax: char_data:     
sax: start_element: li, attrs: {}
sax: start_element: a, attrs: {'herf': '/python'}
sax: char_data: Python
sax: end_element: a
sax: end_element: li
sax: char_data: 

sax: char_data:     
sax: start_element: li, attrs: {}
sax: start_element: a, attrs: {'herf': '/ruby'}
sax: char_data: Ruby
sax: end_element: a
sax: end_element: li
sax: char_data: 

sax: end_element: ol

3、XML的生成

最简单的方法:拼接字符串

L = []
L.append(r'<?xml version="1.0"?>')
L.append(r'<root>')

七、HTMLParser

解析HTML(HTML是XML的子集,但HTML的语法没有XML那么严格)

from html.parser import HTMLParser
from html.entities import name2codepoint

class MyHTMLParser(HTMLParser):
    def handle_starttag(self, tag, attrs):
        print('<%s>' % tag)
    def handle_endtag(self, tag):
        print('</%s>' % tag)
    def handle_startendtag(self, tag, attrs):
        print('<%s/>' % tag)
    def handle_data(self, data):
        print(data)
    def handle_comment(self, data):
        print('<!--', data, '-->')
    def handle_entityref(self, name):
        print('&%s;' % name)
    def handle_charref(self, name):
        print('&#%s;' % name)

parser = MyHTMLParser()
parser.feed('''<html>
<head></head>
<body>
<!-- test html parser -->
<p>Some <a href=\"#\">html</a> HTML&nbsp;tutorial...<br>END</p>
</body></html>''')
  • feed() 方法可以多次调用,可以分部分传入数据。

八、urllib

提供一系列用于操作 URL 的功能。

1、get()

urllib.request 模块可抓取 URL 内容:发送get请求到指定的页面,然后返回 HTTP 的响应。

from urllib import request

# url = 'https://api.douban.com/v2/book/2129650'
url = 'http://www.douban.com/'
req = request.Request(url = url)
# 添加 HTTP 头,可以伪装成浏览器
req.add_header('User-Agent','Mozilla/6.0 (iPhone; CPU iPhones OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
with request.urlopen(req) as f:
    data = f.read()
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', data.decode('utf-8'))

2、post()

以POST发送一个请求,只需把参数 data 以 bytes 形式传入。

from urllib import request, parse

print('Login to weibo.cn...')
email = input('Email:')
passwd = input('Password:')
login_data = parse.urlencode([
    ('username', email),
    ('password', passwd),
    ('entry', 'mweibo'),
    ('client_id',''),
    ('savestate', '1'),
    ('ec', ''),
    ('pagerefer','https://passport.weibo.cn/signin/welcome?entry=nweibo&r=http%3A%2F%2Fm.weibo.cn%2F')
])
url = 'https://passport.weibo.cn/sso/login'
req = request.Request(url)
req.add_header('Origin', 'https://passport.weibo.cn')
req.add_header('User-Agent','Mozilla/6.0 (iPhone; CPU iPhones OS 8_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/8.0 Mobile/10A5376e Safari/8536.25')
req.add_header('Referer','https://passport.weibo.cn/signin/login?entry=mweibo&res=wel&wm=3349&r=http%3A%2F%2Fm.weibo.cn%2F')

with request.urlopen(req, data=login_data.encode('utf-8')) as f:
    print('Status:', f.status, f.reason)
    for k, v in f.getheaders():
        print('%s: %s' % (k, v))
    print('Data:', f.read().decode('utf-8'))

3、Handler

若需要通过一个 Proxy 来访问网站,则利用 ProxyHandler 来处理。

九、常用第三方模块

1、PIL(Python Imaging Library)——图像处理

2、virtualenv

为应用创建一套 Python 运行环境

十、图形界面

第三方库:Tk、wxWidgets、Qt、GTK

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值