操作列表
遍历整个列表
在Python中我们使用for循环来遍历列表(当然其它语言中也普遍用for来遍历列表),总体来说,Python的for循环是比较容易写清楚的了;
#建立一个交通工具列表
transportations = ['bus', 'truck', 'bicycle', 'subway', 'car', 'airplane']
# for循环遍历
for transportation in transportations:
print(transportation)
bus
truck
bicycle
subway
car
airplane
解释一下这段代码的内涵,这里实际上是从transportations中取出一个元素给transportation;这里transportation是一个临时变量,然后把transportation变量中的内容打印出来。for循环会不断列表中取出一个元素;直到将列表中元素取完。
当然,for循环的写法不止这一种,请看另外一种Python的for循环的写法:
for x in range(6):
print(transportations[x])
bus
truck
bicycle
subway
car
airplane
可以看到这两种for循环的运行结果完全相同,程序就是这样,实际上程序可以有很多灵活的写法。如果你问我哪种写法看起来更好,我觉得是第一种更好,这种看起来更容易理解,变量名非常容易理解,使用起来也很方便,也充分发挥了Python语言的特点。
注意,务必要好好取变量名,尽可能选取符合它的描述。
transportations = ['bus', 'truck', 'bicycle', 'subway', 'car', 'airplane']
citys = ['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
for city in citys:
for transportation in transportations:
print(f"I'm going to take a {transportation} to {city}")
以上是一个双层循环,注意:这里print语句缩进的是8个字符,Python没有{}的语句块,因为非常依赖于缩进的格式。如果不进行相应的缩进,则会出现这样的错误:
File "E:\PycharmProjects\......\.......py", line 13
print(f"I'm going to take a {transportation} to {city}")
^
IndentationError: expected an indented block
这就是在提示我们需要注意缩进。同时,for循环还要注意冒号的问题,for循环需要用冒号来告诉Python下一行是循环的第一行。
创建数值列表
我们可以利用列表来存储数字,而不仅仅是字符串。
最普通的数字列表是自己进行赋值的;
numbers = [1, 2, 3, 4, 5]
print(numbers)
在这里介绍几种函数;Python中有一个较为好用的range函数可以进行分配数字;函数语法为range(start, stop, step);这三个参数都是可选的参数,然而调用这个函数输入至少一个参数。当我们只输入一个参数x的时候,则表示范围从0到x,并且不包括x。
参数 | 描述 |
---|---|
start | 可选。整数,指定从哪个位置开始。默认为 0。 |
stop | 可选。整数,指定在哪个位置结束。 |
step | 可选的。整数,指定增量。默认为 1。 |
numbers = range(4)
for i in numbers:
print(i)
0
1
2
3
所以如果输入两个参数是什么情况?range函数并不会去猜测输入的两个参数到底是谁,而是默认为start和stop两个参数。不要尝试去指定参数,例如这样使用range(start = 0, stop = 10),设计range函数的人明显不允许别人这样使用,因为我尝试了一下。
for i in range(0,4):
print(i)
0
1
2
3
写入三个参数的情况,写入的三个,其顺序是默认的,start,stop,step。
for i in range(0,4,2):
print(i)
0
2
很明显,这是可以看出来的,range函数参照step=2生成一个序列,具体是:从0开始,按照步长为2,选中0~4中的数字,并且不包括4。
for i in range(0,5,2):
print(i)
0
2
4
当然,既然可以正序,那为什么不可以倒序呢,完全是可以的,我们只需要把步长设置为负数就可以了。
for i in range(0,5,-2):
print(i)
这是否是一段正确的程序?从语法上这是完全正确的语句,但是可以肯定的是,没有输出。因为,按照上述的说法:从0开始,按照步长为-2选中,05的整数,然而0-2=-2,即0后要输出-2,而-2并不在05之间,之后的-4等一些列数字都不在,故输出为0。
numbers = list(range(0, 5, -2))
print(numbers)
[]
结果也是这样,numbers完全是一个空的列表。
numbers = list(range(5, 0, -2))
print(numbers)
[5, 3, 1]
所以,有时候编译器并没有报错,但是程序却得不到我们想要的结果;很有可能是我们的程序不是语法出错,而是存在逻辑错误。
注意range函数的所有参数都是整数,并且其生成的序列的各个元素也是整数。
如果我们想知道,1~10以内整数的4次方都是多少需要怎么做?
squares = []
for number in range(1, 11):
squares.append(number**4)
print(squares)
[1, 16, 81, 256, 625, 1296, 2401, 4096, 6561, 10000]
如果,你看过前面的知识就发现这段程序实际上非常好理解,从1~10中依次取出数字给number,再将number的4次方追加到squares列表后面,并输出squares。这一段写得很好,但仍然有改进空间。
squares = [number**4 for number in range(1, 11)]
print(squares)
[1, 16, 81, 256, 625, 1296, 2401, 4096, 6561, 10000]
这无疑是一种比较高级的语法,其功能与上面的长一些的代码功能相同。这里首先定义了一个列表名为squares的列表,列表的元素为number**4,也即number的4次方,而number是由谁给出的呢?是从后面的for循环,从range(1,11)中选出的。
使用列表的一部分
使用列表的一部分,对于Python来说是比较容易的,最主要的办法就是创建切片,而切片实际上就是通过下标,来选择列表的一部分,理解了这个就比较容易了。
cities = ['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
someCities = cities[:3]
print(someCities)
['Beijing', 'Nanjing', 'Shanghai']
从这里,就可以窥探出一个事情,就是切片的下标实际上可以这样理解[start:stop:step],并且不包括stop,从上面的示例可以知道,start默认为0,从下标为0,取到下标为2的元素。
someCities = cities[4:]
print(someCities)
['Tainjin', 'Guangzhou']
当然我们也可以不写stop下标,则默认取到最后一个元素。
有时候列表过长,我们并不会记得总共的长度是多少,但是我们想去倒数的元素,那应该如何做?
someCities = cities[-4:]
print(someCities)
['Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
这样我们就取了cities列表最后四个元素。当然可以肯定地是,这里类似于range函数,我们也可以指定step值,也就是步长值。
cities = ['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
someCities = cities[-4::-2]
print(someCities)
['Shanghai', 'Beijing']
看到以上代码,不知道,你是否感到疑惑,为什么是这样取的。这段代码的含义是:从cities的下标为-4的元素开始取,然后再依次取-6,-8,-10等元素(如果有的话),所以得到的列表就是这样。
因此我们又能想到一种列表倒置的方法:
cities = ['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
someCities = cities[-1::-1]
print(someCities)
['Guangzhou', 'Tainjin', 'Chengdu', 'Shanghai', 'Nanjing', 'Beijing']
注意:我个人认为someCities实际上是cities的深拷贝。
cities = ['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
for city in cities:
print(id(city))
2078930038384
2078930038448
2078930038576
2078930038320
2078930039536
2078930040240
someCities = cities[-1::-1]
print(someCities)
for someCity in someCities:
print(id(someCity))
['Guangzhou', 'Tainjin', 'Chengdu', 'Shanghai', 'Nanjing', 'Beijing']
2078930040240
2078930039536
2078930038320
2078930038576
2078930038448
2078930038384
发现了么,对于相同的元素,其元素的地址相同。
cities2 = cities[:]
cities.append('Shenyang')
cities2.append('Hangzhou')
print(cities)
print(cities2)
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Shenyang']
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Hangzhou']
对cities增加一个元素的时候,并没有影响到cities2,而对cities2增加一个元素的时候,也没有影响到cities。
for city in cities:
print(id(city))
print('\n')
for city2 in cities2:
print(id(city2))
1422093512432
1422093505456
1422093505136
1422093504624
1422093504560
1422093506160
1422093506288
1422093512432
1422093505456
1422093505136
1422093504624
1422093504560
1422093506160
1422093506352
观察各自的地址可以看到,相同地址的元素相同,而不同的地址的元素不同。
也许你会问什么是浅拷贝。
浅拷贝
cities2 = cities
print(cities)
print(cities2)
cities.append('Shenyang')
cities2.append('Hangzhou')
print(cities)
print(cities2)
猜猜它的结果是什么样的?
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou']
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Shenyang', 'Hangzhou']
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Shenyang', 'Hangzhou']
我想,也许这和你想的很不一样,你认为再次输出cities列表,其最后一个元素应该是‘Shenyang’,而不是现在的‘Hangzhou’。所以造成这种问题的原因是什么,就是浅拷贝。这里,并不是把cities的列表的副本给了cities2,而是将同一个列表关联到两个变量cities和cities2上。
print('id cities:', id(cities))
print('id cities2:', id(cities2))
id cities: 2235346006336
id cities2: 2235346006336
在这种情况下,它们具有相同的id。
而对于之前提到的深拷贝,其结果是这样的:
cities2 = cities[:]
cities.append('Shenyang')
cities2.append('Hangzhou')
print(cities)
print(cities2)
print('id cities:', id(cities))
print('id cities2:', id(cities2))
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Shenyang']
['Beijing', 'Nanjing', 'Shanghai', 'Chengdu', 'Tainjin', 'Guangzhou', 'Hangzhou']
id cities: 2964343763264
id cities2: 2964344128320
元组
元组与列表的不同之处关键在于:列表的值是能够可以改变的,而元组的值是不能够改变的。元组与列表非常相似,但使用圆括号而非中括号来标识。同样的,定义元组后,就可使用索引来访问其元素,就像访问列表元素一样。
cuboid = (100,50,70)
cuboid[1] = 60
在这里,我先定义了元组cuboid,然后开始尝试修改元组下标为1的元素,即cuboid[1] = 60;此时编译器报错。
Traceback (most recent call last):
File "E:\PycharmProjects\learn\tuple.py", line 3, in <module>
cuboid[1] = 60
TypeError: 'tuple' object does not support item assignment
报错类型是TypeError,错误是‘tuple’ object does not support item assignment,意思是元组对象不允许指派,即修改元组的操作是被禁止的,因此Python指出不能给元组的元素修改。
虽然,我们不能对元组的元素值进行修改,但是我们能够重新复制,这可以理解为对变量重新分派一个值。就像我说过的,变量名有点像一个指针,而指针本身只是指向某个空间,并非真正存储什么值,所以可以改变它的指向。
cuboid = (100, 50, 70)
for dimension in cuboid:
print(dimension)
cuboid = (100, 80, 120)
for dimension in cuboid:
print(dimension)
100
50
70
100
80
120
这里可以看出,对cuboid这个变量,重新进行赋值是完全可以的。元组是一种更为简单的数据结构,如果一些数据在程序的整个生命周期内都不变,就可以使用元组。
设置代码格式
针对这个部分,我的建议是可以去看一下《代码简洁之道》这本书。当然,本书仍有很多有价值的提议。
编程就像写作,编程不仅仅是要解决问题,同时要保证程序是可以进行维护的,可以进行更改的,这非常重要,当我们用某种思路解决了一个问题以后,并不意味着这就结束了,这意味着我们要思考这段代码应该如何进行优化
缩进方面,PEP 8(Python Enhancement Proposal)建议每级缩进都是用四个空格,实际上,Pycharm初始就是这样设置的,应该大部分Python编译器都遵循这样的约定。当然了,有人喜欢用空格键来进行缩进,有人喜欢用Tab 制表符键来进行缩进,本人比较偏向于Tab键,因为再设置之后Tab键按一下就可以达到四个空格的缩进。
《Python编程从入门到实践 第2版》一书建议行长为79个字符,PEP 8建议注释的行长不应该超过72字符,我的认为是,由于现在的屏幕越来越大,每个人显示的字体大小不同,可以考虑有一个并非如此严格的行长习惯,代码行长的具体长度是要保证不拥挤即可。
不要介意使用空行来对代码进行分行,空行不会影响代码的运行,但是会影响代码的整洁度和可读性,但是也不要随意空行,这就像文章的段落,总不能在将好多事情都写在一个段落里吧?但也不能把一件事写的凌乱,明明是一件事情,却分了好几段,也是不好的。