(Python Primary) - 廖雪峰Python3 - 14.常用内建模块

14.常用内建模块

14.1 datetime

from datetime import datetime

获取当前日期时间

>>> now = datetime.now()	# 获取当前datetime,返回datetime类型
>>> print(now)
2015-05-18 16:28:07.198690
>>> print(type(now))
<class 'datetime.datetime'>

获取指定日期和时间

dt = datetime(2020, 7, 7, 11, 25)

datetime转为timestamp

  • 1970年1月1日 00:00:00 UTC+00:00时区的时刻称为epoch time,记为0(1970年以前的时间timestamp为负数)

  • 当前时间就是相对于epoch time的秒数,称为timestamp

timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00	# 北京时间
  • datetime转为timestamp
>>> dt = datetime(2020, 7, 7, 11, 25)
>>> dt.timestamp()	# 把datetime转换为timestamp
1594092300.0
  • timestamp可转到UTC标准时区
>>> t = 1429417200.0
>>> print(datetime.fromtimestamp(t)) # 本地时间
2015-04-19 12:20:00
>>> print(datetime.utcfromtimestamp(t)) # UTC时间
2015-04-19 04:20:00

str转为datetime

>>> cday = datetime.strptime('2015-6-1 18:19:59', '%Y-%m-%d %H:%M:%S') # %Y-%m-%d %H:%M:%S为格式
>>> print(cday)
2015-06-01 18:19:59

datetime转换为str

>>> now = datetime.now()
>>> print(now.strftime('%a, %b %d %H:%M'))
Mon, May 05 16:28

datetime加减

  • 加减可以直接用+-运算符,不过需要导入timedelta这个类
>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 16, 57, 3, 540997)
>>> now + timedelta(hours=10)
datetime.datetime(2015, 5, 19, 2, 57, 3, 540997)
>>> now - timedelta(days=1)
datetime.datetime(2015, 5, 17, 16, 57, 3, 540997)
>>> now + timedelta(days=2, hours=12)
datetime.datetime(2015, 5, 21, 4, 57, 3, 540997)

本地时间转换为UTC时间

  • 一个datetime类型有一个时区属性tzinfo,但是默认为None,所以无法区分这个datetime到底是哪个时区,除非强行给datetime设置一个时区:
>>> from datetime import datetime, timedelta, timezone
>>> tz_utc_8 = timezone(timedelta(hours=8)) # 创建时区UTC+8:00
>>> now = datetime.now()
>>> now
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012)
>>> dt = now.replace(tzinfo=tz_utc_8) # 强制设置为UTC+8:00
>>> dt
datetime.datetime(2015, 5, 18, 17, 2, 10, 871012, tzinfo=datetime.timezone(datetime.timedelta(0, 28800)))

时区转换

  • 可以先通过utcnow()拿到当前的UTC时间,再转换为任意时区的时间
# 拿到UTC时间,并强制设置时区为UTC+0:00:
>>> utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
>>> print(utc_dt)
2015-05-18 09:05:12.377316+00:00
# astimezone()将转换时区为北京时间:
>>> bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
>>> print(bj_dt)
2015-05-18 17:05:12.377316+08:00
# astimezone()将转换时区为东京时间:
>>> tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt)
2015-05-18 18:05:12.377316+09:00
# astimezone()将bj_dt转换时区为东京时间:
>>> tokyo_dt2 = bj_dt.astimezone(timezone(timedelta(hours=9)))
>>> print(tokyo_dt2)
2015-05-18 18:05:12.377316+09:00

14.2 collections

内含许多有用的集合类

namedtuple

创建自定义的tuple对象,并规定其元素个数,且可以用属性来引用tuple的元素

>>> from collections import namedtuple
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(1, 2)
>>> p.x
1
>>> p.y
2

deque

为实现高效插入、删除操作的双向list,适用于队列和栈

  • 支持函数append()pop()appendleft()popleft()
>>> from collections import deque
>>> q = deque(['a', 'b', 'c'])
>>> q.append('x')
>>> q.appendleft('y')
>>> q
deque(['y', 'a', 'b', 'c', 'x'])

defaultdict

dict引用的key不存在就会抛出KeyError,defaultdict引用不存在Key则返回指定的默认值

>>> from collections import defaultdict
>>> dd = defaultdict(lambda: 'N/A')	# 指定返回的默认值
>>> dd['key2'] # key2不存在,返回默认值
'N/A'

OrderedDict

dict的Key是无序的,迭代时无法知道Key的顺序,使用OrderedDict可以保持Key为插入的顺序

>>> from collections import OrderedDict
>>> d = dict([('a', 1), ('b', 2), ('c', 3)])
>>> d # dict的Key是无序的
{'a': 1, 'c': 3, 'b': 2}
>>> od = OrderedDict([('a', 1), ('b', 2), ('c', 3)])
>>> od # OrderedDict的Key是有序的
OrderedDict([('a', 1), ('b', 2), ('c', 3)])
  • OrderedDict实现FIFO dict
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)

ChainMap

把一组dict串起来并组成一个逻辑上的dict,可实现参数的优先级查找,即先查命令行参数,如没有传入,再查环境变量,如没有,就使用默认参数。

  • e.g.查找usercolor两个参数
from collections import ChainMap
import os, argparse

# 构造缺省参数:
defaults = {
    'color': 'red',
    'user': 'guest'
}

# 构造命令行参数:
parser = argparse.ArgumentParser()
parser.add_argument('-u', '--user')
parser.add_argument('-c', '--color')
namespace = parser.parse_args()
command_line_args = { k: v for k, v in vars(namespace).items() if v }

# 组合成ChainMap:
combined = ChainMap(command_line_args, os.environ, defaults)

# 打印参数:
print('color=%s' % combined['color'])	
print('user=%s' % combined['user'])

$ python3 use_chainmap.py 	# 没有任何参数时,打印出默认参数
color=red
user=guest
$ python3 use_chainmap.py -u bob	# 当传入命令行参数时,优先使用命令行参数
color=red
user=bob
$ user=admin color=green python3 use_chainmap.py -u bob	# 同时传入命令行参数和环境变量,命令行参数的优先级较高
color=green
user=bob

Counter

计数器,如统计字符出现的个数

>>> from collections import Counter
>>> c = Counter()
>>> for ch in 'programming':
...     c[ch] = c[ch] + 1
...
>>> c
Counter({'g': 2, 'm': 2, 'r': 2, 'a': 1, 'i': 1, 'o': 1, 'n': 1, 'p': 1})
>>> c.update('hello') # 也可以一次性update
>>> c
Counter({'r': 2, 'o': 2, 'g': 2, 'm': 2, 'l': 2, 'p': 1, 'a': 1, 'i': 1, 'n': 1, 'h': 1, 'e': 1})
>>> c.clear()

14.3 base64

Base64是用64个字符来表示任意二进制数的方法,是最常见的二进制编码方法。如用记事本打开exe、jpg、pdf等出现乱码,因此需要base64将二进制转为字符串

  • 对二进制数据进行处理,每3个字节一组,一共是3x8=24bit,划为4组,每组正好6个bit。得到4个数字作为索引,然后查表,获得相应-的4个字符,就是编码后的字符串,长度增加33%。

base64-encode

  • 如果剩下1或2个字符用\x00字节在末尾补足后在末尾加上1/2个=号,补上的字节在解码时删去
  • base64的使用
>>> import base64
>>> base64.b64encode(b'binary\x00string')
b'YmluYXJ5AHN0cmluZw=='
>>> base64.b64decode(b'YmluYXJ5AHN0cmluZw==')
b'binary\x00string'
>>> base64.b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd++//'
>>> base64.urlsafe_b64encode(b'i\xb7\x1d\xfb\xef\xff')
b'abcd--__'
>>> base64.urlsafe_b64decode('abcd--__')	# "url safe"的base64编码,其实就是把字符+和/分别变成-和_
b'i\xb7\x1d\xfb\xef\xff'
  • Base64是一种通过查表的编码方法,不能用于加密,适用于小段内容的编码,比如数字证书签名、Cookie的内容等

14.4 struct

struct模块来解决bytes和其他二进制数据类型的转换

  • pack函数把任意数据类型变成bytes
>>> import struct
>>> struct.pack('>I', 10240099)	# >表示字节顺序是big-endian,也就是网络序,I表示4字节无符号整数
b'\x00\x9c@c'
  • unpackbytes变成相应的数据类型
>>> struct.unpack('>IH', b'\xf0\xf0\xf0\xf0\x80\x80')	# >IH的说明,后面的bytes依次变为I:4字节无符号整数和H:2字节无符号整数
(4042322160, 32896)

14.5 hashlib

hashlib提供常见的摘要/哈希算法,如MD5、SHA1等,把数据转换为固定长度的16进制字符串

  • MD5(32位HEX/128bit)
import hashlib

md5 = hashlib.md5()
md5.update('how to use md5 in python hashlib?'.encode('utf-8'))
print(md5.hexdigest())
>>> d26a53750bc40b38b65a520292f69306
  • SHA1(40位HEX/160bit)
import hashlib

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

14.6 hmac

增加一个随机生成的salt,使得相同输入也能得到不同的哈希值。

Hmac: Keyed-Hashing for Message Authentication,根据不同的口令计算出不同哈希,必须提供正确口令才能验证hash值

>>> import hmac
>>> message = b'Hello, world!'
>>> key = b'secret'
>>> h = hmac.new(key, message, digestmod='MD5')
>>> # 如果消息很长,可以多次调用h.update(msg)
>>> h.hexdigest()
'fa4ee7d173f2d97ee79022d1a7355bcf'	# 长度与hash一致
  • 注意输入的key和message都是byte类型

14.7 itertools

用于操作迭代对象的函数

  • count():无限迭代器
>>> import itertools
>>> natuals = itertools.count(1)
>>> for n in natuals:
...     print(n)
...
1
2
3
  • cycle():无限重复一个序列
>>> import itertools
>>> cs = itertools.cycle('ABC') # 注意字符串也是序列的一种
>>> for c in cs:
...     print(c)
...
'A'
'B'
'C'
'A'
'B'
'C'
  • repeat():重复一个元素指定次数(不指定次数则为无限次)
>>> ns = itertools.repeat('A', 3)
>>> for n in ns:
...     print(n)
...
A
A
A
  • takewhile():根据条件截取有限序列
>>> natuals = itertools.count(1)
>>> ns = itertools.takewhile(lambda x: x <= 10, natuals)
>>> list(ns)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • chain():把一组迭代对象串联,形成一个更大的迭代器
>>> for c in itertools.chain('ABC', 'XYZ'):
...     print(c)
# 迭代效果:'A' 'B' 'C' 'X' 'Y' 'Z'
  • groupby():把迭代器中相邻的重复元素挑出来放在一起
>>> for key, group in itertools.groupby('AAABBBCCAAA'):
...     print(key, list(group))
...
A ['A', 'A', 'A']
B ['B', 'B', 'B']
C ['C', 'C']
A ['A', 'A', 'A']

忽略大小写

>>> for key, group in itertools.groupby('AaaBBbcCAAa', lambda c: c.upper()):
...     print(key, list(group))
...
A ['A', 'a', 'a']
B ['B', 'B', 'b']
C ['c', 'C']
A ['A', 'A', 'a']

14.8 contextlib

  • 任何对象,只要正确实现了上下文管理,就可以用于with语句

  • 上下文管理:__enter____exit__

class Query(object):

    def __init__(self, name):
        self.name = name

    def __enter__(self):
        print('Begin')
        return self
    
    def __exit__(self, exc_type, exc_value, traceback):
        if exc_type:
            print('Error')
        else:
            print('End')
    
    def query(self):
        print('Query info about %s...' % self.name)
        
        
with Query('Bob') as q:
    q.query()

@contextmanager

from contextlib import contextmanager

class Query(object):

    def __init__(self, name):
        self.name = name

    def query(self):
        print('Query info about %s...' % self.name)

@contextmanager		# 能接收一个generator,用yield输出
def create_query(name):
    print('Begin')
    q = Query(name)
    yield q
    print('End')
    
    
with create_query('Bob') as q:
    q.query()
  • 在代码前后自动执行特定代码
@contextmanager
def tag(name):
    print("<%s>" % name)
    yield
    print("</%s>" % name)

with tag("h1"):
    print("hello")
    print("world")
    
>>>
<h1>
hello
world
</h1>
  1. with语句首先执行yield之前的语句,因此打印出<h1>
  2. yield调用会执行with语句内部的所有语句,因此打印出helloworld
  3. 最后执行yield之后的语句,打印出</h1>

@closing

将对象变成上下文对象,并支持with语句

@contextmanager
def closing(thing):
    try:
        yield thing
    finally:
        thing.close()

使用

from contextlib import closing
from urllib.request import urlopen

with closing(urlopen('https://www.python.org')) as page:
    for line in page:
        print(line)

以下不常用,省略

14.9 urllib

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

Get

Post

Handler

14.10 XML

14.11 HTMLParser

参考教程

廖雪峰老师的Python3教程

(转载整理自网络,如有侵权,联系本人删除,仅供技术总结使用)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值