1 再谈print及import
1.1 print
print函数的原型如下:print(arg1,arg2,…,sep=“具体分隔符”,end="具体结束符")
。
- 默认情况下在使用print打印多个参数时,各个参数之间用空格隔开;
- 在使用sep指定具体分隔符时,使用指定的分隔符来分割各个参数;
- 默认情况下print语句的结束符为换行符,可以使用end来指定打印完各个百年来那个后的分隔符。
>>> print("hello","world")
hello world
>>> print("Age:",26)
Age: 26
>>> print("hello","world",sep="_")
hello_world
#未指定结束符时,默认以换行符结束
print("Hello","World")
print("Welcome","to","BeiJing")
E:\WorkDir\Python\venv\Scripts\python.exe E:/WorkDir/Python/test.py
Hello World
Welcome to BeiJing
#采用指定的结束符来结束
print("Hello","World",end="! ")
print("Welcome","to","BeiJing",end='.')
E:\WorkDir\Python\venv\Scripts\python.exe E:/WorkDir/Python/test.py
Hello World! Welcome to BeiJing.
Process finished with exit code 0
1.2 import导入时重命名
从模块导入时,通常使用import somemodule
或使用from somemodule import somefunction
或from somemodule import somefunction, anotherfunction, yetanotherfunction
或from somemodule import *
。仅当你确定要导入模块中的一切时,采用使用最后一种方式。但如果有两个模块,它们都包含函数open,该如何办呢?你可使用第一种方式导入这两个模块,并像下面这样调用函数:
module1.open(...)
module2.open(...)
但还有一种办法:在语句末尾添加as子句并指定别名。下面是一个导入整个模块并给它指定别名的例子:
>>> import math as foobar
>>> foobar.sqrt(4)
2.0
下面是一个导入特定函数并给它指定别名的例子:
>>> from math import sqrt as foobar
>>> foobar(4)
2.0
对于前面的函数open,可像下面这样导入它们:
from module1 import open as open1
from module2 import open as open2
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: not enough values to unpack (expected 3, got 2)
可使用星号运算符(*)来收集多余的值,这样无需确保值和变量的个数相同,如下例所示:
>>> 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()
有关这方面的详细信息,请参阅5.4.6节介绍相同运算符(is)的部分。
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 布尔表达式
用作布尔表达式(如用作if语句中的条件)时,下面的值都将被解释器视为假:
False None 0 "" () [] {}
换而言之,标准值False和None、各种类型(包括浮点数、复数等)的数值0、空序列(如空字符串、空元组、空列表)以及空映射(如空字典)都被视为假,而其他各种值都被视为真(包括特殊值True)。
3.2 比较运算符
- 理论上,用<和<=等运算符可以比较任意两个对象x和y的相对大小,并获得一个真值,但这种比较仅在x和y的类型相同或相近时(如两个整数或一个整数和一个浮点数)才有意义。
- 在Python 3中,已经不允许这样比较不兼容的类型了,并且不允许对不兼容的类型进行操作(如将int与str相加等);
- ==用来检查两个对象是否相等,而is用来检查两个对象是否相同(是同一个对象)。
>>> 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在内部处理这些对象的方式,这样做的结果是不可预测的。
>>> 10 is 10
True
>>> 10 is 11
False
>>>
>>>
>>> "hello" is "hello"
True
>>>
>>> "hello" is "world"
False
>>>
>>>
>>> x="hello"
>>> y="hello"
>>> x is y
True
>>>
>>>
>>> x=1
>>> y=1
>>> x is y
True
3.3 if..elif..else语句
if condition1:
语句1
语句2
…
elif condition2:
语句3
语句4
…
else:
语句5
语句6
…
3.4 assert关键字
assert condition,可选说明(在断言为False而报出的错误中会进行说明)
>>> x=10
>>> assert x<100
>>> assert x<9,"x>=9"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: x>=9
4 循环语句
4.1 while循环
while condition:
语句1
语句2
……
例如:打印出 1-10的整数
x=1
while x<=10:
print(x,end=' ')
x+=1
4.2 for循环
while语句非常灵活,可用于在条件为真时反复执行代码块。这在通常情况下很好,但有时候你可能想根据需要进行定制。一种这样的需求是为序列(或其他可迭代对象)中每个元素执行代码块。
for para in sequence:
语句1
语句2
……
注意:
- 基本上,可迭代对象是可使用for循环进行遍历的对象。后续将详细介绍可迭代对象和迭代器。就目前而言,只需将可迭代对象视为序列即可。
- 可以使用
range(start,end)
来创建一个可迭代的范围[start,end),或者使用range(end)
创建范围[0,end)。
>>> range(1,10)
range(1, 10)
>>> list(range(1,10))
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
例如:
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)
#打印1-100之间的整数
for number in range(1,101):
print(number)
5 一些常用的迭代工具
5.1 zip并行迭代
有时候,你可能想同时迭代两个序列。假设有下面两个列表:
names = ['anne', 'beth', 'george', 'damon']
ages = [12, 45, 32, 102]
如果要打印名字和对应的年龄,可以像下面这样做:
for i in range(len(names)):
print(names[i], 'is', ages[i], 'years old')
i是用作循环索引的变量的标准名称。一个很有用的并行迭代工具是内置函数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)]
5.2 使用enumerate同时遍历索引和内容
strings=['this','is','a','good','girl']
for index,context in enumerate(strings):
print(index,context)
#运行结果
0 this
1 is
2 a
3 good
4 girl
5.3 反向迭代和排序后再迭代
来看另外两个很有用的函数:reversed和sorted。它们类似于列表方法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那样返回一个更神秘的可迭代对象。你无需关心这到底意味着什么,只管在for循环或join等方法中使用它,不会有任何问题。只是你不能对它执行索引或切片操作,也不能直接对它调用列表的方法。要执行这些操作,可先使用list对返回的对象进行转换。
5.4 跳出循环:break,continue
要结束(跳出)循环,可使用break。假设你要找出小于100的最大平方值(整数与自己相乘的结果),可从100开始向下迭代。找到一个平方值后,无需再迭代,因此直接跳出循环。
from math import sqrt
for n in range(99, 0, -1):
root = sqrt(n)
if root == int(root):
print(n)
break
使用continue
for x in seq:
if condition1: continue
if condition2: continue
if condition3: continue
do_something()
do_something_else()
do_another_thing()
etc()
while True...break示例
while True:
word = input('Please enter a word: ')
if not word: break
# 使用这个单词做些事情:
print('The word was ', word)
5.5 和循环配套使用的else子句
在循环中添加的else子句,它仅在循环中没有调用break时才执行
from math import sqrt
for n in range(99, 81, -1):
root = sqrt(n)
if root == int(root):
print(n)
break
else: #在循环中添加的else子句,它仅在循环中没有调用break时才执行
print("Didn't find it!")
6 各种推导式
6.1 列表推导
列表推导是一种从其他列表创建列表的方式,类似于数学中的集合推导。列表推导的工作原理非常简单,有点类似于for循环。
>>> [x * x for x in range(10)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
这个列表由range(10)内每个值的平方组成,非常简单吧?如果只想打印那些能被3整除的平方值,该如何办呢?可使用求模运算符:如果y能被3整除, y%3 将返回(请注意,仅当x能被3整除时, x*x才能被3整除)。为实现这种功能,可在列表推导中添加一条if语句。
>>> [x*x for x in range(10) if x 3 == 0] %
[0, 9, 36, 81]
还可添加更多的for部分。
>>> [(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))
与以前一样,使用多个for部分时,也可添加if子句。
>>> 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']
这些代码将名字的首字母相同的男孩和女孩配对。
上述代码要遍历所有的boys和girls,效率比较低,下面是一种更好的解决方案解决方案:
girls=['alice','bernice','clarice','apple']
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]]])
#执行结果:
['chris->clarice', 'arnold->alice', 'arnold->apple', 'bob->bernice']
这个程序创建一个名为letterGirls的字典,其中每项的键都是一个字母,而值为以这个字母开头的女孩名字组成的列表(字典方法setdefault在前一章介绍过)。创建这个字典后,列表推导遍历所有的男孩,并查找名字首字母与当前男孩相同的所有女孩。这样,这个列表推导就无需尝试所有的男孩和女孩组合并检查他们的名字首字母是否相同了。
6.2 ()生成generator
将列表推导式的[]改成()即可得到生成器。
multiples = (i for i in range(30) if i % 3 is 0)
print(type(multiples))
# Output: <type 'generator'>
6.3 字典推导
字典推导和列表推导的使用方法是类似的,只不中括号该改成大括号。直接举例说明:
例一:大小写key合并
mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}
mcase_frequency = {
k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)
for k in mcase.keys()
if k.lower() in ['a','b']
}
print(mcase_frequency)
# Output: {'a': 17, 'b': 34}
例二:快速交换key和value
mcase = {'a': 10, 'b': 34}
mcase_frequency = {v: k for k, v in mcase.items()}
print(mcase_frequency)
# Output: {10: 'a', 34: 'b'}
6.4 集合推导式
它们跟列表推导式也是类似的。 唯一的区别在于它使用大括号{}。集合推导式的结果中删除了重复的元素。
>>> squared={x**2 for x in [1,1,2]}
>>> squared
{1, 4}
7 pass、 del、 exec和eval
- pass语句什么都不做,但适合用作占位符。
- del语句用于删除变量或数据结构的成员,但不能用于删除值。
- 函数exec用于将字符串作为Python程序执行。
- 函数eval计算用字符串表示的表达式并返回结果
7.1 exec
函数exec将字符串作为代码执行。
>>> exec("print('Hello, world!')")
Hello, world!
为了放置exec中执行的程序污染代码,在执行exec函数时,可以向其传递一个命名空间。实际上,可向exec提供两个命名空间:一个全局的和一个局部的。提供的全局命名空间必须是字典,而提供的局部命名空间可以是任何映射。这一点也适用于eval。
>>> from math import sqrt
#传递过来的sqrt变量和当前模块中的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
#使用字典scope作为exec的命名空间
>>> from math import sqrt
>>> scope = {}
>>> exec('sqrt = 1', scope)
>>> sqrt(4)
2.0
>>> scope['sqrt']
1
7.2 eval
eval是一个类似于exec的内置函数。 exec执行一系列Python语句,而eval计算用字符串表示的Python表达式的值,并返回结果(exec什么都不返回,因为它本身是条语句)。
>>> eval(input("Enter an arithmetic expression: "))
Enter an arithmetic expression: 6 + 18 * 2
42
网友评论