zoukankan      html  css  js  c++  java
  • python列表(list)和元组(tuple)浅析

    列表(list)元组(tuple)都是一种数据结构,python将这种数据结构统称为序列(sequence)。和序列对应的就是映射(map),还有一种不属于这两种那就是集合(set)。这三种其实都属于python的另一种数据结构,即容器(container)。也就是说,python的容器是一种通用的数据结构,包括上面所说的这三种数据结构,它是一种包含其他对象的对象。其中序列包含很多类型,常见的有list, tuplelist中可以包含多种数据类型的元素,比如:score这个序列中既包含字符串的name,也包含number类型的marks。

    >>> zhangsan=['zhang san', 98]
    >>> lisi=['li si', 60]
    >>> score=[zhangsan, lisi]
    >>> score
    [['zhang san', 98], ['li si', 60]]
    >>> 

    列表和元组的主要区别在于:列表可以修改,元组则不能。

    序列的通用操作

    所有的序列类型都可以进行某些特定的操作,这些操作包括:索引(indexing)分片(sliceing)加 (adding)乘(multipling),以及检查某个元素是否在序列中的in,此外,python还提供了一些内建(build-in)函数,如:max,min, len等。

    索引操作(包括列表与元组)

    接下来,我们看看索引操作相关的例子,很明显它可以直接以变量的方式按索引取元素值,也可以直接以序列的方式取,还包括以函数返回值的方式取:

    
    >>> greeting='hello'
    >>> greeting[0] #以变量的方式
    'h'
    >>> greeting[-1]
    'o'
    >>> 'hello'[0] #以序列的方式
    'h'
    >>> 'hello'[-1]
    'o'
    >>> raw_input('Year: ')[3] #以函数返回值的方式
    Year: 2017
    '7'

    切片操作(包括列表与元组)

    接下来看一看切片操作的相关例子:

    >>> numbers=[1,2,3,4,5,6,7,8,9,10]
    >>> numbers[1,10]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: list indices must be integers, not tuple
    >>> numbers[1:10]
    [2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> numbers[1:10]
    [2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> numbers[0:10]
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> numbers[:]   
    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
    >>> numbers[5::2]
    [6, 8, 10]
    >>> numbers[5::-2]
    [6, 4, 2]
    >>> numbers[5::]  
    [6, 7, 8, 9, 10]
    >>> numbers[5:] 
    [6, 7, 8, 9, 10]
    >>> numbers[:2]  
    [1, 2]
    >>> numbers[:2:]
    [1, 2]
    >>> numbers[-3:0]
    []

    请仔细观察上面的各个例子,这样才能更好的理解以下几点:

    • 分片以:分隔
    • 分片从0开始计数索引
    • 要取序列的首和末只需要分别将它们的位置留空
    • 只要左索引比右索引晚出现在序列中,就是一个空序列
    • 默认步长是1
    • 如果没有左或者右索引,取数的顺序取决于它的步长是正还是负,正是顺,负是逆

    加法操作(包括列表与元组)

    我们来看看加操作,请看例子:

    >>> [1,2,3]+[4,5,6]
    [1, 2, 3, 4, 5, 6]
    >>> 'hello,'+'world' 
    'hello,world'
    >>> 'hello,'+[1,2,3]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: cannot concatenate 'str' and 'list' objects
    >>> 

    从例子中可见,加操作的两边必须是同类型,否则就出错。
    请注意这个+不会改变被加的序列(列表),而 list的 extend方法会。详见:

    >>> a=[1,2,3]
    >>> b=[4,5,6]
    >>> a+b
    [1, 2, 3, 4, 5, 6]
    >>> a
    [1, 2, 3]
    >>> a.extend(b)
    >>> a
    [1, 2, 3, 4, 5, 6]

    乘法操作(包括列表与元组)

    再看看乘操作:

    >>> 'love'*5
    'lovelovelovelovelove'
    >>> [1,2,3]*5
    [1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3]
    >>> [None]*5
    [None, None, None, None, None]
    >>> [1,2,3]*[1,2,3]
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can't multiply sequence by non-int of type 'list'
    >>> 'love'*'love'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can't multiply sequence by non-int of type 'str'
    >>> 

    请仔细观察上面的各个例子,这样才能更好的理解以下几点:

    • 乘之前是什么类型还是该类型
    • 乘操作只能以int类型作为参数

    in 操作(包括列表与元组)

    这里说一说in运算符,对于早期python版本(<2.3),判断字符是否在字符串中可以用in,但是这个只能用于判断单个字符,只有在2.3版本后,才可以允许多个字符的判断。

    >>> 'h' in "hello"
    True
    >>> 'hell' in "hello"
    True
    >>> 3 in (1,2,3)
    True

    max和min函数(包括列表与元组)

    看下max与min的内建函数:

    >>> numbers=[1,9,4,2]
    >>> max(numbers)
    9
    >>> min(numbers)
    1
    >>> max(1,9,4,2)
    9
    >>> min(1,9,4,2)
    1
    >>> max((1,2,3))
    3

    前两个操作好理解是基于序列的,但后两个操作很污啊,为什么直接传多个数值也可以啊,是因为如果用,分隔值,则自动创建元组。所以逗号是很重要的,这个需要注意一下。

    >>> 1,2,3
    (1, 2, 3)
    >>> 

    接下来分别对比讲一下列表及元组、字符串等。

    只适合列表(list)的操作

    列表(list)函数

    list函数可以将一个不能修改的序列(如:字符串,元组),转换成list。
    其实,list并不是函数,而是一种类型。下面我们看看如何来修改一个字符串,比如:

    >>> str='python'
    >>> str[0]='P'
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: 'str' object does not support item assignment
    >>> lst=list(str)
    >>> lst
    ['p', 'y', 't', 'h', 'o', 'n']
    >>> lst[0]='P'
    >>> lst
    ['P', 'y', 't', 'h', 'o', 'n']
    >>> 

    基本的列表(list)操作

    基本的列表操作,包括元素赋值(=),删除(del), 分片赋值

    >>> x=[1,2,3]
    >>> x[1]=5
    >>> x
    [1, 5, 3]
    >>> del x[1]
    >>> x
    [1, 3]
    >>> x[1:1]=2
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: can only assign an iterable
    >>> x[1:1]=[2]
    >>> x
    [1, 2, 3]
    >>> x[1:]=[]
    >>> x
    [1]
    >>> 

    列表(list)的方法

    列表(list),实际上是一个对象,那么它就有方法,调用的方法一般是 对象.方法() 的形式。注意,()很重要,表示函数调用。它的方法有很多,比如:append, count, extend, index, insert, pop, remove, reverse, sort等,

    append(...)
        L.append(object) -- append object to end
    
    count(...)
        L.count(value) -> integer -- return number of occurrences of value
    
    extend(...)
        L.extend(iterable) -- extend list by appending elements from the iterable
    
    index(...)
        L.index(value, [start, [stop]]) -> integer -- return first index of value.
        Raises ValueError if the value is not present.
    
    insert(...)
        L.insert(index, object) -- insert object before index
    
    pop(...)
        L.pop([index]) -> item -- remove and return item at index (default last).
        Raises IndexError if list is empty or index is out of range.
    
    remove(...)
        L.remove(value) -- remove first occurrence of value.
        Raises ValueError if the value is not present.
    
    reverse(...)
        L.reverse() -- reverse *IN PLACE*
    
    sort(...)
        L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
        cmp(x, y) -> -1, 0, 1

    这里主要列举一些比较容易出错的几点:

    1、 pop是唯一的既修改了列表,又有返回值的方法

    首先如何判断某个方法是否有返回值?
    最简单直观的方法就是在python控制台敲该方法,如果回车后没有输出值就表示没有返回值,否则输出的该值就是有返回值。举例如下,reverse是没有返回值的,而pop有返回值。

    >>> x=[1,2,3]
    >>> x.reverse() #无输出
    >>> x
    [3, 2, 1]
    
    >>> x=[1,2,3]
    >>> x.pop() #有输出,3为其返回值
    3
    >>> x
    [1, 2]

    另外一种方法就是用 print打印出来,如果是None则无返回值,否则就有。

    >>> x=[1,2,3]
    >>> print x.reverse() #返回值为None表示空
    None
    >>> x
    [1, 2, 3]
    >>> print x.pop(1) #返回值为2
    2
    >>> x
    [1, 3]
    >>> 

    2、 什么是原位置操作(in-place operation)?

    原位置操作(in-place operation)表示:在执行某个操作后(一般是调用list的某个方法),改变了原列表的元素位置。即如果某个方法改变了原列表的元素位置,则该方法即是原位置方法。

    >>> a=[1,2,3]
    >>> b=[4,5,6]
    >>> a+b #+号不是原位置操作
    [1, 2, 3, 4, 5, 6]
    >>> a
    [1, 2, 3]
    >>> a.extend(b) #extend是原位置操作方法
    >>> a
    [1, 2, 3, 4, 5, 6]

    3、sort函数解密

    现在我们来看看sort这个函数,它首先是一个原位置操作方法,会改变原列表的排序。

    >>> numbers=[5,2,9,7]
    >>> numbers.sort()
    >>> numbers
    [2, 5, 7, 9]

    另外,它又不会返回值,所以想通过它来接收排序后的结果是得不到的。有时候我们经常希望保持排序前的数据不变,在调用sort后,然后将其赋值到某个列表,但这个想法是错误的,如下:

    >>> x=[5,2,9,7]
    >>> y=x.sort()
    >>> x
    [2, 5, 7, 9]
    >>> print y
    None

    那要怎么办?看来不能直接通过返回值来接收,那我们先赋值呢?将y=x呢?
    我们来看看:

    >>> x=[5,2,9,7]
    >>> y=x
    >>> y
    [5, 2, 9, 7]
    >>> y.sort()
    >>> y
    [2, 5, 7, 9]
    >>> x
    [2, 5, 7, 9]

    虽然实现了y的排序,但是x的值也跟着变了。。这并不是我们想要的。
    我们很快会想到用分片操作,试试看:

    >>> x=[5,2,9,7] 
    >>> y=x[:]
    >>> y
    [5, 2, 9, 7]
    >>> y.sort()
    >>> y
    [2, 5, 7, 9]
    >>> x
    [5, 2, 9, 7]

    果然可以了。原因是y=x这种赋值是一种引用的方法,是浅拷贝。而y=x[:]是深拷贝。
    我们都知道,浅拷贝只是对指针的拷贝,拷贝后两个指针指向同一个内存空间,深拷贝不但对指针进行拷贝,而且对指针指向的内容进行拷贝,经深拷贝后的指针是指向两个不同地址的指针。具体一点,对于字符串类型来说,浅复制是对值的复制,对于对象来说,浅复制是对对象地址的复制,并没有开辟新的栈,也就是复制的结果是两个对象指向同一个地址,修改其中一个对象的属性,则另一个对象的属性也会改变,而深复制则是开辟新的栈,两个对象对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性。
    当然还有一种获取已排序的列表副本的方法是用sorted,使用如下:

    >>> x=[5,2,9,7]
    >>> y=sorted(x)
    >>> y
    [2, 5, 7, 9]
    >>> x
    [5, 2, 9, 7]

    好了,我们看看sort的函数原型,它有三个参数,

    sort(...)
        L.sort(cmp=None, key=None, reverse=False) -- stable sort *IN PLACE*;
        cmp(x, y) -> -1, 0, 1

    sort函数可以接收的参数有:一种用于排序的比较函数 compare(内建的是 cmp ,默认的也是cmp);一种用于按某种以关键字参数传递的key参数,还有一种关键字参数是reverse

    >>> numbers=[5,2,9,7]
    >>> numbers.sort(cmp)
    >>> numbers
    [2, 5, 7, 9]
    
    
    >>> numbers=['a5','b2aaaa1','9ccc','dd7']
    >>> numbers.sort(key=len)
    >>> numbers
    ['a5', 'dd7', '9ccc', 'b2aaaa1']
    
    
    >>> numbers=['a5','b2aaaa1','9ccc','dd7']
    >>> numbers.sort(key=len,reverse=True)
    >>> numbers
    ['b2aaaa1', '9ccc', 'dd7', 'a5']

    参数key和cmp有点类似,必须提供一个在排序过程中使用的函数。然而该函数并不像cmp那样直接确定对象的大小,而是为每个元素创建一个以赋值给key的函数的返回值的键,然后所有的元素按照键来排序。如上所示,就是根据元素的长度来进行排序的。
    最后,cmp, key, reverse参数也都可用于sorted的函数。


    只适合元组(tuple)的操作

    元组与列表一样,也是一种序列,唯一不同的是元组不能修改,其实字符串也是不能修改的。创建元组很简单,只要使用逗号隔开,自动就创建成了元组。

    >>> 1,2,3
    (1, 2, 3)
    >>> 3,
    (3,)

    元组(tuple)函数

    元组(tuple)和列表(list)一样,其实并不是函数,而是一种类型。它以一个序列作为参数,并转化成为元组,如果本身就是元组,那么直接返回。

    >>> tuple('Python')
    ('P', 'y', 't', 'h', 'o', 'n')
    >>> tuple(('P', 'y', 't', 'h', 'o', 'n'))
    ('P', 'y', 't', 'h', 'o', 'n')
    >>> tuple([1,2,3])
    (1, 2, 3)

    元组(tuple) 的基本操作

    元组只读的,一般除了访问元数和分片外,没有什么操作。分片后当然还是元组。

    >>> x=1,2,3
    >>> x[1]
    2
    >>> x[:]
    (1, 2, 3)

    元组(tuple) 的作用是什么?

    一般元组能做到的,列表也能做到,但下面两个重要原因,是列表不能替代的:

    • 元组可以在映射或集合中充当键的作用,列表则不行。
    • 元组作为很多内建函数和方法的返回值存在。
  • 相关阅读:
    iOS开发-Sqlite
    iOS开发-HTTP协议
    iOS开发
    iOS 开发小记 (八)
    iOS
    iOS开发-基础框架
    Java门面模式
    Linux常用命令
    canal使用小结
    MySQL隔离级别的测试
  • 原文地址:https://www.cnblogs.com/qianggezhishen/p/7460308.html
Copyright © 2011-2022 走看看