Python 学习笔记

本笔记内容来自于
Python 教程
Python 语言参考
Python 标准库

python 的注释

  • 行注释 # annotation
  • 块注释 """annotation"""
  • 编码声明 # -*- coding: <encoding-name> -*- (编码声明需要匹配正则表达式coding[=:]\s*([-\w.]+))

交互模式
python 解释器退出方式:

  • exit()
  • quit()
  • Control-D(Unix) Control-Z(Windows)

在交互模式下,除法运算 (/) 永远返回浮点数类型,如果要做 floor division 得到一个整数结果(忽略小数部分)你可以使用 // 运算符
在交互模式下,上一次打印出来的表达式被赋值给变量 _。这意味着当你把 Python 用作桌面计算器时,继续计算会相对简单。这个变量应该被使用者当作是只读类型。不要向它显式地赋值 —— 你会创建一个和它名字相同独立的本地变量,它会使用魔法行为屏蔽内部变量。

添加在引号前添加r使用原生字符,而非\转义

字符串字面值可以跨行连续输入。一种方式是用三重引号:”””…””” 或 ‘’’…’’’。字符串中的回车换行会自动包含到字符串中,如果不想包含,在行尾添加一个 \ 即可

字符串使用+拼接,使用*重复
相邻的两个或多个字符串字面值将会自动连接到一起,把很长的字符串拆开分别输入的时候尤其有用

字符串支持索引获取字符,也支持切片 word[0:2],需要注意的是,切片结果是左闭右开的

列表通过append()方法追加元素

python 允许多重赋值:a, b = 1, 2
print 中的 end 可以用来取消输出后面的换行,或是用另外一个字符串来结尾,如print(a, end=’,’)

python 中的 range 是个iterable,使用 list(range(5)) 可以从指定范围内获取一个列表。
pass 语句可作为编程占位语句
php 函数定义使用 function 关键字,而 Python 中则使用 def 关键字

name表示接收一个元组,**name 表示接收一个字典。name 必须出现在 **name 之前

python 中的方法参数传递分为位置或关键字参数、仅限位置参数(在形参后放置/)、仅限关键字参数三种(在形参前放置*),如def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):,具体示例可查看https://docs.python.org/zh-cn/3/tutorial/controlflow.html#function-examples

python 中形参类型标注放置在形参之后,且用:分隔,返回值类型标注使用 -> str: 标注,如def f(ham: str, eggs: str = 'eggs') -> str:

数据结构

列表

list
python 支持指定位置插入元素、清空列表(php 则是通过重新赋值的方式,重新赋值是新建一份内存区,原内存区变量将被回收)

del 类似于PHP 中的 unset(),不同的是,del 是语句,而 unset()是方法,正如 PHP 中,echo 是语句,而 print()是方法

序列数据类型包括 list、tuple、range

元组

元组,由几个逗号分隔的值组成,支持嵌套、但元组的内容不可修改,输出时总是被圆括号保卫,以便正确表示嵌套关系。

元组与列表的区别:列表是 mutable (可变的),并且列表中的元素一般是同种类型的,并且通过迭代访问。元组是 immutable (不可变的),其序列通常包含不同种类的元素,并且通过解包或者索引来访问(如果是 namedtuples 的话甚至还可以通过属性访问)。

空元组可以直接被一对空圆括号创建,含有一个元素的元组可以通过在这个元素后添加一个逗号来构建(圆括号里只有一个值的话不够明确)。
元组的序列解包类似于 PHP 中的 list($a, $b, $c) = [‘A’, ‘B’, ‘C’];

集合

集合可以通过花括号或 set() 函数可以用来创建集合。注意:要创建一个空集合你只能用 set() 而不能用 {},因为后者是创建一个空字典。集合也支持推导式形式。PHP 中不存在集合。
PHP中的array_diff是最后一种情况

1
2
3
4
5
set1.add(4)
set1.add(5)
set2.update([11, 12])
set2.discard(5)
set2.remove(4)

区别就是 remove 的元素在 set 当中没有的话会报错,而 discard 不会。

差集:a - b, array_diff(a,b)
交集:a & b, array_intersect(a, b)
并集:a | b, + 或 array_merge()
对称差集:a ^ b,

字典

字典是以关键字为索引的,关键字可以是任意不可变类型,通常是字符串或数字。如果一个元组只包含字符串、数字或元组,那么这个元组也可以用作关键字。但如果元组直接或间接地包含了可变对象,那么它就不能用作关键字。列表不能用作关键字,因为列表可以通过索引、切片或 append() 和 extend() 之类的方法来改变。
对字典使用list()将字典所有的键以列表展示。可通过 in 关键字检查字典中的某个特定的键是否存在。dict() 构造函数可以直接从键值对序列里创建字典。

[]是列表,{}是字典/集合,()是元组。
list()可将元组转换为列表,tuple()可将列表转换为元组。
元组的优势在于,一方面内容不可修改,天然线程安全,另一方面则是在创建时间和占用的空间上面都优于列表
数字、字符串和元组是不可变的,而字典和列表是可变的。
有些对象包含对其他对象的引用;它们被称为 容器。容器的例子有元组、列表和字典等。
a = 1; b = 1 之后,a 和 b 可能会也可能不会指向同一个值为一的对象,这取决于具体实现,但是在 c = []; d = [] 之后,c 和 d 保证会指向两个不同、单独的新建空列表。(请注意 c = d = [] 则是将同一个对象赋值给 c 和 d。)

流程控制

循环的技巧
当在字典中循环时,用 items() 方法可将关键字和对应的值同时取出,用enumerate()可以获取索引和值,用sorted()可以在不改动原序列的基础上返回一个新的排好序的序列
python 还支持同时多个循环,如

1
2
3
4
5
6
7
8
>>> questions = ['name', 'quest', 'favorite color']
>>> answers = ['lancelot', 'the holy grail', 'blue']
>>> for q, a in zip(questions, answers):
... print('What is your {0}? It is {1}.'.format(q, a))
...
What is your name? It is lancelot.
What is your quest? It is the holy grail.
What is your favorite color? It is blue.

比较操作符

in 和 not in 校验一个值是否在(或不在)一个序列里
is 和 is not 比较两个对象是不是同一个对象
比较操作可以传递。例如 a < b == c 会校验是否 a 小于 b 并且 b 等于 c。
not 优先级最高, or 优先级最低,因此 A and not B or C 等价于 (A and (not B)) or C

php 与 C 中用 sprintf() 来格式化输出的字符,而 Python 中使用 str.format(),且占位符与格式可以声明位置对应,无需依照自然序列对应,同时,str.format()也支持传入字典。

读写文件

在文本模式下读取时,默认会把平台特定的行结束符 (Unix 上的 \n, Windows 上的 \r\n) 转换为 \n。在文本模式下写入时,默认会把出现的 \n 转换回平台特定的结束符。这样在幕后修改文件数据对文本文件来说没有问题,但是会破坏二进制数据例如 JPEG 或 EXE 文件中的数据。请一定要注意在读写此类文件时应使用二进制模式。

在处理文件对象时,最好使用 with 关键字。优点是当子句体结束后文件会正确关闭,即使在某个时刻引发了异常。 而且使用 with 相比等效的 try-finally 代码块要简短得多:

1
2
with open('workfile') as f:
read_data = f.read()

要读取文件内容,请调用 f.read(size),它会读取一些数据并将其作为字符串(在文本模式下)或字节串对象(在二进制模式下)返回。 size 是一个可选的数值参数。 当 size 被省略或者为负数时,将读取并返回整个文件的内容;如果文件的大小是你的机器内存的两倍就会出现问题。 当取其他值时,将读取并返回至多 size 个字符(在文本模式下)或 size 个字节(在二进制模式下)。 如果已到达文件末尾,f.read() 将返回一个空字符串 (‘’)。

f.readline() 从文件中读取一行;换行符(\n)留在字符串的末尾,如果文件不以换行符结尾,则在文件的最后一行省略。这使得返回值明确无误;如果 f.readline() 返回一个空的字符串,则表示已经到达了文件末尾,而空行使用 ‘\n’ 表示,该字符串只包含一个换行符。

异常处理

Python 中使用try - raise - except - (else -) finally,PHP 中使用try - throw - catch - finally结构处理异常。

Python 中的except语句可以以元组形式同时指定多个异常,若不指定异常类型,则默认捕获所有异常(不建议在不清楚逻辑的情况下捕获所有异常,有可能你隐藏了很严重的问题)。PHP 中则使用|同时指定多个异常。
Python中try…except…else…结构中else的作用? - 张雨萌的回答

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
try {
foreach (range(1,10) as $num) {
if (5 == $num) {
throw new \Exception('It\'s five!');
}

echo $num, PHP_EOL;
}
} catch (\Exception $e) {
echo $e->getMessage(), PHP_EOL;
} finally {
echo 'Done';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
try:
for num in range(1, 10):
if 5 == num :
# raise Exception("It's five!")
pass

print(num)
except Exception as e:
print(e)
else:
print('Everything is all right')
finally:
print('Done')

在实际应用程序中,finally 子句对于释放外部资源(例如文件或者网络连接)非常有用,无论是否成功使用资源。

python 中使用.调用属性,而 PHP 中使用->调用属性

同 PHP 的对比

Python 中的True``False``None都是首字母大写,而 Python 中的None等同于 PHP 中的null

Python 比 PHP 高效的地方

移除指定区间数组/列表元素
python letters[2:5] = []
php 循环取 key 后 unset()

python 支持 for 遍历字符串、支持多值同时遍历
python在表达式内部赋值必须显式地使用海象运算符 := 来完成,这避免了想要在表达式中写 == 时却写成了 =。(66666)

Python 比 PHP 低效的地方

Python查找一个变量时会按照“局部作用域”、“嵌套作用域”、“全局作用域”和“内置作用域”的顺序进行搜索
Python为字符串类型提供了非常丰富的运算符,我们可以使用+运算符来实现字符串的拼接,可以使用*运算符来重复一个字符串的内容,可以使用in和not in来判断一个字符串是否包含另外一个字符串(成员运算),我们也可以用[]和[:]运算符从字符串取出某个字符或某些字符(切片运算

#疑惑
为什么浮点数在计算机中无法精确存储?财务金额计算如何解决浮点数的精度问题

InnoDB使用的B-tree索引,数值类型的列除了等值判断时索引会生效之外,使用>、<、>=、<=、BETWEEN…AND… 、<>时,索引仍然生效;对于字符串类型的列,如果使用不以通配符开头的模糊查询,索引也是起作用的,但是其他的情况会导致索引失效,这就意味着很有可能会做全表查询。

SQL MongoDB 解释(SQL/MongoDB)
database database 数据库/数据库
table collection 二维表/集合
row document 记录(行)/文档
column field 字段(列)/域
index index 索引/索引
table joins 表连接/嵌套文档
primary key primary key 主键/主键(_id字段)

训练场

俗话说,光说不练假把式,我们就用仅有的只是来抓取豆瓣电影 top250 的信息导出为 Excel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# -*- coding: utf8 -*-

""""
学爬虫利器 XPath, 看这一篇就够了 https://zhuanlan.zhihu.com/p/29436838
https://www.jianshu.com/p/cd3b80849613
https://zhuanlan.zhihu.com/p/99810013
python lxml 教程 https://www.cnblogs.com/dahu-daqing/p/6749666.html
Python 最佳实践指南 https://pythonguidecn.readthedocs.io/zh/latest/

xlwt 针对 Ecxec2007 之前的版本,即.xls 文件,其要求单个 sheet 不超过 65535 行,而 openpyxl 则主要针对 Excel2007 之后的版本(.xlsx),它对文件大小没有限制。xlrd/xlwt的读写速度也优于openpyxl
"""

import xlwt
import requests
import lxml.etree

from time import sleep

header = {
'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36'
}

wb = xlwt.Workbook()
sheet = wb.add_sheet('Movie')
title = ('排名', '链接', '片名', '海报', '语录', '导演', '类型', '上映日期', '国家', '评分', '评价人数', 'IMDB 链接')
for index in range(len(title)):
sheet.write(0, index, title[index])

"""
每页 25 条数据,共 10 页
"""
for start in range(0, 10):
url = 'https://movie.douban.com/top250?start=' + str(start * 25) + '&filter='

# 获取排行页内容并 XML 化处理
list_page_selector = lxml.etree.HTML(requests.get(url, headers=header).text)

for item in range(1, 26):
base_xpath = '//*[@id="content"]/div/div[1]/ol/li[' + str(item)

ranking = int(list_page_selector.xpath(base_xpath + ']/div/div[1]/em/text()')[0])
link = list_page_selector.xpath(base_xpath + ']/div/div[2]/div[1]/a/@href')[0]
movie_info = list_page_selector.xpath(base_xpath + ']/div/div[2]/div[2]/p[1]/text()[2]')[0].strip().split(' / ')

# 获取影片详情页内容
detail_page_selector = lxml.etree.HTML(requests.get(link, headers=header).text)

movie = [
ranking, # Ranking
link, # Link
detail_page_selector.xpath('//*[@id="content"]/h1/span[1]/text()')[0], # Name
list_page_selector.xpath(base_xpath + ']/div/div[1]/a/img/@src')[0].replace('s_ratio_poster', 'raw'), # Poster
list_page_selector.xpath(base_xpath + ']/div/div[2]/div[2]/p[2]/span/text()')[0], # Quote
detail_page_selector.xpath('//*[@id="info"]/span[1]/span[2]/a/text()')[0], # Director
movie_info[2], # Type
# detail_page_selector.xpath('//*[@id="info"]/span[13]/text()'), # Runtime 片长无法正常获取
movie_info[0], # Release Date
movie_info[1], # Country
list_page_selector.xpath(base_xpath + ']/div/div[2]/div[2]/div/span[2]/text()')[0], # Rating
"{:,}".format(int(list_page_selector.xpath(base_xpath + ']/div/div[2]/div[2]/div/span[4]/text()')[0].replace('人评价', ''))), # Ratings
detail_page_selector.xpath('//*[@id="info"]/a/@href')[0] # IMDB
]

# 将数据填充入表格
for index in range(len(movie)):
sheet.write(ranking, index, movie[index])

# 根据 https://movie.douban.com/robots.txt 得 Crawl-delay: 5
sleep(5)

wb.save('./Douban_movie_top_250.xls')

print('DONE')
因为热爱,所以执着。