操作列表《Python编程:从入门到实践 第2版》笔记

操作列表

遍历整个列表

在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字符,我的认为是,由于现在的屏幕越来越大,每个人显示的字体大小不同,可以考虑有一个并非如此严格的行长习惯,代码行长的具体长度是要保证不拥挤即可。

不要介意使用空行来对代码进行分行,空行不会影响代码的运行,但是会影响代码的整洁度和可读性,但是也不要随意空行,这就像文章的段落,总不能在将好多事情都写在一个段落里吧?但也不能把一件事写的凌乱,明明是一件事情,却分了好几段,也是不好的。

你可能感兴趣的:(Python,原创,python,开发语言)