目录
1. print和import
1.1 打印多个参数
print 可用于打印一个表达式,这个表达式要么是字符串,要么将自动转换为字符串。也可以同时打印多个表达式,条件是用逗号分隔它们。
>>> print('Age:', 18)
Age: 18
>>> name = 'Gumby'
>>> salutation = 'Mr.'
>>> greeting = 'Hello,'
>>> print(greeting, salutation, name)
Hello, Mr. Gumby
# 如果字符串变量greeting 不包含逗号,如何在结果中添加呢?
>>> print(greeting + ',', salutation, name)
Hello, Mr. Gumby
# 可自定义分隔符
>>> print("I", "wish", "to", "register", "a", "complaint", sep='_')
I_wish_to_register_a_complaint
还可自定义结束字符串,以替换默认的换行符。将结束字符串指定为空字符串,以后就可继续打印到当前行。
print('Hello,', end='')
print('world!')
1.2 导入时重命名
import somemodule
from somemodule import somefunction
from somemodule import somefunction, anotherfunction, yetanotherfunction
from somemodule import *
# 在语句末尾添加as指定别名
from module1 import open as open1
import module as module1
2. 赋值魔法
2.1 序列解包
同时 (并行)给多个变量赋值
>>> x, y, z = 1, 2, 3
>>> print(x, y, z)
1 2 3
# 还可交换多个变量的值
>>>> x, y = y, x
>>>> print(x, y, z)
2 1 3
这里执行的操作称为序列解包 (或可迭代对象解包 ):将一个序列(或任何可迭代对象)解包,并将得到的值存储到一系列变量中。
>>> values = 1, 2, 3
>>> values
(1, 2, 3)
>>> x, y, z = values
>>> x
1
从字典中随便获取(或删除)一个键-值对,可使用方法popitem ,它随便获取一个键-值对并以元组的方式返回。可直接将返回的元组解包到两个变量中。
>>> scoundrel = {'name': 'Robin', 'girlfriend': 'Marion'}
>>> key, value = scoundrel.popitem()
>>> key
'girlfriend'
>>> value
'Marion'
要解包的序列包含的元素个数必须与你在等号左边列出的目标个数相同,否则Python将引发异常。
# 错误示范
>>> x, y, z = 1, 2
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# ValueError: need more than 2 values to unpack
>>> x, y, z = 1, 2, 3, 4
# Traceback (most recent call last):
# File "<stdin>", line 1, in <module>
# ValueError: too many values to unpack
可使用星号运算符(* )来收集多余的值,这样无需确保值和变量的个数相同。
>>> a, b, *rest = [1, 2, 3, 4]
>>> rest
[3, 4]
# 还可将带星号的变量放在其他位置
>>> name = "Albus Percival Wulfric Brian Dumbledore"
>>> first, *middle, last = name.split()
>>> middle
['Percival', 'Wulfric', 'Brian']
赋值语句的右边可以是任何类型的序列,但带星号的变量最终包含的总是一个列表。在变量和值的个数相同时亦如此。
>>> a, *b, c = "abc"
>>> a, b, c
('a', ['b'], 'c')
2.2 链式赋值
链式赋值是一种快捷方式,用于将多个变量关联到同一个值。
x = y = somefunction()
y = somefunction()
x = y
# 这两条语句不等价
x = somefunction()
y = somefunction()
2.3 增强赋值
可以不编写代码x = x + 1 ,而将右边表达式中的运算符(这里是+ )移到赋值运算符(= )的前面,从而写成x += 1 。这称为增强赋值 ,适用于所有标准运算符,如* 、/ 、% 等。
>>> x = 2
>>> x += 1
>>> x *= 2
>>> x
6
增强赋值也可用于其他数据类型(只要使用的双目运算符可用于这些数据类型)。
>>> fnord = 'foo'
>>> fnord += 'bar'
>>> fnord *= 2
>>> fnord
'foobarfoobar'
3. 条件和条件语句
3.1 布尔值
False None 0 "" () [] {};用作布尔表达式(如用作if 语句中的条件)时,这些值都将被解释器视为假 。
标准值False 和None 、各种类型(包括浮点数、复数等)的数值0、空序列(如空字符串、空元组和空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真,包括特殊值True 。
标准真值为0(表示假 )和1(表示真 )。实际上,True 和False 不过是0和1的别名,虽然看起来不同,但作用是相同的。
>>> True
True
>>> False
False
>>> True == 1
True
>>> False == 0
True
>>> True + False + 42
43
布尔值True 和False 属于类型bool ,而bool 与list 、str 和tuple 一样,可用来转换其他的值。
>>> bool('I think, therefore I am')
True
>>> bool(42)
True
>>> bool('')
False
>>> bool(0)
False
虽然[] 和"" 都为假(即bool([]) == bool("") == False ),但它们并不相等(即[] != "" )。对其他各种为假的对象来说,情况亦如此(一个更显而易见的例子是() != False )。
3.2 有条件的执行 和 if语句
if 语句,让你能够有条件地执行代码。这意味着如果条件 (if 和冒号之间的表达式)为前面定义的真 ,就执行后续代码块(这里是一条print 语句);如果条件为假 ,就不执行。
name = input('What is your name? ')
if name.endswith('Gumby'):
print('Hello, Mr. Gumby')
3.3 else语句
使用else 子句增加一种选择(之所以叫子句 是因为else 不是独立的语句,而是if 语句的一部分)。
name = input('What is your name?')
if name.endswith('Gumby'):
print('Hello, Mr. Gumby')
else:
print('Hello, stranger')
条件表达式
如果条件(紧跟在if 后面)为真,表达式的结果为提供的第一个值(这里为"friend" ),否则为第二个值(这里为"stranger" )。
status = "friend" if name.endswith("Gumby") else "stranger"
3.4 elif语句
要检查多个条件,可使用elif 。
num = int(input('Enter a number: '))
if num > 0:
print('The number is positive')
elif num < 0:
print('The number is negative')
else:
print('The number is zero')
3.5 代码嵌套
将if 语句放在其他if 语句块中
name = input('What is your name? ')
if name.endswith('Gumby'):
if name.startswith('Mr.'):
print('Hello, Mr. Gumby')
elif name.startswith('Mrs.'):
print('Hello, Mrs. Gumby')
else:
print('Hello, Gumby')
else:
print('Hello, stranger')
3.6 其他条件
01. 比较运算符
表达式 | 描述 |
---|---|
x == y | x 等于y |
x < y | x 小于y |
x > y | x 大于y |
x >= y | x 大于或等于y |
x <= y | x 小于或等于y |
x != y | x 不等于y |
x is y | x 和y 是同一个对象 |
x is not y | x 和y 是不同的对象 |
x in y | x 是容器(如序列)y 的成员 |
x not in y | x 不是容器(如序列)y 的成员 |
与赋值一样,Python也支持链式 比较:可同时使用多个比较运算符,如0 < age < 100 。
相等运算符
要确定两个对象是否相等,可使用比较运算符,用两个等号(== )表示。
一个等号是赋值运算符,用于修改 值。
>>> "foo" == "foo"
True
>>> "foo" == "bar"
False
# 一个等号会报错
>>> "foo" = "foo"
# SyntaxError: can't assign to literal
is:相同运算符
is 检查两个对象是否相同 (而不是相等 )。
变量x和y指向同一个列表,而z指向另一个列表(其中包含的值以及这些值的排列顺序都与前一个列表相同)。这两个列表虽然相等,但并非同一个对象 。
>>> x = y = [1, 2, 3]
>>> z = [1, 2, 3]
>>> x == y
True
>>> x == z
True
>>> x is y
True
>>> x is z
False
不要将is 用于数和字符串等不可变的基本值。鉴于Python在内部处理这些对象的方式,这样做的结果是不可预测的。
in :成员资格运算符
用于条件表达式中。
name = input('What is your name?')
if 's' in name:
print('Your name contains the letter "s".')
else:
print('Your name does not contain the letter "s".')
字符串和序列的比较
字符串是根据字符的字母排列顺序进行比较的。
>>> "alpha" < "beta"
True
>>> "a" < "B"
False
>>> "a".lower() < "B".lower()
True
>>> 'FnOrD'.lower() == 'Fnord'.lower()
True
02. 布尔运算符
运算符and 是一个布尔运算符。它接受两个真值,并在这两个值都为真时返回真,否则返回假。
or和not。
短路逻辑和条件表达式
布尔运算符有个有趣的特征:只做必要的计算。例如,仅当x 和y 都为真时,表达式x and y 才为真。因此如果x 为假,这个表达式将立即返回假,而不关心y 。如果x 为假,这个表达式将返回x ,否则返回y 。这种行为称为短路逻辑 (或者延迟求值 )。在表达式x or y 中,如果x 为真,就返回x ,否则返回y 。
3.7 断言
如果知道必须满足特定条件,程序才能正确地运行,可在程序中添加assert 语句充当检查点。
>>> age = 10
>>> assert 0 < age < 100
>>> age = -1
>>> assert 0 < age < 100
# Traceback (most recent call last):
# File "<stdin>", line 1, in ?
# AssertionError
>>> age = -1
>>> assert 0 < age < 100, 'The age must be realistic'
# Traceback (most recent call last):
# File "<stdin>", line 1, in ?
# AssertionError: The age must be realistic
4. 循环
4.1 while循环
打印1~100的所有数。
x = 1
while x <= 100:
print(x)
x += 1
4.2 for循环
可迭代对象是可使用for 循环进行遍历的对象。
words = ['this', 'is', 'an', 'ex', 'parrot']
for word in words:
print(word)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for number in numbers:
print(number)
>>> range(0, 10)
range(0, 10)
>>> list(range(0, 10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
打印数1~100
for number in range(1,101):
print(number)
只要能够使用for 循环,就不要使用while 循环。
4.3 迭代字典
遍历字典的关键字
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key, 'corresponds to', d[key])
也可使用keys 等字典方法来获取所有的键。如果要获取值,可使用d.values 。d.items 以元组的方式返回键-值对。for 循环的优点之一是,可在其中使用序列解包。
for key, value in d.items():
print(key, 'corresponds to', value)
字典元素的排列顺序是不确定的。换而言之,迭代字典的键或值时,一定会处理所有的键或值,但不知道处理的顺序。
4.4 迭代工具
01 并行迭代
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
for i in range(len(names)):
print(names[i], 'is', ages[i], 'years old')
内置函数zip ,它将两个序列“缝合”起来,并返回一个由元组组成的序列。返回值是一个适合迭代的对象,要查看其内容,可使用list 将其转换为列表。
>>> list(zip(names, ages))
[('anne', 12), ('beth', 45), ('george', 32), ('damon', 102)]
“缝合”后,可在循环中将元组解包。
for name, age in zip(names, ages):
print(name, 'is', age, 'years old')
函数zip 可用于“缝合”任意数量的序列。需要指出的是,当序列的长度不同时,函数zip 将在最短的序列用完后停止“缝合”。
>>> list(zip(range(5), range(100000000)))
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
02 迭代时获取索引
迭代对象序列的同时获取当前对象的索引,使用内置函数enumerate 。
替换一个字符串列表中所有包含子串'xxx' 的字符串。
for index, string in enumerate(strings):
if 'xxx' in string:
strings[index] = '[censored]'
enumerate()方法的实例。这个函数让你能够迭代索引-值对,其中的索引是自动提供的。
>>> seasons = ['Spring', 'Summer', 'Fall', 'Winter']
>>> list(enumerate(seasons))
[(0, 'Spring'), (1, 'Summer'), (2, 'Fall'), (3, 'Winter')]
>>> list(enumerate(seasons, start=1)) # 下标从 1 开始
[(1, 'Spring'), (2, 'Summer'), (3, 'Fall'), (4, 'Winter')]
03 反向迭代和排序后再迭代
方法reverse 和sort (sorted 接受的参数也与sort 类似),但可用于任何序列或可迭代的对象,且不就地修改对象,而是返回反转和排序后的版本。
>>> sorted([4, 3, 6, 8, 3])
[3, 3, 4, 6, 8]
>>> sorted('Hello, world!')
[' ', '!', ',', 'H', 'd', 'e', 'l', 'l', 'l', 'o', 'o', 'r', 'w']
>>> list(reversed('Hello, world!'))
['!', 'd', 'l', 'r', 'o', 'w', ' ', ',', 'o', 'l', 'l', 'e', 'H']
>>> ''.join(reversed('Hello, world!'))
'!dlrow ,olleH'
sorted 返回一个列表,而reversed 像zip 那样返回一个可迭代对象。不能对它执行索引或切片操作,也不能直接对它调用列表的方法。要执行这些操作,可先使用list 对返回的对象进行转换。
4.5 跳出循环
通常,循环会不断地执行代码块,直到条件为假或使用完序列中的所有元素。但在有些情况下,你可能想中断循环、开始新迭代(进入“下一轮”代码块执行流程)或直接结束循环。
01 break
要结束(跳出)循环,可使用break 。假设你要找出小于100的最大平方值,可从100开始向下迭代。找到一个平方值后,无需再迭代,因此直接跳出循环。
from math import sqrt
for n in range(99, 0, -1):
root = sqrt(n)
if root == int(root):
print(n)
break
02 continue
语句continue 没有break 用得多。它结束当前迭代,并跳到下一次迭代开头。这基本上意味着跳过循环体中余下的语句,但不结束循环。
for x in seq:
if condition1: continue
if condition2: continue
if condition3: continue
do_something()
do_something_else()
do_another_thing()
etc()
03 while True/break 成例
while True:
word = input('Please enter a word: ')
if not word: break
# 使用这个单词做些事情:
print('The word was ', word)
4.6 循环中的else子句
from math import sqrt
for n in range(99, 81, -1):
root = sqrt(n)
if root == int(root):
print(n)
break
else:
print("Didn't find it!")
5. 简单推导
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导 。列表推导的工作原理非常简单,有点类似于for 循环。
>>> [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> [x*x for x in range(10) if x % 3 == 0]
[0, 9, 36, 81]
>>> [(x, y) for x in range(3) for y in range(3)]
[(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2), (2, 0), (2, 1), (2, 2)]
# 用两个for循环
result = []
for x in range(3):
for y in range(3):
result.append((x, y))
>>> girls = ['alice', 'bernice', 'clarice']
>>> boys = ['chris', 'arnold', 'bob']
>>> [b+'+'+g for b in boys for g in girls if b[0] == g[0]]
['chris+clarice', 'arnold+alice', 'bob+bernice']
# 上面的方案效率不高,更佳的解决方案
girls = ['alice', 'bernice', 'clarice']
boys = ['chris', 'arnold', 'bob']
letterGirls = {}
for girl in girls:
letterGirls.setdefault(girl[0], []).append(girl)
print([b+'+'+g for b in boys for g in letterGirls[b[0]]])
使用圆括号代替方括号并不能实现元组推导,而是将创建生成器。可使用花括号来执行字典推导 。
# 在列表推导中,for 前面只有一个表达式,而在字典推导中,for 前面有两个用冒号分隔的表达式。这两个表达式分别为键及其对应的值。
>>> squares = {i:"{} squared is {}".format(i, i**2) for i in range(10)}
>>> squares[8]
'8 squared is 64'
6. pass、del、exec
6.1 什么都不做
>>> pass
>>>
编写代码时,可将其用作占位符。运行时不会报错。
if name == 'Ralph Auldus Melish':
print('Welcome!')
elif name == 'Enid':
# 还未完成……
pass
elif name == 'Bill Gates':
print('Access Denied')
6.2 使用del删除
# 最初,robin和scoundrel指向同一个字典,将None赋给scoundrel后,依然可以通过robin来访问这个字典。
# 但将robin也设置为None之后,这个字典就漂浮在计算机内存中,没有任何名称与之相关联,再也无法获取或使用它了。
# 因此,智慧无穷的Python解释器直接将其删除。这被称为垃圾收集。
# 请注意,在前面的代码中,也可将其他任何值(而不是None )赋给两个变量,这样字典也将消失。
>>> scoundrel = {'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin = scoundrel
>>> scoundrel
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> scoundrel = None
>>> robin
{'age': 42, 'first name': 'Robin', 'last name': 'of Locksley'}
>>> robin = None
使用del 语句,这不仅会删除到对象的引用,还会删除名称本身。
>>> x = 1
>>> del x
>>> x
# Traceback (most recent call last):
# File "<pyshell#255>", line 1, in ?
# x
# NameError: name 'x' is not defined
>>> x = ["Hello", "world"]
>>> y = x
>>> y[1] = "Python"
>>> x
['Hello', 'Python']
>>> del x
>>> y
['Hello', 'Python']
x 和y 指向同一个列表,但删除x 对y 没有任何影响,因为你只删除名称x ,而没有删除列表本身(值)。事实上,在Python中,根本就没有办法删除值,而且你也不需要这样做,因为对于你不再使用的值,Python解释器会立即将其删除。
6.3 使用exec 和eval 执行字符串及计算其结果
01 exec
>>> exec("print('Hello, world!')")
Hello, world!
调用函数exec 时只给它提供一个参数绝非好事。在大多数情况下,还应向它传递一个命名空间 ——用于放置变量的地方;否则代码将污染你的命名空间,即修改你的变量。例如,假设代码使用了名称sqrt :
>>> from math import sqrt
>>> exec("sqrt = 1")
>>> sqrt(4)
# Traceback (most recent call last):
# File "<pyshell#18>", line 1, in ?
# sqrt(4)
# TypeError: object is not callable: 1
函数exec 主要用于动态地创建代码字符串。如果这种字符串来自其他地方(可能是用户),就几乎无法确定它将包含什么内容。因此为了安全起见,要提供一个字典以充当命名空间。
>>> from math import sqrt
>>> scope = {}
>>> exec('sqrt = 1', scope)
>>> sqrt(4)
2.0
>>> scope['sqrt']
1
02 eval
eval 是一个类似于exec 的内置函数。exec 执行一系列Python语句,而eval 计算用字符串表示的Python表达式的值,并返回结果(exec 什么都不返回,因为它本身是条语句)。
>>> eval(input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 6 + 18 * 2
42