python slice的几个小点总结

最近在看python时发现python中关于序列的操作,尤其slice的用法挺特别的,遂上网又细细查了查资料,感觉这篇文章总结的很好,就转载下来,留个记录。


问题的起因

    今天在写代码的时候,看到一个比较有意思的写法。假设我们有一个list,它的内容是a = [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9]。如果我们取它反转后的结果,一般我们头脑里默认想到的无非就是reverse这样的方法了。但是它还有一种写法:a[::-1],输出的结果是和当前的结果相反。在某些情况下,它的应用还是比较有意思的。就想针对这一块总结一下。

slice在python中的应用

     在Python中,list, tuple以及字符串等可以遍历访问的类型都可以应用slice访问。slice本身的意思是指切片,在这些可以遍历访问的类型中截取其中的某些部分。比如如下的代码:

Python代码 
  1. >>> l = range(10)  
  2. >>> l  
  3. [0123456789]  
  4. >>> l[1:5]  
  5. [1234]  

   首先,我们通过range(10) 生成一个从0到9的列表。在这个列表中取[1:5]的时候返回的是索引1到4的。所以,我们发现他们所取的slice是一个半开半闭的区间。l[a:b]==> l[a, b).

    前面这种情况下,是我们已知列表的长度,然后取他们的某个区段,如果我们不知道列表的长度,或者列表长度的获取比较麻烦呢?如果用其他的语言,我们可能考虑这个列表是否应该有一个list.length之类的属性了。在这里,有另外一个办法来取得:

Python代码 
  1. >>> l[-1]  
  2. 9  
  3. >>> l[1:-1]  
  4. [12345678]  
  5. >>> l[2:-2]  
  6. [234567]  

    我们可以看到如果要取列表中的最后一个元素,可以用l[-1]的方式,如果从后面向前,可以依次取l[-2], l[-3]...

    既然我们前面提到,在列表中slice是取的一个前面闭合后面开放的区间,也就是说我在l[a:b]的时候,索引值为b的那个元素是不包含在结果中的。如果我们想要包含后面的值那么该怎么办呢?

    这个问题可以分为几种情况来考虑,一个是加入b本身长度比较小,那么我们取l[a:b+1]就好了。比如说如下:

Python代码   收藏代码
  1. >>> l[1:3]  
  2. [12]  
  3. >>> l[1:4]  
  4. [123]  

 如果我们想把索引值为3的也包含进来,我们就用l[1:4]就行了。那么,对于处在列表末尾的元素呢?用过c, Java开发的人会想到,按照这种方式会不会导致访问数组越界呢?我们试试看吧:

Python代码   收藏代码
  1. >>> len(l)  
  2. 10  
  3. >>> l[1:10]  
  4. [123456789]  
  5. >>> l[1:11]  
  6. [123456789]  
  7. >>> l[1:12]  
  8. [123456789]  

    len(l)返回l的长度。我们原来潜意识的认为,既然数组长度为10,那么我们访问的索引最大值也不过为l[9]。实际上,在python这里,可以列出的访问下标值超出数组长度范围,只不过仅仅返回能遍历到的元素而已。

    当然,我们还有另外一种办法:

Python代码   收藏代码
  1. >>> l[1:]  
  2. [123456789]  

    这种方式就完全将前面索引到数组末尾的元素都包含进来了。

    这样,我们要包含整个数组中的元素就可以采用如下的几种方式:

Python代码   收藏代码
  1. >>> l[0:]  
  2. [0123456789]  
  3. >>> l[:]  
  4. [0123456789]  
  5. >>> l  
  6. [0123456789]  

    从前面我们用l[a:b] 的方式来访问元素来看,我们这里a, b取的值要么满足0<= a <= b 或者 a >= 0 b < 0。实际上,a所对应元素的位置总是在b所对应位置的后面。那么,如果我们把他们的顺序倒过来一下会怎么样呢?比如说:

Python代码   收藏代码
  1. >>> l[5:2]  
  2. []  
  3. >>> l[-1:3]  
  4. []  

    在这里,我们发现,如果实际取的元素先从右边开始然后到左边的话,并不是我们所期望的返回一个倒过来的数组,而是返回一个空的数组。我举的这个例子有什么用呢?别急,看了后面那一节你就知道了。

理解extended slice

    前面那一部分相对来说还是比较好理解的。现在,如果我们有一些其他的要求,比如说,我们想返回数组里面索引为奇数的元素,或者索引为偶数的元素,那么该怎么办呢?

我们可以有几种办法来做,其中的一种就是采用extended slice,一个典型的解决方法如下:

Python代码   收藏代码
  1. >>> l[::2]  
  2. [02468]  
  3. >>> l[1::2]  
  4. [13579]  
  5. >>>   

    前面这种包含两个冒号的样式是怎么回事呢?

     实际上,我们这边第一个冒号隔开的这两个部分和前面的意思是一样的,就是指定数组中间元素的区间。所以前面第一个l[::2]前面就是指的整个数组的元素。而后面那个部分则是指的一个步长。这表示什么意思呢?就是既然我们前面指定的是整个数组,那么它就是从0开始,然后每次访问后面相邻的元素。而设置为2之后呢,则访问后面和它距离为2的元素,而不是直接相邻的元素。这样,我们也就容易理解l[1::2],它就是从元素1开始到结尾的元素集合里取间隔为2的这些元素。

    到这一步,就离我们理解前面那个古怪的l[::-1]很接近了。我们前面的这个取步长是将步长设置为正数,所以在取元素的集合里它表示从左到右的取指定步长覆盖的元素。如果我们将步长设置为负数呢?我们来看:

Python代码   收藏代码
  1. >>> l[1:9:-1]  
  2. []  
  3. >>> l[9:1:-1]  
  4. [98765432]  

    有了前面这一部分的代码,相信就不难理解了。我们取区间[1, 9),结果取步长为-1的时候返回的是一个空的集合。而我们取9到1的时候,步长为-1取出来了倒序的数组。这是因为如果我们指定的步长为负数的话,那么它必须和数据指定的区间方向一致。也就是说,如果我们前面指定的区间是从数组小的索引到大的索引,那么我指定的步长必然也要从小到大。所以必须为正数。而如果我们指定的区间是从后面往前的话,则步长必须指定为负数。否则返回的结果都是空的数组。

总结

    有了前面那么多的讨论,我们再来看数组的slice访问。他们无非就是这么几个情况,在l[a:b]的情况下,必须保证a所在的索引位置在前,b所在的索引位置在后,否则返回结果为空。在l[a:b:step]的情况下,我们首先要根据a, b的位置来判断方向,a在前,b在后的话,step应该为正,否则应该为负。不符合这些情况的话,则返回空的数组。也就是说,看a, b的位置来确定方向,不要犯方向性的错误,否则就竹篮打水一场空了:)

### Python 绘图入门教程 #### 使用 Matplotlib 创建简单图表 Matplotlib 是 Python 中最著名的绘图库之一,能够创建多种类型的静态、动态可视化图形[^1]。下面通过几个简单的例子展示如何使用 Matplotlib 进行基本的数据可视化。 安装 Matplotlib 可以通过 pip 工具完成: ```bash pip install matplotlib ``` #### 导入必要的模块并绘制第一个图表 为了开始绘图,首先需要导入 `matplotlib.pyplot` 模块,并通常将其命名为 `plt` 以便后续调用更简洁。接着可以尝试画一条简单的折线图作为起点。 ```python import matplotlib.pyplot as plt # 准备数据点 x_values = [0, 1, 2, 3, 4] y_values = [0, 2, 1, 3, 4] # 创建一个新的图像窗口 plt.figure() # 添加线条到当前坐标轴上 plt.plot(x_values, y_values) # 显示所作的图 plt.show() ``` 这段代码会打开一个新窗口显示由给定 x 和 y 数值构成的一条折线。 #### 自定义图表外观 除了默认设置外,还可以自定义图表的颜色、样式以及添加标签等元素来增强可读性和美观度。 ```python import numpy as np import matplotlib.pyplot as plt t = np.arange(0., 5., 0.2) # red dashes, blue squares and green triangles plt.plot(t, t, 'r--', label='line') plt.plot(t, t**2, 'bs-', label='square') plt.plot(t, t**3, 'g^-', label='cube') # 设置X轴和Y轴名称 plt.xlabel('time (s)') plt.ylabel('value') # 添加标题 plt.title("Simple Plot") # 展示图例 plt.legend() # 调整布局防止重叠 plt.tight_layout() # 渲染图像 plt.show() ``` 此段脚本不仅展示了不同样式的曲线,还加入了 X/Y 轴说明文字、图表标题及图例解释各个系列代表的意义。 #### 制作其他类型的图表 除了上述提到的折线图之外,Matplotlib 支持更多种类的统计图表形式,比如柱状图(bar chart),饼图(pie chart)等等。以下是两个额外的例子用于快速了解这些功能。 ##### 条形图 ```python import matplotlib.pyplot as plt labels = ['G1', 'G2', 'G3', 'G4'] men_means = [20, 35, 30, 35] women_means = [25, 32, 34, 20] ind = np.arange(len(labels)) # the x locations for the groups width = 0.35 # 定义每组内柱子宽度 fig, ax = plt.subplots() rects1 = ax.bar(ind - width/2, men_means, width, color='SkyBlue', label='Men') rects2 = ax.bar(ind + width/2, women_means, width, color='IndianRed', label='Women') # Add some text for labels, title and custom x-axis tick labels, etc. ax.set_ylabel('Scores') ax.set_title('Scores by group and gender') ax.set_xticks(ind) ax.set_xticklabels(labels) ax.legend() def autolabel(rects, xpos='center'): """ Attach a text label above each bar in *rects*, displaying its height. *xpos* indicates which side to place the text w.r.t. the center of the bar. It can be one of the following {'center', 'right', 'left'}. """ ha = {'center': 'center', 'right': 'left', 'left': 'right'} offset = {'center': 0.5, 'right': 0.57, 'left': 0.43} # x_txt = x + w*off for rect in rects: height = rect.get_height() ax.text(rect.get_x() + rect.get_width()*offset[xpos], 1.01*height, '{}'.format(height), ha=ha[xpos], va='bottom') autolabel(rects1, "left") autolabel(rects2, "right") plt.show() ``` 该程序片段实现了带有自动标注数值大小的功能的分组条形图。 ##### 饼图 ```python import matplotlib.pyplot as plt # Pie chart, where the slices will be ordered and plotted counter-clockwise: labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' sizes = [15, 30, 45, 10] explode = (0, 0.1, 0, 0) # only "explode" the 2nd slice (i.e. 'Hogs') fig1, ax1 = plt.subplots() ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90) ax1.axis('equal') # Equal aspect ratio ensures that pie is drawn as a circle. plt.show() ``` 这里给出的是一个典型的饼图实例,其中包含了突出显示特定部分的效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值