Ch2 Python速成
2.1 Python 之禅
There should be one—and preferably only one—obvious way to do it.
应该提供一种——且最好只提供一种——明显的解决方案。
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
2.3 虚拟环境
每个数据科学项目都要依赖一些外部库,不同的项目可能需要不同版本的库。为了解决不同项目之间的库版本冲突问题,可以使用虚拟环境(Virtual Environment)。每一个虚拟环境相当于一个沙盒,它们各自维护各自的Python版本和库版本。
一条铁律:在虚拟环境中工作,而不是使用“base”环境。
2.3.1 Anaconda的虚拟环境管理
- 查看目前所有的虚拟环境
$ conda info -e # 查看目前所有的虚拟环境
# conda environments:
#
base * /Users/zhuyuxi/opt/anaconda3
dsfs /Users/zhuyuxi/opt/anaconda3/envs/dsfs
- 创建一个新的虚拟环境
$ conda create -n dsfs2 python=3.9 # 创建一个(名为dsfs2的, Python版本号为3.9的)新的虚拟环境
- 激活虚拟环境(从默认环境切换到某一指定虚拟环境)
$ conda activate dsfs2 # 激活虚拟环境dsfs2
(base) zhuyuxi@zhuyuxideMacBook-Pro ~ % conda activate dsfs2
(dsfs2) zhuyuxi@zhuyuxideMacBook-Pro ~ %
- 关闭虚拟环境(从当前虚拟环境切换回默认环境)
$ conda deactivate
(dsfs2) zhuyuxi@zhuyuxideMacBook-Pro ~ % conda deactivate
(base) zhuyuxi@zhuyuxideMacBook-Pro ~ %
- 删除虚拟环境
$ conda remove -n dsfs2 --all # 删除名为dsfs2的虚拟环境
- 查看当前虚拟环境中已经安装的包
$ conda list
(dsfs) zhuyuxi@zhuyuxideMacBook-Pro ~ % conda list
# packages in environment at /Users/zhuyuxi/opt/anaconda3/envs/dsfs:
#
# Name Version Build Channel
ca-certificates 2022.4.26 hecd8cb5_0
certifi 2021.5.30 py36hecd8cb5_0
libcxx 12.0.0 h2f01273_0
... ... ...
2.4 空白格式(Whitespace)
2.4.1 缩进
许多语言使用大括号来分隔代码块,但是在Python中使用缩进:
for i in [1, 2, 3, 4, 5]:
print(i) # first line in "for i" block
for j in [1, 2, 3, 4, 5]:
print(j) # first line in "for j" block
print(i + j) # last line in "for j" block
print(i) # last line in "for i" block
print("done looping")
2.4.2 忽略方括号和圆括号中的空格
Python会忽略方括号和圆括号内的空格:1. 这对冗长的计算很有帮助 2. 使代码更易读
# Example1
long_winded_computation = (
1 + 2 + 3 + 4 + 5
+ 6 + 7 + 8 + 9 + 10
+ 11 + 12 + 13 + 14 + 15
+ 16 + 17 + 18 + 19 + 20
)
# Example2
list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
easier_to_read_list_of_lists = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
注意:使用反斜杠\
也可以使语句继续到下一行,但是这样会降低可读性,因此一般不这么写。
2.4.3 使用%paste
进行代码的复制粘贴
含有whitespace的代码在复制粘贴到Python Shell中执行时总是会出问题,使用Ipython中的%paste
魔法函数可以正确地复制粘贴代码。
复制下面的代码:
for i in [1,2,3,4,5]:
# 注意这里的空行
print(i)
在Ipython中通过%paste
魔法函数粘贴并执行(在In []
后输入%paste
然后按回车键):
In [ ]: %paste
for i in [1,2,3,4,5]:
# 注意这里的空行
print(i)
## -- End pasted text --
1
2
3
4
5
2.5 模块
- 导入模块本身
- 通过模块名访问模块内部的对象(函数、常量等)
- 可以为模块赋别名
- 当代码中已经有同名对象时
- 当模块名称过长时
- …
import re # 导入模块本身(不使用别名)
my_regex = re.compile("[0-9]+", re.I) # 通过 re. 访问模块内部的对象
import re as regex # 导入模块本身(使用别名)
my_regex = regex.compile("[0-9]+", regex.I) # 通过 regex. 访问模块内部的对象
- 导入模块中的部分对象
- 直接通过对象名访问导入的对象
from re import compile # 导入re模块中的compile函数对象
my_regex = compile("[0-9]+", re.I) # 直接调用compile函数
from re import *
可以将模块中的内容全部导入命名空间,但是之前代码中的重名对象会直接被覆盖,所以最好不要这么做!
2.6 函数
2.6.1 定义函数
通过def关键字定义函数:
def double(x):
"""
在这里,可以使用文档字符串来注释函数的用法。
比如,这个函数就是将输入乘以2。
"""
return x*2 # 如果没有返回值写 return None 或不写
def my_print(msg = "default msg"):
print(msg)
my_print() # 不指定->使用默认参数值,打印 "default msg"
my_print("hello") # 使用指定参数,打印 "hello"
my_print(msg="hello") # 按参数名称指定参数值
2.6.2 函数是对象
在Python中函数也是一种对象:
- 可以将函数赋给其它变量,相当于给函数起了一个别名
my_double = double # my_double是函数double的别名
a = 10
a_doubled = my_double(a) # 可以通过函数的别名来调用函数,等价于直接调用函数
# 等价于:a_doubled = double(a)
- 可以将函数作为参数传递给其它函数
def apply_to_one(func):
"""
将1作为参数调用函数func
"""
return func(1)
one_doubled = apply_to_one(double) # one_doubled = 2
2.6.3 lambda函数
lambda函数是匿名函数,语法格式为:lambda <argument_list>:<expression>
,其中:
lambda
是Python中的预留关键字<argument_list>
是参数列表,使用方法与函数的参数列表相同<expression>
是一个关于参数的表达式,表达式中出现的参数需要在<argument_list>
中有定义,并且表达式只能是单行的,该表达式的计算结果即为该lambda函数的输出
y = apply_to_one(lambda x:x+4) # y is 5
# Equals to
def add_four(x):
return x + 4
y = apply_to_one(add_four) # y is 5
注意:也可以将lambda函数赋给变量,这相当于给它了一个名字;但是最好不要这么写,如果你真的想创建一个具名函数就直接用def
去定义就好了。
another_double = lambda x: 2*x # 不好的写法
def another_double(x):
"""好的写法"""
return 2*x
2.7 字符串
- 字符串可以用单引号或双引号包围:
single_quoted_string = 'data science'
double_quoted_string = "data science"
- 转义字符:反斜杠
tab_string = "\t" # 表示单个Tab字符组成的字符串
len(tab_string) # 单个Tab字符 -> len为1
- 原始字符串:
r"..."
not_tab_string = r"\t" # 表示字符'\'和't'组成的字符串
len(not_tab_string) # 2
- 多行字符串:
multi_line_string = """The first line.
The second line.
The third line."""
- f-string
first_name = "Joel"
second_name = "Grus"
# 组合full-name的三种方式
full_name_concat = first_name + " " + second_name
full_name_format = "{0} {1}".format(first_name, second_name)
full_name_fstring = f"{first_name} {second_name}" # (推荐)更简洁明了
2.8 异常
try:
print(0/0)
except ZeroDivisionError:
print("cannot divide by zero")
cannot divide by zero
虽然在许多语言中异常被认为是不好的情况,但是在Python中,不必因为使用这些技巧而感到难堪,有时这么做可以让代码更清晰。