Skip to content

入门

Python 的名字来自于英国超现实主义喜剧团队,而不是来自蛇

https://github.com/vinta/awesome-python

https://github.com/mahmoud/awesome-python-applications

https://pypi.org/

https://docs.python.org/zh-cn/3/

安装

https://docs.anaconda.com/anaconda/install/

https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/

https://docs.anaconda.com/anaconda/packages/oldpkglists/

1
2
3
4
5
wget https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.02-Linux-x86_64.sh
bash https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/Anaconda3-2020.02-Linux-x86_64.sh
source .zshrc
python --version
Python 3.7.6

查看程序所用的 Python 版本:

1
2
3
In [1]: import sys
In [4]: sys.version
Out[4]: '3.7.0 (default, Jun 28 2018, 07:39:16) \n[Clang 4.0.1 (tags/RELEASE_401/final)]'

编码规范

Phthon 中采用 PEP 8 作为编码规范,其中 PEP 是 Python Enhancement Proposal,翻译过来就是 Python 增强建议书,而 "8" 代表版本号。

  • 每个 import 语句只导入一个模块,尽量避免一次导入多个模块
  • 建议每行不超过 80 个字符,如果超过,建议使用小括号“()”将多行内容隐式的连接起来,而不推荐使用反斜杠“\”进行连接
  • 使用必要的空行增加代码的可读性。一般在顶级定义(如函数或者类的定义)之间空两行,而方法定义之间空一行。另外,在用于分隔某些功能的位置也可以空一行
  • 适当使用异常处理结构提高程序容错性,但不能过多依赖异常处理结构,适当的显式判断还是必要的
  • 模块名尽量短小,并且全部使用小写字母,不推荐使用下划线
  • 包名尽量短小,并且全部使用小写字母,不推荐使用下划线
  • 类名采用单词首字母大写形式(即 Pascal 风格)
  • 模块内部的类采用下划线 + Pascal 风格的类名组成
  • 函数、类的属性和方法的命名规则同模块类似,也是全部使用小写字母,多个字母间用下划线分隔
  • 常量命名时采用全部大写字母,可以使用下划线
  • 使用单下划线开头的模块变量或者函数是受保护的,在使用 from xxx import * 语句从模块中导入时这些变量或者函数不能被导入
  • 使用双下划线开头的实例变量或方法是类私有的

注释

语句块分界线:#%%

1
2
3
4
5
6
7
8
9
#%%

print(1)

#%%

print(2)

#%%

基本数据类型

int 数据类型表明值是整数。带有小数点的数,称为浮点型(float)

可以使用 str(), int() 和 float() 函数将其他类型的值转换成字符串, 整数或浮点数的值

1
spam = int(input())

可以使用 int() 对浮点数取整: int(7.7),结果为 7

一般而言,编译器有很少(合理)隐式类型转化的是强类型语言,有较多(过分)隐式类型转化的是弱类型语言。
python 是强类型的语言,因为字符串和整数不能相加,但是 JavaScript 可以

  • 强类型:Java、C#、Python、Ruby、Erlang(再加GO、Rust)……
  • 弱类型:C、C++、Javascript、Perl、PHP、VB……

Python 社区的主流看法认为它是强类型语言,而判断的标准也是看隐式类型转换。
例子有很多,比如 Python 官方的 wiki,它专门回答了 Why is Python a dynamic language and also a strongly typed language https://wiki.python.org/moin/Why%20is%20Python%20a%20dynamic%20language%20and%20also%20a%20strongly%20typed%20language,给出了 4 个答案,为 Python 的“动态强类型”定性

字符串和整数可以相乘

如果修改数字类型变量的值,那么会先把该值存放到内存中,然后修改变量让其指向新的内存地址

// 表示整除,2 ** 3 表示计算 2 的 3 次方

ASCII码表图

  • chr 函数(获取整数对应的字符)
1
2
>>> print(chr(65))
A
  • ord 函数(将一个字符转换成 ASCII 数值或者 Unicode 数值)
1
2
3
4
>>> print(ord('A'))
65
>>> print(ord('5'))
53

比较运算符

在 Python 中,当需要判断一个变量是否介于两个值之间,可以采用“值1 < 变量 < 值2”的形式,如“0 < a < 100”

1
2
3
4
5
6
In [4]: 42 == '42'
Out[4]: False
In [5]: 42 == 42.0
Out[5]: True
In [6]: 42.0 == 0042.000
Out[6]: True

列表和元组

可以使用 in 关键字检查某个元素是否是序列的成员,即检查某个元素是否包含在该序列中
sorted(): 对元素进行排序
reversed(): 反向序列中的元素
enumerate(): 将序列组合为一个索引序列,多用在 for 循环中

1
2
3
4
In [55]: for index, item in enumerate([111, 'hhh']):
            print(f"{index} {item}")
0 111
1 hhh

如果想要将一个列表中的全部元素添加到另一个列表中,可以使用列表对象的 extend() 方法实现
listname.count(obj): 获取指定元素出现的次数
listname.index(obj): 获取指定元素首次出现的下标
listname.sort(key=None, reverse=False)
sorted(iterable, key=None, reverse=False) 使用 sorted 函数时,会建立一个原列表的副本

range(start, stop[, step]): 第一个参数是开始的值,第二个参数是上限,但不包含它,它就是一个停止的数字,第三个参数是“步长”。步长是每次迭代后循环变量增加的值

切片

seq[start:end:step]

1
2
3
4
In [6]: l = [i for i in range(5)]

In [7]: l[::-1]
Out[7]: [4, 3, 2, 1, 0]

字典与集合

1
2
3
4
5
6
7
8
9
dictionary = dict(zip(list1, list2)) # 通用映射函数创建字典  
dictionary = dict(key1=value1, key2=value2,..., keyn=valuen) # 通过给定的“键值对”创建字典
dictionary = dict.fromkeys(list1) # 创建值为空的字典
dictionary = {tuple1:list1} # 通过已经存在的元组和列表创建字典
dictionary.getg(key, [default])
In [57]: for key, value in dictionary.items():
            print(f"{key} {value}")
a 1
b 2

字典对象提供了 values() 和 keys() 方法,用于返回字典的值和键列表

判断字典是否存在某个 key,用 key in dictionary 进行判断

1
2
3
4
5
d = {'name':{},'age':{},'sex':{}}
print("name" in d, "month" in d)
"""
True False
"""

字典推导式

1
2
3
In [59]: randomdict = {i: random.randint(10, 100) for i in range(1, 5)}
In [60]: randomdict
Out[60]: {1: 95, 2: 78, 3: 18, 4: 56}

向集合中添加元素:add()
从集合中删除元素:remove()
移除最后一个元素:pop()
清空集合:clear()
进行交集运算时使用&符号;进行并集运算时使用|符号;进行差集运算时使用-符号

1
2
3
4
5
6
# set 的 update 方法
In [1]: x = {'a', 'b', 'c'}
In [2]: y = {'c', 'd'}
In [3]: x.update(y)
In [4]: x
Out[4]: {'a', 'b', 'c', 'd'}

函数

位置参数
关键字参数
在定义函数时,指定默认的形参必须在所有参数的最后,否则将产生语法错误
可变参数
*args 表示接收任意多个参数并将其放到一个元组中
**kwargs 表示接收任意多个显式赋值的实际参数,并将其放到一个字典中

当局部变量与全局变量重名时,对函数体的变量进行赋值后,不影响函数体外的变量

在函数体内定义,并且使用 global 关键字后,该变量也可以变成全局变量。在函数体外也可以访问到该变量,并且在函数体内还可以对其进行修改

值传递和引用传递

在Python中,数字、字符或者元组等不可变对象类型都属于值传递,而字典dict或者列表list等可变对象类型属于引用传递。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
In [12]: def test(l):
    ...:     l[1] = 10
    ...:

In [13]: l = [1, 2, 3]

In [14]: test(l)

In [15]: l
Out[15]: [1, 10, 3]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [16]: def test(l):
    ...:     l = l.copy()
    ...:
    ...:     l[1] = 10
    ...:

In [17]: l = [1, 2, 3]

In [18]: test(l)

In [19]: l
Out[19]: [1, 2, 3]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
In [1]: l = [1, 2, 3, 4]
In [2]: l[-2:]
Out[2]: [3, 4]
In [3]: def test(l):
   ...:     l = l[-2:]
   ...:     print(l)
   ...:
In [4]: l = [1, 2, 3, 4]
In [5]: test(l)
[3, 4]
In [6]: l
Out[6]: [1, 2, 3, 4]

内置函数

abs(x) 获取绝对值
divmod(a, b) 获取商和余数的元组
sum(iterable, start): 求和计算,start 表示相加后再次相加的值,默认为 0
round(x, n): 四舍五入,n 表示要保留的小数位数(很辣鸡, 会有精度误差)
pow(x, y): 计算 x 的 y 次方
min(a, b, c, ...) 或 min(seq): 取出给定参数的最小值
max(a, b, c, ...) 或 max(seq): 取出给定参数的最大值
hex(x): 十进制转换十六进制
oct(x): 十进制转换八进制
bin(x): 十进制转换二进制
filter(function, iterable): 通过指定条件过滤序列并返回新的列表对象
zip(iterable1,...): 将可迭代的对象打包成元组并返回由元组组成的对象
map(function, iterable,...): 通过自定义函数实现对序列的元素映射操作并返回操作后的结果
help(object): 查看对象帮助信息

类和对象

类属性
类属性是指定义在类中,并且在函数体外的属性。类属性可以在类的所有实例之间共享值,也就是在所有实例化的对象中公用

1
2
3
class Geese:
    neck = '1' # 定义类属性
    wing = 10

实例属性
实例属性是指定义在类的方法中的属性,只作用于当前实例中

1
2
3
4
class Geese:
    def __init__(self):
        self.neck = 'hhh' # 定义实例属性
        self.wing = 100

实例属性只能通过实例名访问。不能通过类名访问实例属性

访问限制

在类的内部可以定义属性和方法,而在类的外部则可以直接调用属性或方法来操作数据,从而隐藏了类内部的复杂逻辑。
但是 Python 并没有对属性和方法的访问权限进行限制。
为了保证类内部的某些属性或方法不被外部所访问,可以在属性或方法名前面加单下划线(_foo)、双下划线(__foo)或首尾双下划线(__foo__),从而限制访问权限

  • __foo__: 首尾双下划线表示定义特殊方法,一般是系统定义的名字,如 __init__()
  • _foo: 以单下划线开头的表示 protected(保护) 类型的成员,只允许类本身和子类进行访问,但不能使用 from module import * 语句导入
  • __foo: 双下划线表示 private(私有)类型的成员,只允许定义该方法的类本身进行访问,而且也不能通过类的实例进行访问,而且也不能通过类的实例进行访问,但是可以通过“类的实例名.类名__xxx”方式访问

创建用于计算的属性

在 Python 中,可以通过 @property 装饰器将一个方法转换为属性,从而实现用于计算的属性,将方法转换为属性后,可以直接通过方法名来访问方法,而不需要再添加一对小括号“()”,这样可以让代码更加简洁

例如,定义一个矩形类,在 __init__() 方法中定义两个实例属性,然后再定义一个计算矩形面积的方法,并应用 @property 将其转换为属性,最后创建类的实例,并访问转换后的属性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Rect:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    @property
    def area(self):
        return self.width * self.height
rect = Rect(800, 600)
print(f"面积为: {rect.area}")
"""
面积为: 480000
"""

为属性添加安全保护机制

在 Python 中,默认情况下,创建的类属性或者实例,是可以在类体外进行修改的,如果想要限制其不能在类体外修改,可以将其设置为私有的,但设置为私有后,在类体外也不能获取它的值,如果想要创建一个可以读取,但不能修改的属性,那么可以使用 @property 实现只读属性

例如,创建一个电视节目类 TVshow,再创建一个 show 属性,用于显示当前播放的电视节目

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
class TVshow:
    def __init__(self, show):
        self.__show = show
    @property
    def show(self):
        return self.__show
tvshow = TVshow("《战狼2》")
print(tvshow.show)
"""
《战狼2》
"""

通过上面的方法创建的 show 属性是只读的

异常处理

常见的异常及描述

异常 描述
NameError 尝试访问一个没有声明的变量引起的错误
IndexError 索引超出序列范围引发的错误
IndentationError 缩进错误
ValueError 传入的值错误
KeyError 请求一个不存在的字典关键字引发的错误
IOError 输入输出错误(如要读取的文件不存在)
ImportError 当 import 语句无法找到模块或 from 无法在模块中找到相应的名称时引发的错误
AttributeError 尝试访问未知的对象属性引发的错误
TypeError 类型不合适引发的错误
MemoryError 内存不足
ZeroDivisionError 除数为 0 引发的错误

try...except...else 语句,用于指定当 try 语句块中没有发现异常时要执行的语句块

try...except...finally 任何情形中都必须执行的代码放到 finally 语句的区块中

使用 raise 语句可以抛出异常,例如

1
raise ValueError("除数不能为 0")
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def spam(divide_by):
    try:
        return 42 / divide_by
    except ZeroDivisionError:
        print('Error: Invalid argument.')
print(spam(2))
print(spam(12))
print(spam(0))
print(spam(1))
"""
21.0
3.5
Error: Invalid argument.
None
42.0
"""
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
def spam(divide_by):
    return 42 / divide_by
try:
    print(spam(2))
    print(spam(12))
    print(spam(0))
    print(spam(1))
except ZeroDivisionError:
    print('Error: Invalid argument.')
"""
21.0
3.5
Error: Invalid argument.
"""

打印或检索堆栈回溯

https://docs.python.org/zh-cn/3.7/library/traceback.html

1
2
3
4
5
6
import traceback

try:
    x = 1 / 0
except ZeroDivisionError:
    print(traceback.format_exc())

模块和包

避免模块名重复,包简单理解就是“文件夹”,只不过在该文件夹下必须存在一个名称为__init__.py的文件

random 模块
  • random.sample(population, k) 返回从总体序列或集合中选择的唯一元素的 k 长度列表。 用于无重复的随机抽样。
  • random.choice 从一个序列中随机选出一个元素
  • random.randint(1, 10): 求 1 到 10(包括10) 之间的一个随机整数
  • random.uniform(0.9, 1.3): 生成 [0.9, 1.3) 之间的一个随机浮点数
sys 模块

与 Python 解释器及其环境操作相关的标准库

sys.argv[1] 表示传入的第一个参数

sys.exit() 可以提前结束程序

time 模块
  • time.time() 返回值为从 1970 年 1 月 1 日 0 点开始的秒数
1
2
3
>>> import time
>>> time.time()
1561866344.232516
datetime 模块
1
2
3
4
5
6
7
8
9
>>> import datetime
>>> datetime.datetime.now()
datetime.datetime(2019, 6, 30, 11, 55, 16, 149144)
>>> dt = datetime.datetime(2019, 10, 1, 10, 36, 36)
>>> dt.year, dt.month, dt.day
(2019, 10, 1)
>>> dt.hour, dt.minute, dt.second, dt.microsecond
(10, 36, 36, 0)
# microsecond: 微秒; 1 微秒 = 0.001 毫秒
  • 将 datetime 对象转换为字符串: strftime()
格式符 说明
%Y 四个数字表示的年份 2015
%y 两个数字表示的年份 15
%m 返回月份 范围[0,12]
%b 月份的英文单词的缩写:如一月, 则返回 Jan
%B 月份的引文单词的缩写:如一月, 则返回 January
%d 返回的是当前时间是当前月的第几天
%j 返回 当天是当年的第几天 范围[001,366]
%w 当天在当周的天数,范围为[0, 6],6表示星期天
%a 星期的英文单词的缩写:如星期一, 则返回 Mon
%A 星期的英文单词的全拼:如星期一,返回 Monday
%H 以24小时制表示当前小时
%I 以12小时制表示当前小时
%M 返回分钟数 范围 [0,59]
%S 秒,'00' 至 '59'
%p 返回是上午还是下午–AM or PM
%f 微秒的表示: 范围: [0,999999]
1
2
3
4
5
6
7
8
>>> from datetime import datetime
>>> dt = datetime(2008, 1, 1, 16, 36, 26)
>>> dt.strftime('%Y/%m/%d %H:%M:%S')
'2008/01/01 16:36:26'
>>> dt.strftime('%I:%M %p')
'04:36 PM'
>>> dt.strftime("%B of '%y")
"January of '08"
  • 将字符串转为 datetime 对象:strptime()
1
2
3
4
>>> datetime.strptime('October 21, 2015', '%B %d, %Y')
datetime.datetime(2015, 10, 21, 0, 0)
>>> datetime.strptime('2015/10/21 16:29:00', '%Y/%m/%d %H:%M:%S')
datetime.datetime(2015, 10, 21, 16, 29)

获取明天早上 8 点:

1
2
3
4
5
6
from datetime import datetime, timedelta, time

# 获取明天早上8点   
next_date = (datetime.now() + timedelta(1)).date()
next_day_8 = datetime.combine(next_date, time(8))
print(next_day_8)

定时到今天的 14:47执行任务:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from datetime import datetime, time
import asyncio

until_time = datetime.combine(datetime.now().date(), time(14, 47))


async def run():
    d = until_time - datetime.now()
    await asyncio.sleep(d.seconds + d.microseconds / 1000000)
    print(f"now time = {datetime.now()}")


loop = asyncio.get_event_loop()
loop.run_until_complete(run())
# now time = 2021-01-23 14:47:00.005584
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 定时到今天 14:31
import time
import datetime


until_time = datetime.datetime.combine(
    datetime.datetime.now().date(), 
    datetime.time(14, 31)
)
d = until_time - datetime.datetime.now()
time.sleep(d.seconds + d.microseconds / 1000000)

print(datetime.datetime.now())
math 模块
1
math.hypot(x, y): 返回欧几里德范数sqrt(x*x + y*y)这是从原点到点 (x, y) 的向量长度
git 模块

pip install GitPython

uuid 模块

UUID: 通用唯一标识符(Universally Unique Identifier)

uuid.uuid4() -- 基于随机数,由伪随机数得到,有一定的重复概率

typing 模块

(1)类型检查,防止运行时出现参数和返回值类型不符合的问题。
(2)作为开发文档附件说明,方便使用者调用时传入和返回参数类型。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from typing import List,Tuple,Dict

def add(a: int, string: str, f: float, b: bool) -> Tuple[List, Tuple, Dict, bool]:
    list1=list(range(a))
    tup=(string,string, string)
    d={"a": f}
    bl=b
    return list1,tup,d,bl
if __name__ == '__main__':
    print(add(5, 'mark', 183.1, False))
"""
([0, 1, 2, 3, 4], ('mark', 'mark', 'mark'), {'a': 183.1}, False)
"""