简明Python3教程 11.数据结构

简介

数据结构基本上就是 – 可以将一些数据结合到一起的结构,换言之用于存储一组相关的数据。

python拥有4种内建数据结构 – 列表,元组(tuple),字典和集合。

我们将看到如何它们,它们又是怎样使我们的编程生涯变的惬意~

 

列表

列表是一种用于保存有序元素集合的数据结构,即你可以在列表中存储元素序列。

考虑一个购物清单,上面有你需要购买的物品列表,只不过你可能希望以行分隔它们而到了python变成了逗号。

这样想来就容易理解列表了吧。

列表元素应该被封闭在方括号中,这样python才会明白你指定的是一个列表。

一但列表创建完毕,你可以对其元素进行添加,删除和搜索。

正因为可以执行添加和删除操作,我们将列表称作可变类型,即这种类型可以被修改。

 

对象和类快速简介

尽管我一直推迟讨论对象和类,但现在需要对其进行少量的说明好让你更好的理解列表。后面会在相应的章节深入研究类和对象。

列表是使用对象和类的一个例子。当我们为变量i赋值时,例如赋值5,这相当于创建一个int类(类型)的对象(实例)i

事实上你可以阅读help(int)的输出更好的理解它。

一个类同样可以拥有方法,即函数,而且它们只能应用于这个类。并且只有当你拥有一个类的对象时才能使用这些功能。

例如,python为列表类提供了一个append方法允许你将新的元素添加到列表尾。

举个例子,mylist.append(‘an item’)将字符串添加到列表mylist的尾部。注意要使用点号访问对象的方法。

一个类还可以拥有字段,而字段只不过是专门应用于一个类的变量而已。当你拥有对应类的对象时就能使用这些变量/名字了。

字段同样利用点号访问,例如mylist.field

范例:

#!/usr/bin/python

# Filename: using_list.py

# This is my shopping list

shoplist = ['apple', 'mango', 'carrot', 'banana']

print('I have', len(shoplist), 'items to purchase.')

print('These items are:', end=' ')

for item in shoplist:

    print(item, end=' ')

print('/nI also have to buy rice.')

shoplist.append('rice')

print('My shopping list is now', shoplist)

print('I will sort my list now')

shoplist.sort()

print('Sorted shopping list is', shoplist)

print('The first item I will buy is', shoplist[0])

olditem = shoplist[0]

del shoplist[0]

print('I bought the', olditem)

print('My shopping list is now', shoplist)

输出:

    $ python using_list.py

    I have 4 items to purchase.

    These items are: apple mango carrot banana

    I also have to buy rice.

    My shopping list is now ['apple', 'mango', 'carrot', 'banana', 'rice']

    I will sort my list now

    Sorted shopping list is ['apple', 'banana', 'carrot', 'mango', 'rice']

    The first item I will buy is apple

    I bought the apple

    My shopping list is now ['banana', 'carrot', 'mango', 'rice']

工作流程:

变量shoplist是某个购物人的购物清单。

我们只在shoplist中存储被购买物品的名字的字符串,但你也可以为列表增加任何其它种类的对象,包括数字甚至是其它列表。

我们通过for…in迭代列表元素,现在你一定意识到一个列表也是一个序列了吧。有关序列的特点我们会在后节讨论。

注意printend关键字实参,它指定我们希望以空格结束输出而不是通常的换行。

接下来我们使用列表对象的append方法为列表添加一个新的元素。

为了确定元素真的被添加进去了,我们简单的将列表传给print函数,print函数整洁的将列表内容打印出来。

随后我们使用列表的sort方法对列表进行排序,紧记sort会影响列表本身而不是返回一个被修改后的列表。

这与字符串的工作方式不同。这也是为什么说类标是可变类型而字符串是不可变类型的原因。

然后当在市场购买一样东西后,我们希望将其从列表中删除,del语句正是用武之地。

在这里我们指出希望删除列表中的哪个元素,del就将这个元素从列表中删除。

我们指定的是希望删除列表的第一个元素,因此我们使用del shoplist[0](回想一下,python的索引从0开始)。

如果你想知道list对象的所有方法,详见help(list)

 

元组

元组用于保存各种各样的对象。它与列表很相似,但它缺少列表提供的大量功能。

列表的一个主要特点就象字符串一样,它是不可变类型,也就是说你不可以修改元组。

元组通过一组以逗号分隔的元素定义,并以一个可选的小括号闭合。

元组通常用于这样的情形,一个语句或一个用户定义的函数能够安全的假设其使用的一组值(即元组值)不会发生改变。

范例:

#!/usr/bin/python

# Filename: using_tuple.py

zoo = ('python', 'elephant', 'penguin') # 注意小括号是可选的

print('Number of animals in the zoo is', len(zoo))

new_zoo = ('monkey', 'camel', zoo)

print('Number of cages in the new zoo is', len(new_zoo))

print('All animals in new zoo are', new_zoo)

print('Animals brought from old zoo are', new_zoo[2])

print('Last animal brought from old zoo is', new_zoo[2][2])

print('Number of animals in the new zoo is',

len(new_zoo)-1+len(new_zoo[2]))

输出:

    $ python using_tuple.py

    Number of animals in the zoo is 3

    Number of cages in the new zoo is 3

    All animals in new zoo are ('monkey', 'camel', ('python', 'elephant', 'penguin'))

    Animals brought from old zoo are ('python', 'elephant', 'penguin')

    Last animal brought from old zoo is penguin

    Number of animals in the new zoo is 5

代码如何工作:

变量zoo引用一个元组。我们看到len函数可以得到元组的长度。这也表明元组同样是一个序列类型。

因为老动物园歇菜了,于是我们将这些动物转移到一个新的动物园。因此元组new_zoo既包含已有的动物又包含从老动物园转移过来的新动物。

言归正传,注意一个包含在其它元组内的元组并不会丢失它的身份。

(注:包含元组会引用被包含元组,即在包含元组内对被包含元组的操作会反应到被包含元组自身之上,有点绕口。。。)

像列表一样,我们可以通过一对方括号指定元素的位置访问这个元素。这叫做索引操作符。

我们通过new_zoo[2]访问new_zoo的第三个元素,通过new_zoo[2][2]访问new_zoo的第三个元素的第三个元素。

一但你理解这种语言风格,这样的操作太安逸了。

 

小括号

虽然小括号是可选的,但我强烈建议你坚持使用小括号,这样一眼就能看出它是个元组,尤其还能避免出现歧义。

例如,print(1, 2, 3)print((1, 2, 3))是不同的 – 前者打印3个数字而后者打印一个元组(包含3个数字)。

 

拥有0个或1个元素的元组

一个空元组通过空小括号创建,例如myempty = ()

不过,指定一个单元素元组就不那么直观了。你必须在其仅有的一个元素后跟随一个逗号,这样python才能区分出

你要的是元组而不是一个被小括号包围的对象的表达式。例如你想要一个包含值为2的单元素元组,则必须写成singleton = (2, )

 

perl程序员请注意(注:对不起perl程序员,我是perl盲。。。不知道说的啥,以后可能补充翻译)

A list within a list does not lose its identity i.e. lists are not flattened as in Perl. The

same applies to a tuple within a tuple, or a tuple within a list, or a list within a tuple,

etc. As far as Python is concerned, they are just objects stored using another object,

that's all.

 

字典

字典就像通讯录,只要知道联系人的名字就能找到他的地址或详细信息。即我们将(名字)与(相关信息)联系到一起。

注意键必须是唯一的,这就像如果两个人同名你就没法找到正确的信息了。

还有字典的键必须是不可变对象(比如字符串),但字典的值可以是可变或不可变对象。基本上这意味着只能将简单的对象作为键。

字典中的键值对使用语法d = {key1 :value1, key2: value2}指定。

其中键和值由分号分隔而所有的键值对用逗号分隔,并且它们被括在一对大括号内。

记住字典中的键值对是无序的。如果你希望按照特定的顺序排列它们,你只能在使用前自己排序。

而你实际使用的字典是dict类的对象/实例。

范例:

#!/usr/bin/python

# Filename: using_dict.py

# 'ab'是'a'ddress'b'ook的缩写

ab = {  'Swaroop'   : 'swaroop@swaroopch.com',

        'Larry'     : 'larry@wall.org',

        'Matsumoto' : 'matz@ruby-lang.org',

        'Spammer'   : 'spammer@hotmail.com'

    }

print("Swaroop's address is", ab['Swaroop'])

# 删除一个键值对

del ab['Spammer']

print('/nThere are {0} contacts in the address-book/n'.format(len(ab)))

for name, address in ab.items():

    print('Contact {0} at {1}'.format(name, address))

# 添加一个键值对

ab['Guido'] = 'guido@python.org'

if 'Guido' in ab: # OR ab.has_key('Guido')

    print("/nGuido's address is", ab['Guido'])

Output:

    $ python using_dict.py

    Swaroop's address is swaroop@swaroopch.com

   

    There are 3 contacts in the address-book

   

    Contact Swaroop at swaroop@swaroopch.com

    Contact Matsumoto at matz@ruby-lang.org

    Contact Larry at larry@wall.org

   

    Guido's address is guido@python.org

代码如何工作:

我们使用先前介绍的语法创建字典ab。然后使用在列表和元组部分讨论过的索引操作符指定字典键访问键值对。多简单的语法阿。

我们的老朋友del语句可以帮助我们删除键值对。只需简单的为索引操作符指定被删除的键,再将其传给del语句就哦了。

执行删除操作时我们无需理会键所对应的值。

接下来我们使用字典的items方法访问字典的键值对,它会返回一个包含键值对元组的列表 – 值跟在键后面。

for…in循环中我们检索每个键值对并将它们分别赋给变量nameaddress,之后在循环体中打印它们。

利用索引操作符访问一个键并对其赋予一个值我们可以增加一个新的键值对,就象本例中的Guido那样。

通过dict类的has_key可以检查字典中是否存在某个键值对。你可以执行help(dict)找到字典所有方法的列表。

 

关键字实参与字典

如果你已经在函数中使用过关键字实参,那么你也已经使用过字典了!

你可以这样理解 – 你在函数定义时的形参列表中指定了键值对,当你在函数中访问这些变量的时候只不过是在访问一个字典

(在编译器设计的术语中这被称作符号表)

 

序列

列表,元组和字符串都是序列的例子,但到底序列是啥呢?为什么它对我们的意义如此特别?

序列最主要的特点在于支持成员从属测试(即,表达式中的innot in操作)和索引操作。

其中索引操作允许我们直接地获取序列中的指定元素。

以上说到的三种序列类型 – lists,tuples,strings还支持一种切片操作,允许我们得到序列的一个切片,即序列的部分。

范例:

#!/usr/bin/python

# Filename: seq.py

shoplist = ['apple', 'mango', 'carrot', 'banana']

name = 'swaroop'

# Indexing or 'Subscription' operation

print('Item 0 is', shoplist[0])

print('Item 1 is', shoplist[1])

print('Item 2 is', shoplist[2])

print('Item 3 is', shoplist[3])

print('Item -1 is', shoplist[-1])

print('Item -2 is', shoplist[-2])

print('Character 0 is', name[0])

# Slicing on a list

print('Item 1 to 3 is', shoplist[1:3])

print('Item 2 to end is', shoplist[2:])

print('Item 1 to -1 is', shoplist[1:-1])

print('Item start to end is', shoplist[:])

# Slicing on a string

print('characters 1 to 3 is', name[1:3])

print('characters 2 to end is', name[2:])

print('characters 1 to -1 is', name[1:-1])

print('characters start to end is', name[:])

Output:

    $ python seq.py

    Item 0 is apple

    Item 1 is mango

    Item 2 is carrot

    Item 3 is banana

    Item -1 is banana

    Item -2 is carrot

    Character 0 is s

    Item 1 to 3 is ['mango', 'carrot']

    Item 2 to end is ['carrot', 'banana']

    Item 1 to -1 is ['mango', 'carrot']

    Item start to end is ['apple', 'mango', 'carrot', 'banana']

    characters 1 to 3 is wa

    characters 2 to end is aroop

    characters 1 to -1 is waroo

    characters start to end is swaroop

代码如何工作:

首先我们看看如何使用索引得到序列的单个元素。这也被称作下标操作。

正如上面的代码,每当你在序列旁的方括号中指定一个数字的时候,python会获取这个索引所对应的序列元素。

回想一下,python的索引从0开始计算。因此shoplist[0]获取序列shplist的第一个元素,而shoplist[3]获取第四个元素。

索引也可以是负数,这时候位置将从序列尾开始计算。所以,shoplist[-1]引用序列的最后一个元素,shoplist[-2]为倒数第二个。

切片操作的使用方法是先指定序列名后跟一对方括号,其中包含一对可选的由分号分隔的数字。

注意这与你至今使用的索引操作非常相似。记住数字是可选的,但分号不可以省略。

切片操作中的第一个数字(分号前)指出切片的开始位置而第二个数字(分号后)指定将在哪个位置结束。

如果省略第一个数字则python将以序列的起点为开始处,而省略第二个数字时切片会停止在序列的结尾处。

注意切片将在开始处开始,结束于结尾处之前,即包括开始处但不包括结尾处。(注:比如a[1:10],返回的是a[1]到a[9]不包括a[10])。

因此,shoplist[1:3]开始于索引1,包括索引2但止于索引3,即返回一个包含两个元素的切片。与之类似shoplist[:]将返回整个序列的拷贝。

你还能以负索引切片。负数代表从序列的末尾开始反向计算位置。例如shooplist[: -1]返回整个序列,但不包括未末的元素。

另外你还可以为切片提供第三个实参,它代表步长(默认为1)。

>>> shoplist = ['apple', 'mango', 'carrot', 'banana']

>>> shoplist[::1]

['apple', 'mango', 'carrot', 'banana']

>>> shoplist[::2]

['apple', 'carrot']

>>> shoplist[::3]

['apple', 'banana']

>>> shoplist[::-1]

['banana', 'carrot', 'mango', 'apple']

注意当步长为2时,我们得到索引为0,2…的元素,步长为3时得到0,3…,以此类推。

用python交互解释器(这样你能立即看到结果)尝试切片的各种用法吧。

序列类型最棒的地方在于你能够以相同的方式访问元组,列表,字符串!

 

集合

集合是简单对象的无序集合,适合当更关心集合中的元素是否存在而不是它们的顺序或是它们出现的次数的时候。

使用集合,你可以测试从属关系,是否一个集合是另一个集合的子集,或是寻找两个集合的交集等等。

>>> bri = set(['brazil', 'russia', 'india'])

>>> 'india' in bri

True

>>> 'usa' in bri

False

>>> bric = bri.copy()

>>> bric.add('china')

>>> bric.issuperset(bri)

True

>>> bri.remove('russia')

>>> bri & bric # OR bri.intersection(bric)

{'brazil', 'india'}

代码如何工作:

代码几乎是自说明的,因为它涉及到的基础集合论知识我们已经在学校学过了。

 

引用

当你创建一个对象并将其赋给一个变量的时候,变量只是引用了这个对象,而变量并不代表这个对象本身!

换言之,变量名指向你的计算机内存的一部分,而这部分内存用于存储实际的对象。这叫做名字到对象的绑定。

通常你不用关心这些,但你应该知道由于引用造成的一些微妙的影响。

范例:

#!/usr/bin/python

# Filename: reference.py

print('Simple Assignment')

shoplist = ['apple', 'mango', 'carrot', 'banana']

mylist = shoplist # mylist只是指向相同对象的另一个名字

del shoplist[0] # 我购买了第一个水果,所以把它从清单中删除

print('shoplist is', shoplist)

print('mylist is', mylist)

# 注意列表shoplist和mylist打印了相同的内容,其中都不包括’apple’,因为它们指向的是相同的对象。

print('Copy by making a full slice')

mylist = shoplist[:] # 以全切片创造一个列表的完整拷贝

del mylist[0] # 删除第一个元素

print('shoplist is', shoplist)

print('mylist is', mylist)

# 注意现在两个列表指向不同的对象(注:回忆一下,切片操作会返回一个新的对象!)

Output:

    $ python reference.py

    Simple Assignment

    shoplist is ['mango', 'carrot', 'banana']

    mylist is ['mango', 'carrot', 'banana']

    Copy by making a full slice

    shoplist is ['mango', 'carrot', 'banana']

    mylist is ['carrot', 'banana']

代码如何工作:

大多数的解释已经包含在注释中了。

记住,如果你想创建一个诸如列表这样的序列或复杂对象(不是象整数那样的简单对象)的拷贝,必须使用切片操作。

如果你只是简单的用变量名指向另一个变量名,两者实际上将引用相同的对象,如果你不注意这点将会招来麻烦!

 

Perl程序员请注意

记住对于列表的赋值语句并不会创建一个拷贝。必须使用分片操作创建序列的拷贝。

(注:实际上切片操作不是唯一的选择,内见的工厂函数比如list,typle, set等都能达到同样的目的)

 

关于字符串的更多知识

前面我们已经详细讨论过字符串了。在这里我们还会了解到什么呢?

呵呵,你知道字符串同样是一种对象并拥有很多方法吗? 从检查字符串的一部分到删除其中的空格应有尽有!

你在程序中使用的所有字符串都是str类的对象。下面的例子会演示str类中的一些有用的方法。全部方法的列表,参见help(str)

范例:

#!/usr/bin/python

# Filename: str_methods.py

name = 'Swaroop' # 这是一个字符串对象

if name.startswith('Swa'):

    print('Yes, the string starts with "Swa"')

if 'a' in name:

    print('Yes, it contains the string "a"')

if name.find('war') != -1:

    print('Yes, it contains the string "war"')

delimiter = '_*_'

mylist = ['Brazil', 'Russia', 'India', 'China']

print(delimiter.join(mylist))

Output:

    $ python str_methods.py

    Yes, the string starts with "Swa"

    Yes, it contains the string "a"

    Yes, it contains the string "war"

    Brazil_*_Russia_*_India_*_China

代码如何工作:

在这里我们看到了许多字符串方法的用法。

startswith方法用于确定字符串是否以指定的字符串开头。而in操作检查一个字符串是否是另一个字符串的一部分。

find方法用来寻找给定的字符串在字符串中的位置,如果没找到对应的子串则返回-1

str类还有一个简洁的连接序列中每个字符串并返回连接后的字符串的方法join,其中每个字符串都将以指定的字符串分隔。

 

小结

我们已经详细研究了python中的各种内建数据结构。这些数据结构对于编写合理规模大小的程序是必须可少的。

现在我拥有了许多的python的基础知识,下一步我们会看到如何设计和编写一个实用的python程序。

 

 

 

--------------Python书籍推荐-----------------

Python基础教程-第2版.修订版 

购买地址1  购买地址2

 

 

PYTHON核心编程

购买地址1  购买地址2

 

 

零基础学Python

购买地址1  购买地址2

时间: 2024-09-14 03:20:53

简明Python3教程 11.数据结构的相关文章

简明Python3教程(A Byte of Python 3)

 关键字:[A Byte of Python v1.92(for Python 3.0)] [A Byte of Python3] 简明Python教程 Python教程 简明Python3教程    简明Python3教程<A Byte of Python3>是一本关于用Python3语言编程的书.可以作为初学这的入门教程.也可以供计算机相关人员参考. 本书可作为Python编程语言的指导或辅导.主要是针对新手的,当然,对于有经验的程序员也很有用.如果你所了解的计算机的知识就是如何保存文本文

简明Python3教程 6.基础

你肯定不满足于只打印"Hello World"吧? 你想要的更多 - 你希望得到一些输入,操纵它后再从中得到某些东西.我们可以使用python中的常量和变量实现这些功能.   字面常量(literal constant)字面常量的一个例子是数字诸如5, 1.23, 9.25e-3或字符串This is a string', "It's a string!".顾名思义,字面常量的重点在于"字面", 你直接以字面的意义使用它们.数字2永远是数字2绝不

简明Python3教程 5.第一步

介绍 我们现在来看看如何在Python中运行传统的"Hello world"程序.这会教你如何写.保存以及运行Python程序. 有两种办法来运行您的Python程序--使用交互式的解释器提示符或者源代码文件.我们现在来分别看一看这两种方法. 使用解释器提示符 在命令提示符中输入python来打开解释器. 那些在GNU/Linux与BSD上同时安装了Python 3.x与Python 2.x的用户可能需要输入python3. 而对于Windows用户而言,如果您在PATH环境变量里正确

简明Python3教程 4.安装

如果你已经安装了Python 2.x,你不需要在安装Python 3.0前卸载Python 2.x.这两者可以共存. GNU/Linux用户和BSD用户 如果你使用类似于Ubuntu.Fedora.OpenSUSE.Debian.CentOS或其他你选择的GNU/Linux发行版,或类似于FreeBSD的BSD系统,你的系统很可能已经了Python. 可通过开启shell程序(如konsole或gnome-terminal)并输入以下命令以检测Python是否安装在你的BSD或GNU/Linux

简明Python3教程 10.模块

简介 现在你已经知道通过定义函数可以在你的程序中复用代码.但当你想在你编写的其他程序中复用大量函数怎么办呢? 也许你可以猜到了,办法就是利用模块. 有各种编写模块的方式,但最简单的方式是创建一个以.py为后缀的文件并包含所需的函数与变量. 另一种方式是以编写python解释器的本地语言编写模块. 例如C语言编写的模块被编译后可供运行于标准python解释器上的python代码使用. 模块可以被其它程序导入以使用其提供的功能.这也是为什么我们可以使用python标准库. 我们先来看看如何使用标准库

简明Python3教程 16.标准库

简介 python标准库作为python标准安装的一部分,其自身包含数量庞大的实用模块, 因此熟悉python标准库非常重要,因为很多问题都能利用python标准库快速解决. 下面我们将研究标准库中的一些常用模块.完整的标准库模块列表可以在安装python时附带的文档中的'Library Reference'一节找到. 现在就让我们来看看这些模块吧.   提示 如果你感觉本章内容对于你过于超前,那么可以跳过本章.但是当你熟悉python编程后我强烈建议你把这章补上.   sys模块 sys模块包

简明Python3教程 7.运算符和表达式

简介 你写的大多数逻辑行都包含表达式.表达式的一个简单例子是2 + 3.一个表达式可分为操作符和操作数两部分. 操作符的功能是执行一项任务:操作符可由一个符号或关键字代表,如+ .操作符需要数据以供执行其功能,这些数据名为操作数.在上面的例子中,2和3是操作数. 操作符 我们在这里简单地介绍操作符及其用途: 你可在Python解释器中交互验证下面给出的例子.例如,验证2 + 3,在Python解释器提示符中输入: >>> 2 + 3 5 >>> 3 * 5 15 >

简明Python3教程 9.函数

简介 函数是程序的可复用片段,允许你为语句块赋予名字之后在程序的任何地方运行它们任意次,这称做函数调用. 我们已经使用过一些内建函数,例如len和range等. 函数也许是任何有意义的软件中最重要的构件,所以我们将在本章探究函数的方方面面. 函数以关键字def定义,其后紧跟函数名,由一对小括号闭合的形参,最后以冒号结束定义行, 定义行下面的是函数体,它是一个语句块. 听着有点复杂,其实定义起来是很简单的,见下面的例子: 范例: #!/usr/bin/python # Filename: func

简明Python3教程 2.序言

Python也许是为数不多的既简单又强大的编程语言.这有利于新手甚至于专家,更重要的是用它编程所带来的乐趣. 这本书的目的是帮助您了解这种神奇的语言,展示如何快速而轻松地完成事情--事实上"编程问题的完美解决方案!" 本书的读者 本书可以作为Python编程语言的一本指南或者教程.它主要是为新手而设计,不过对于有经验的程序员来说,它同样有用. 其目的是,即使你对计算机的认识只是知道如何保存文件,你仍然可以从本书中学到的Python.如果你之前有过编程经验,你也可以从本书中学到的Pyth