廖雪峰课程 Python笔记(三)
一、学习网站
摘抄 廖雪峰 Python课程:点击打开
二、模块介绍
在Python中,一个.py文件就称之为一个模块(Module)。使用模块将函数进行分组,更便于维护代码。并且编写代码不必从头开始,一个模块可以到处引用,节省开发时间。
并且相同函数或变量名称在不同模块内部互不影响,但不能与内置模块名称冲突。
Python内置模块:点击查看
模块命名:
文件名称就是模块名称,如 abc.py
文件模块名就是 abc
注意:
模块名要遵循Python变量命名规范,不要使用中文、特殊字符;
模块名不要和系统模块名冲突,最好先查看系统是否已存在该模块,检查方法是在Python交互环境执行import abc,若成功则说明系统存在此模块。
1、使用模块
以内置 sys
模块为例,摘抄 廖雪峰
老师的案例代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23#!/usr/bin/env python3 # 标准注释 让这个hello.py文件直接在Unix/Linux/Mac上运行
# -*- coding: utf-8 -*- # 标准注释 表示.py文件本身使用标准UTF-8编码
" a test module " # 一个字符串,表示模块的文档注释,任何模块代码的第一个字符串都被视为模块的文档注释;
__author__ = "Michael Liao" # __author__变量把作者写进去,公开源代码后别人可知作者;
## 👆以上就是Python模块的标准文件模板,可以不写。
import sys # 导入模块
def test():
args = sys.argv # sys模块内的argv变量,用list存储了命令行的所有参数。
if len(args)==1:
print("Hello, world!")
elif len(args)==2:
print("Hello, %s!" % args[1])
else:
print("Too many arguments!")
if __name__=="__main__":
test()
# 用于做运行测试,原理:运行模块后,Python解释器把一个特殊变量__name__置为__main__
# 而如果在其他地方导入该hello模块时,if判断将失败,后面代码不执行,即可作为运行测试。
注意:
argv至少有一个元素,因为第一个参数永远是该.py文件的名称:1
2
3
4 > python3 hello.py
# ["hello.py"] > sys.argv
> python3 hello.py Michael
# ["hello.py", "Michael] > sys.argv
2、作用域
希望函数和变量仅在内部使用,可通过 _
前缀来实现。
正常的函数和变量名是公开的(public),可以直接被引用,比如:abc
、x123
、PI
等。
特殊变量名如 __xxx__
可以直接引用但是有其他用途,比如之前的 __author__
,__name__
就是特殊变量,一般我们直接写不要用这种。
非公开的(private)函数和变量名,如 _xx
和 __xx
,不能直接引用。
外部不需要引用的函数全部定义成private,只有外部需要引用的函数才定义为public。
3、安装第三方模块
python需要通过包管理工具 pip
来安装第三方模块。
pip安装教程:点击打开
Windows安装要记得在安装时勾选了 pip
和 Add python.exe to Path
。
安装完成,通过下面命令安装:1
pip install packageName
4、安装常用模块
可以通过命令行安装。
也可以使用 Anaconda
安装。
5、模块搜索路径
默认情况下,Python解释器会搜索 当前目录
、所有已安装的内置模块
和 第三方模块
,搜索路径存放在 sys模块
的 path变量
中:1
2
3 > import sys
> sys.path
["", "/Library/Frameworks/Python.framework/Versions/3.6/lib/python36.zip", "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6", ..., "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages"]
如果我们要添加自己的搜索目录,有两种方法:
一是直接修改 sys.path
,添加要搜索的目录:1
2 > import sys
"/Users/michael/my_py_scripts") > sys.path.append(
这种方法是在运行时修改,运行结束后失效。
第二种方法是设置环境变量 PYTHONPATH
,该环境变量的内容会被自动添加到模块搜索路径中。
设置方式与设置 Path环境变量
类似。注意只需要添加你自己的搜索路径,Python自己本身的搜索路径不受影响。
3、常用内建模块
python内置了许多非常有用的模块,无需额外安装和配置,即可直接使用。
a)、datetime
datetime是python处理日期和时间的标准库。
获取当前日期和时间
由于 datetime
模块还包含一个 datetime类
,所以导入有2种方法。1
2
3
4
5
6
7
8# 方法1:
from datetime import datetime
# 方法2:
impot datetime.datetime
now = datetime.now()
print(now) # 2017-12-04 22:29:25.865744
print(type(now)) # <class "datetime.datetime">
datetime.now()
返回当前日期和时间,其类型是 datetime
。
获取指定日期和时间
1 | from datetime import datetime |
datetime转换为timestamp
在计算机中,时间实际上是用 数字表示
的。我们把 1970年1月1日 00:00:00 UTC+00:00时区
的时刻称为 epoch time
,记为0(1970年以前的时间 timestamp
为负数),当前时间就是相对于 epoch time
的秒数,称为 timestamp
。即:1
2
3timestamp = 0 = 1970-1-1 00:00:00 UTC+0:00
# 对应的北京时间是(时差8小时):
timestamp = 0 = 1970-1-1 08:00:00 UTC+8:00
可见 timestamp
的值与时区毫无关系,因为 timestamp
一旦确定,其UTC时间就确定了,转换到任意时区的时间也是完全确定的,这就是为什么计算机存储的当前时间是以 timestamp
表示的,因为全球各地的计算机在任意时刻的 timestamp
都是完全相同的(假定时间已校准)。
把一个 datetime类型
转换为 timestamp
只需要简单调用 timestamp()
方法:1
2
3from datetime import datetime
dt = datetime(2017,12,04,12,20) # 用指定日期时间创建datetime
dt.timestamp() # 把datetime转换成timestamp
另外:如果转换结果小数位,即小数位表示毫秒数。
timestamp转换为datetime
使用 datetime
提供的 fromtimestamp()
方法即可:1
2
3from datetime import datetime
t = 1429417200.0
print(datetime.fromtimestamp(t)) # 2015-04-19 12:20:00
timestamp
也可以直接被转到UTC标准市区的时间。1
2
3
4from datetime import datetime
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
通过 datetime.strptime()
实现。1
2
3from datetime import datetime
cday = datetime.strptime("2017-12-04 22:51:59","%Y-%m-%d %H:%M:%S")
print(cday) # 2017-12-04 22:51:59
关于时间格式 %Y-%m-%d %H:%M:%S
,可以查看官方介绍:点击打开
datetime转换为str
通过 strftime()
实现。1
2
3from datetime import datetime
now = datetime.now()
print(now.strftime("%a,%b,%d %H:%M"))# Mon,Dec,04 22:55
datetime加减
对日期和时间进行加减实际上就是把datetime往后或往前计算,得到新的datetime。
加减可以直接用 +
和 -
运算符,不过需要导入 timedelta
这个类:1
2
3
4
5
6from datetime import datetime,timedelta
now = datetime.now()
print(now) # 2017-12-04 23:01:31.882059
print(now + timedelta(hours = 10)) # 2017-12-05 09:01:31.882059
print(now - timedelta(days = 1)) # 2017-12-03 23:01:31.882059
print(now + timedelta(days = 2,hours = 12)) # 2017-12-07 11:01:31.882059
本地时间转换为UTC时间
本地时间是指系统设定时区的时间,例如北京时间是 UTC+8:00时区
的时间,而UTC时间指 UTC+0:00时区
的时间。
一个 datetime类型
有一个时区属性 tzinfo
,但是默认为 None
,所以无法区分这个 datetime
到底是哪个时区,除非强行给 datetime
设置一个时区:1
2
3
4
5
6from datetime import datetime, timedelta, timezone
tz_utc_8 = timezone(timedelta(hours=8)) # 创建时区UTC+8:00
now = datetime.now()
print(now) # 2017-12-04 23:05:03.537432
dt = now.replace(tzinfo=tz_utc_8) # 强制设置为UTC+8:00
print(dt)
时区转换
通过 utcnow()
拿到当前的UTC时间,再转换成任意时区的时间:1
2
3
4
5
6
7
8
9
10
11
12from datetime import datetime, timedelta, timezone
utc_dt = datetime.utcnow().replace(tzinfo=timezone.utc)
print(utc_dt) # 2017-12-04 15:10:49.949725+00:00
# astimezone()将转换时区为北京时间:
bj_dt = utc_dt.astimezone(timezone(timedelta(hours=8)))
print(bj_dt) # 2017-12-04 23:11:36.684443+08:00
# astimezone()将转换时区为东京时间:
tokyo_dt = utc_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt) # 2017-12-05 00:12:35.397543+09:00
# astimezone()将bj_dt转换时区为东京时间:
tokyo_dt2 = bj_dt.astimezone(timezone(timedelta(hours=9)))
print(tokyo_dt2) # 2017-12-05 00:12:35.397543+09:00
时区转换的关键在于,拿到一个 datetime
时,要获知其正确的时区,然后强制设置时区,作为基准时间。
利用带时区的 datetime
,通过 astimezone()
方法,可以转换到任意时区。
注:不是必须从UTC+0:00时区转换到其他时区,任何带时区的datetime都可以正确转换,例如上述bj_dt到tokyo_dt的转换。
小结
datetime
表示的时间需要时区信息才能确定一个特定的时间,否则只能视为 本地时间
。
如果要存储 datetime
,最佳方法是将其转换为 timestamp
再存储,因为 timestamp
的值与时区完全无关。
b)、collections模块
collections是Python内建的一个集合模块,提供了许多有用的集合类。
namedtuple
如用 tuple
表示一个二维坐标:1
p = (1,2)
这个 tuple
很难看出是个坐标,即可以使用 namedtulpe
表示:1
2
3
4
5from collections import namedtuple
Point = namedtuple("Point",["x","y"])
p = Point(1,2)
print(p.x) # 1
print(p.y) # 2
其格式如:1
namedtuple("名称", [属性list]):
namedtuple
是一个函数,创建一个自定义 tuple
对象,并规定 tuple
元素个数,我们可以用属性而不是索引来引用 tuple
的某个元素。
可以验证创建的 Point对象
是 tuple
的一种子类:1
2print(isinstance(p,Point)) # True
print(isinstance(p,tuple)) # True
然后创建一个圆:1
Circle = nametuple("Circle",["x","y","r"])
deque
使用 list
存储数据时,按索引访问元素很快,但是插入和删除元素就很慢了,因为 list
是线性存储,数据量大的时候,插入和删除 效率很低
。deque
是为了高效实现插入和删除操作的双向列表,适合用于 队列和栈
:1
2
3
4
5from collections import deque
q = deque(["a","b","c"])
q.append("x") # 从后面入栈
q.appendleft("y") # 从前面入栈
print(q) # deque(["y", "a", "b", "c", "x"])
defaultdict
使用 dict
时,如果引用的 Key
不存在,就会抛出 KeyError
。如果希望 key
不存在时,返回一个 默认值
,就可以用 defaultdict
:1
2
3
4
5from collections import defaultdict
dd = defaultdict(lambda:"N/A")
dd["key1"] = ["abc"]
print(dd["key1"]) # "abc"
print(dd["key2"]) # "N/A"
OrderedDict
使用 dict
时,Key
是无序的。在对 dict
做迭代时,我们无法确定 Key
的顺序。如果要保持 key
的顺序,可以用 OrderedDict
:1
2
3
4
5from collections import OrderedDict
d = dict([("a",1),("b",2),("c",3)])
print(d) # dict的Key是无序的 {"a": 1, "b": 2, "c": 3}
od = OrderedDict([("a",1),("b",2),("c",3)])
print(od) # OrderedDict的Key是有序的 OrderedDict([("a", 1), ("b", 2), ("c", 3)])
注意:OrderedDict
的 Key
会按照插入的顺序排列,不是 Key
本身排序:1
2
3
4
5od = OrderedDict()
od["z"] = 1
od["y"] = 2
od["x"] = 3
print(list(od.keys())) # 按照插入的Key的顺序返回 ["z", "y", "x"]
Counter
Counter
是一个简单的计算器,比如计算字符出现的个数:1
2
3
4
5from collections import Counter
c = Counter()
for ch in "programing":
c[ch] = c[ch]+1
print(c) # Counter({"r": 2, "g": 2, "p": 1, "o": 1, "a": 1, "m": 1, "i": 1, "n": 1})
Counter
实际上也是 dict
的一个子类,上面的结果可以看出,字符"g"
、"m"
、"r"
各出现了两次,其他字符各出现了一次。
c)、base64
1 | import base64 |