第四章 数据类型:list列表
4.1 列表(序列)的定义
任务一:Python内置数据类型
知识点:
Python内置(build-in)数据类型可以分为数值型和非数值型
数值型:整型(int)、浮点型(float)、布尔型(bool) 、复数型 (complex)
非数值型(序列):字符串、列表、元组、字典
知识点:
非数值类都是一个 序列 sequence,也可以理解为容器。它们都支持以下功能:
索引取值**[]**
遍历元素for in
计算序列长度、最大/最小值、比较、删除
拼接+运算符和重复*运算符
切片技术
任务二:认识什么是列表
列表由一系列按特定顺序排列的元素组成。列表是对象,是集合/容器类型的对象
用方括号(**[])来表示列表,并用逗号**来分隔其中的元素
下面是一个简单的列表示例,这个列表包含几种自行车:
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized'] |
1、鉴于列表通常包含多个元素,给列表指定一个表示复数的名称(如letters、digits或names)是个不错的主意
2、与Java或C的数组区别:
数组的数据类型必须是一样,而列表可以不一样;
数组长度事先声明固定长度,列表长度可增可减
3、Python列表元素可以是任意类型
1 | things = [1, 'car', 4.2, [2, 1]] |
习题:
1、输入你最喜欢的四个朋友,并把她们名字打印(英语名)
2、使用type() 查看类型
3、id() 查看列表引用地址
1 | names = ['James','Kobe','ONeal','Jordan'] |
1 | ['James', 'Kobe', 'ONeal', 'Jordan'] <class 'list'> |
4.1.1 访问列表元素
任务一:使用索引访问列表元素
列表是有序的容器类数据类型,要访问列表元素,只需将该元素的位置或索引
即列表名[索引]。列表的第1个元素索引从0开始。例如,下面的代码从列表bicycles中提取第一款自行车:
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized'] |
当你请求获取列表元素时,Python只返回该元素,而不包括方括号和引号:trek。可以进一步对返回的列表元素调用特定的方法。例如,可使用方法**title()让元素‘trek’**格式更整洁:
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized'] |
这个示例的输出与前一个示例相同,只是首字母T是大写的
任务二:列表的索引
知识点:元素索引
列表的索引从0 开始
所谓的索引就是元素在列表中的位置编号,索引又名为下标序号。
从列表中取值时,如果超出索引范围,程序触发异常IndexError
4.1.2 索引访问
任务一:第1个元素的索引是0
知识点:
在Python中,第一个列表元素的索引为0,而不是1
第二个列表元素的索引为1
根据这种简单的计数方式,要访问列表的任何元素,都可将其位置减1,并将结果作为索引
例如,要访问第4个列表元素,可使用索引3
下面的代码访问索引1和3处的自行车,这些代码返回列表中的第二个和第四个元素:
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized'] |
知识点:
Python为列表提供了一种更强大的元素访问机制,切片索引,来获得一个区间索引中的元素
切片索引区间:list[n:m]索引,其中n为起始,m为终止,元素区间**[n,m)**返回索引为n到m-1的元素
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized','redline', 'specialized'] |
知识点:
负索引(重要):在不知道列表长度的情况下访问最后的元素
Python为访问最后一个列表元素提供了一种特殊语法
通过将索引指定为**-1,返回最后一个列表元素**
1 | print('---------倒数第一个元素是-1索引---------') |
这些代码返回**’specialized’。这种约定也适用于其他负数索引,例如,索引-2返回倒数第二个列表元素,索引-3**返回倒数第三个列表元素,以此类推
4.1.3 使用列表中的值
任务一:如何使用列表中的元素值
知识点:
使用索引得到的元素进行后续操作。
例如,可以使用拼接根据列表中的值来创建消息
下面来尝试从列表中提取第一款自行车,并使用这个值来创建一条消息:
1 | bicycles = ['trek', 'cannondale', 'redline', 'specialized'] |
使用bicycles[0]的值生成了一个句子,并将其存储在变量message中。输出是一个简单的句子,其中包含列表中的第一款自行车:My first bicycle was a Trek.
习题:
1、将一些朋友的姓名存储在一个列表中,并将其命名为names。依次访问该列表中的每个元素,从而将每个朋友的姓名都打印出来
1 | names = ['James','Kobe','Jordan'] |
1 | James |
2、继续上一题,但不打印每个朋友的姓名,而为每人打印一条消息。每条消息都包含相同的问候语,但抬头为相应朋友的姓名
1 | names = ['James','Kobe','Jordan'] |
1 | James, how is everything going on ? |
3、为朋友输入他们喜欢的交通方式,如骑摩托车或开汽车,并创建一个包含多种交通方式的列表。根据该列表打印一系列有关这些交通方式的宣言,朋友名字和交通工具字符为全大写,如“Lilei would like to own a Honda motorcycle”
1 | names = ['JAMES','KOBE','JORDAN'] |
1 | JAMES would like to ride a BIKE. |
4.1.4 列表的通用操作
4.2(重要)变量内涵
任务一:变量的内涵
变量是Python语言最基本的元素。变量是指向具体数据(对象)的地址引用
1 | a = `python` |
变量:门牌号;具体内容:房间
通过赋值(=)语句进行关联
误区:变量中直接存储了具体了数据/对象。程序通过变量来间接访问和操作变量所指的对象
变量中存的地址引用可通过**id()**查看
python内存共享优化机制:
在python中,所有的对象(变量所指向的具体内容)都存活在系统堆上
对于小整数和字符串对象,可能在程序中会经常的使用。如果将这些经常使用的小整数对象也放在系统堆上,python就会经常的在堆上申请空间,释放空间,会严重的影响python的整体性能
对于小整数和字符串(不可变对象)对象做了一些优化,通过使用了对象池技术,将它们驻留在程序缓存中
变量共享引用相同的地址,小整数[-5,256] 和 字符串(不含空格)
1 | a = 'trek1111 111111111111111111111111111111' |
1 | bicycles1 = ['trek', 'cannondale', 'redline', 'specialized'] |
4.3 修改、添加和删除列表元素
4.3.1 修改元素
知识点:修改列表元素的语法与访问列表元素的语法类似
首先可指定列表名和要修改的元素的索引;
再通过赋值语句,为该元素赋新的值
例如,假设有一个摩托车列表,其中的第一个元素为**’honda’**,如何修改它的值呢?
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
首先定义一个摩托车列表,其中的第一个元素为**’honda’**
接下来,将第一个元素的值改为**’ducati’**
输出表明,第一个元素的值确实变了,但其他列表元素的值没变
4.3.2 添加元素
补充知识:Python是面向对象编程语言
通俗讲对象就是某种类型的变量
比如字符串对象,整形对象,浮点数对象等
在python中,可以按需求自定义类型,设计新的类
从面向对象OO(Object Oriented)的概念来讲,对象是类的一个实例;类是对象/实例的类型
比如str message,这里的str是类,而message是str类型的对象或str类型的实例
任务一:在列表末尾添加元素append()
知识点:
append()方法用于在列表末尾动态添加新的对象
语法:list.append(obj)
参数:obj为添加到列表末尾的元素
返回:该方法无返回值,直接会修改原来的列表
1 | list1 = ['Google', 'Runoob', 'Taobao'] |
例子:继续使用前一个示例中的列表,在其末尾添加新元素**’ducati’。方法append()将元素‘ducati’**添加到了列表末尾,而不影响列表中的其他所有元素
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
任务二:创建空列表并动态添加元素
知识点:
经常要等程序运行后,你才知道用户要在程序中存储哪些数据
为控制用户,可首先创建一个空列表,用于存储用户将要输入的值,然后将用户提供的每个新值附加到列表中
此外,方法append()让动态地创建列表易如反掌。例如,可以先创建一个空列表,再使用一系列的append()语句添加元素。下面来创建一个空列表,再在其中添加元素‘honda’、‘yamaha’和‘suzuki‘,最终的列表与前述示例中的列表完全相同:
1 | motorcycles = [] # 创建空列表 |
任务三:在列表的指定位置插入新元素insert()
知识点:
insert()方法用于将指定对象插入列表的指定位置。为此,需要指定新元素(对象)的索引和值
语法:list.insert(index, obj)
. 可以看作是该方法的对象作用域。指明该方法仅仅是针对某个具体的list对象进行操作
参数:index为元素obj需要插入的索引位置
参数:obj为添加到列表的元素
返回:该方法无返回值,但会在列表指定位置插入对象
注意:将列表中原索引(包括)之后的所有元素都右移一个位置
1 | list1 = ['Google', 'Runoob', 'Taobao'] |
例子:将值**’ducati**’存储到这个地方
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
4.3.3 删除元素
知识点:
根据位置或值从列表中删除一个或多个元素
玩家将空中的一个外星人射杀后,那么就要将其从存活的外星人列表中删除;
当用户在你创建的Web网站中注销登录的账户时,将该用户从活跃用户列表中删除
任务一:使用del语句删除元素
知识点:
语法:del list[index]
描述:del方法用于将指定位置的列表元素永久删除。为此,需要指定删除元素的索引
del其实并不属于列表的方法或者函数
list[index]为特定列表list的index索引位置的原始
条件:使用del可删除任何位置处的列表元素,条件是知道其索引
注意:del是直接删除list元素内容,无法再访问被删除的元素
例子:使用del删除了列表motorcycles中的第一个元素——**’honda’**
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
任务二:使用方法pop()删除元素
知识点:
语法:obj list.pop([index=-1])
描述:移除列表中的一个元素(默认最后一个元素),并且返回该元素的值
将元素从列表中删除,并接着使用它的值
参数: 带方括号的参数指可选参数
**[index=-1]**可选参数,指明要移除列表元素的索引值,不能超过列表总长度,默认为 index=-1,删除最后一个列表值
返回值: 该方法返回从列表中移除的元素对象obj
例子:下面从列表motorcycles中弹出一款摩托车:
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
分析:
首先定义并打印了列表motorcycles
接下来,我们从这个列表中弹出一个值,并将其存储到变量popped_motorcycle中
然后我们打印这个列表,以核实从其中删除了一个值
最后,我们打印弹出的值,以证明我们依然能够访问被删除的值
输出表明,列表末尾的值**’suzuki’已删除,它现在存储在变量popped_motorcycle**中
知识点:
方法**pop()**是怎么起作用的呢?
被删除的元素还有用于他用
假设列表中的摩托车是按购买时间存储的,就可使用方法**pop()**打印一条消息,指出最后购买的是哪款摩托车,输出是一个简单的句子,指出了最新购买的是哪款摩托车:
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
任务三:pop()列表中任何位置处的元素
实际上,你可以使用pop()来删除列表中任何位置的元素,只需在括号中指定要删除的元素的索引即可
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
首先,弹出列表中的第一款摩托车,然后打印了一条有关这辆摩托车的消息
输出是一个简单的句子,描述了我购买的第一辆摩托车
知识点:
每当使用pop()时,被弹出的元素就不再在列表中了
如果不确定该使用del语句还是**pop()**方法,下面是一个简单的判断标准:
如果你要从列表中删除一个元素,且不再以任何方式使用它,就使用del语句;
如果你要在删除元素后还能继续使用它,就使用方法pop()
任务四:使用remove()方法,根据值删除元素
知识点:
语法:list.remove(obj)
描述:remove()方法用于移除列表中某个值的第一个匹配项
参数: obj为列表中要移除的元素
返回值:该方法没有返回值,但是会移除列表中的某个值的第一个匹配项
条件:只要知道要删除的元素的值
1 | list1 = ['Google', 'Runoob', 'Taobao', 'Baidu'] |
知识点:**remove()**返回值为空
例子:从列表motorcycles中删除值**’ducati’。通过调用remove()方法,查询‘ducati’**出现在列表的什么地方,并将该元素删除:
1 | motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati'] |
例子:下面删除值**’ducati’**,并打印一条消息,指出要将其从列表中删除的原因
1 | motorcycles = ['honda', 'yamaha', 'suzuki', 'ducati', 'yamaha' , 'ducati'] |
定义列表后,我们将值**’ducati’存储在变量too_expensive**中
接下来,我们使用这个变量来告诉Python将哪个值从列表中删除
最后,值**’ducati’已经从列表中删除,但它还存储在变量too_expensive中,让我们能够打印一条消息,指出将‘ducati’从列表motorcycles**中删除的原因
知识点:
remove()只删除第一个指定的值
如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值
习题:
1、3-4 嘉宾名单:如果你可以邀请任何人一起共进晚餐(无论是在世的还是故去的),你会邀请哪些人?请创建一个列表,其中包含至少3个你想邀请的人;然后,使用这个列表打印消息,邀请这些人来与你共进晚餐
1 | customs = ['James','Kobe','Jordan'] |
1 | Wish James would attend my party |
2、3-5 修改嘉宾名单:你刚得知有位嘉宾无法赴约,因此需要另外邀请一位嘉宾
以完成练习3-4 时编写的程序为基础,在程序末尾添加一条print语句,指出哪位嘉宾无法赴约
修改嘉宾名单,将无法赴约的嘉宾的姓名替换为新邀请的嘉宾的姓名
再次打印一系列消息,向名单中的每位嘉宾发出邀请
1 | customs = ['James','Kobe','Jordan'] |
1 | Jordan can`t attend the party |
3、3-6 添加嘉宾:你刚找到了一个更大的餐桌,可容纳更多的嘉宾。请想想你还想邀请哪三位嘉宾
以完成练习3-4 或练习3-5时编写的程序为基础,在程序末尾添加一条print语句,指出你找到了一个更大的餐桌
使用**insert()**将一位新嘉宾添加到名单开头
使用**insert()**将另一位新嘉宾添加到名单中间
使用**append()**将最后一位新嘉宾添加到名单末尾
打印一系列消息,向名单中的每位嘉宾发出邀请
1 | customs = ['James','Kobe','Jordan'] |
1 | I found a bigger table |
4、3-7 缩减名单:你刚得知新购买的餐桌无法及时送达,因此只能邀请两位嘉宾
以完成练习3-6时编写的程序为基础,在程序末尾添加一行代码,打印一条你只能邀请两位嘉宾共进晚餐的消息
使用**pop()**不断地删除名单中的嘉宾,直到只有两位嘉宾为止。每次从名单中弹出一位嘉宾时,都打印一条消息,让该嘉宾知悉你很抱歉,无法邀请他来共进晚餐
对于余下的两位嘉宾中的每一位,都打印一条消息,指出他依然在受邀人之列
使用del将最后两位嘉宾从名单中删除,让名单变成空的。打印该名单,核实程序结束时名单确实是空的
1 | customs = ['James','Kobe','Jordan'] |
1 | I can only invite two customs to the party |
4.3.4 将列表用作栈和队列
任务一:将列表用作栈和队列
知识点:列表实现栈
栈是通常所说的一种LIFO(Last In First Out 后进先出)数据结构
它的意思是最后进入的数据第一个出来
一个最简单的例子往一端封闭的管道放入一些弹珠然后取出来,如果想把弹珠取出来,必须从最后放入弹珠的位置挨个拿出来。
使用**append()**将元素追加到列表尾部
使用 pop() 将最后个的元素弹出列
1 | a = [1, 2, 3, 4, 5, 6] |
上面的代码中使用了一个列表的 **pop()和append()**方法实现出栈和入栈操作
知识点:列表实现队列
在日常生活中会经常遇到队列,比如售票窗口、图书馆、超市的结账出口
队列 是一种在末尾追加数据以及在开始弹出数据的数据结构
与栈不同,它是 FIFO(First In First Out 先进先出)的数据结构
使用**append()**将元素追加到列表尾部
使用 pop(0) 将第0位置的元素弹出列表
1 | a = [1, 2, 3, 4, 5] |
4.4 列表的排序
4.4.1 list.sort()方法进行永久性排序
任务一:列表的永久排序
所谓永久性排序,指调用**list.sort()**方法会改变原列表
知识点:
描述:list.sort()方法用于对列表进行排序;默认情况下,sort()方法对列表进行(ascending)升序排序;还可以通过自定义比较函数来设置排序规则
语法:list.sort(reverse=False|True, key=myFunc)
参数:
reverse – 可选。reverse=True 将对列表进行降序排序。默认是 reverse=False
key – 可选。指定排序标准的函数
返回值:该方法没有返回值
该排序方法会修改了列表list元素的排列顺序
1 | # vowels list |
例子:假设你有一个汽车列表,并要让其中的汽车按字母顺序排列。为简化这项任务,假设该列表中的所有值都是小写的
1 | cars = ['toyota', 'subaru', 'abmw', 'abudi'] |
方法sort()永久性地修改了列表元素的排列顺序。现在,汽车是按字母顺序排列的,再也无法恢复到原来的排列顺序
还可以按与字母顺序相反的顺序排列列表元素,为此,只需向sort()方法传递参数reverse=True
任务二:通过sort()的参数key,自定义排序规则
例子:按照值的长度对列表进行排序:
1 | # 定义函数:返回值为元素的长度 |
例子:按二维数组的第二个元素值进行排序
1 | def takeSecond(elem): |
练习:
1、输入5个数,存到列表中,然后使用**sort()**,对该列表进行按升序、降序进行排序,并输出结果
1 | numbers = ['3', '1', '4', '2', '5'] |
1 | ['3', '1', '4', '2', '5'] |
2、构造拥有5个城市名字元素的列表cities,然后使用**sort()**,对该列表进行按升序、降序、字符串长度方式进行排序,并输出结果
1 | citis = ['China', 'America', 'Canada', 'England','Japan'] |
1 | sorted()排序后(升序默认): ['America', 'Canada', 'China', 'England', 'Japan'] |
4.4.2 sorted()函数进行临时排序
任务一:列表的临时排序
list.sort()方法是将排序结果覆盖修改原列表
新需求:希望得到列表的排序,但而不希望对原列表进行修改。函数**sorted()**让我们能够对列表进行元素排序(返回一个新的临时列表),但不影响原始排列顺序
知识点:
描述: sorted() 函数对所有可迭代的对象进行排序操作
语法:sorted(iterable, key=None, reverse=False)
参数:
iterable – 可迭代对象。通俗讲是该对象的元素是可以被循环遍历的。通常是集合或序列类型,比如list, str
key – 可选。指定排序标准的函数
reverse – 可选。reverse=True 将对列表进行降序排序。默认是 reverse=False
返回值:返回重新排序的列表(与原列表无关)
注意:传进去的是可迭代对象,而返回的是列表(非原来对象类型)
1 | # list 列表对象 |
任务二:自定义排序规则
**sorted()**函数的第二个元素的值为自定义排序规则
1 | def takeSecond(elem): |
1 | cars = ['bmw', 'audi', 'toyota', 'subaru'] |
任务三:sorted()是python的一个全局函数
知识点:
sorted()是python的一个全局函数,不是list的方法,因此不能通过**list.sorted()**方式调用
方法:属于对象的函数
函数:全局函数
1 | print("------------不能通过cars.sorted()-------------") |
4.4.3 list.reverse()方法对列表进行逆序
要反转列表元素的排列顺序,可使用方法list.reverse()
知识点:
描述:**list.reverse()**方法反转元素的排序顺序
语法:list.reverse()
参数:无
返回值:无
注意:永久性的修改原列表
假设汽车列表是按购买时间排列的,可轻松地按相反的顺序排列其中的汽车:
1 | cars = ['bmw', 'audi', 'toyota', 'subaru'] |
知识点:
reverse()不是指按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序
方法reverse()永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,为此只需对列表再次调用**reverse()**即可
习题:
1、创建一个列表,通过**reverse()**对元素顺序进行翻转,再恢复原来的排序
1 | names = ['James', 'Kobe', 'Jordan', 'ONeal'] |
1 | 原列表: ['James', 'Kobe', 'Jordan', 'ONeal'] |
2、输入多个字符串,存在列表中,然后调用**reverse()**对元素顺序进行翻转,并输出结果
1 | messages = ["Hello Python world!","James","Kobe","Jordan"] |
1 | 原列表: ['Hello Python world!', 'James', 'Kobe', 'Jordan'] |
4.4.4 len()函数查询长度
任务一:使用len()查询列表长度
知识点:
描述:**len()**函数获得列表的长度
语法:len(object)
参数:集合或序列类型的对象。比如list,str等
返回:长度值
属性:Python的build-in(内建)函数。所谓内建,就是Python自带的函数,类似于sorted()
在下面的示例中,列表包含4个元素,因此其长度为4:
1 | cars = ['bmw', 'audi', 'toyota', 'subaru'] |
1 | mylist = "Hello" |
1 | a = 1 |
习题:
3-8 放眼世界:想出至少5个你渴望去旅游的地方
将这些地方存储在一个列表中,并确保其中的元素不是按字母顺序排列的
按原始排列顺序打印该列表。不要考虑输出是否整洁的问题,只管打印原始Python列表
使用**sorted()**按字母顺序打印这个列表,同时不要修改它
再次打印该列表,核实排列顺序未变
使用**sorted()**按与字母顺序相反的顺序打印这个列表,同时不要修改它
再次打印该列表,核实排列顺序未变
使用**reverse()**修改列表元素的排列顺序。打印该列表,核实排列顺序确实变了
使用**reverse()**再次修改列表元素的排列顺序。打印该列表,核实已恢复到原来的排列顺序
使用**sort()**修改该列表,使其元素按字母顺序排列。打印该列表,核实排列顺序确实变了
使用**sort()**修改该列表,使其元素按与字母顺序相反的顺序排列。打印该列表,核实排列顺序确实变了
1 | places =['Japan','America','Canada','Switzerland','Norway'] |
1 | ['Japan', 'America', 'Canada', 'Switzerland', 'Norway'] |
3-9 晚餐嘉宾:在完成练习3-4~练习3-7时编写的程序之一中,使用**len()**打印一条消息,指出你邀请了多少位嘉宾来与你共进晚餐
1 | customs = ['James','Kobe','Jordan'] |
1 | I found a bigger table |
3-10 尝试使用各个函数:想想可存储到列表中的东西,如山岳、河流、国家、城市、语言或你喜欢的任何东西。编写一个程序,在其中创建一个包含这些元素的列表,然后,对于本章介绍的每个函数,都至少使用一次来处理这个列表
1 | customs = ['James','Kobe','Jordan'] |
1 | 6 |
4.4.5 列表list常用操作
4.5 使用列表时避免索引错误
任务一:熟悉列表常见的索引错误
刚开始使用列表时,经常会遇到一种错误。假设你有一个包含三个元素的列表,想获得最后一个元素,误用索引为3:
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
Python试图向你提供位于索引3处的元素,但它搜索列表motorcycles时,却发现索引3处没有元素。鉴于列表索引差一的特征,这种错误很常见。有些人从1开始数,因此以为第三个元素的索引为3;但在Python中,第三个元素的索引为2,因为索引是从0开始的
知识点:
索引错误意味着Python无法理解你指定的索引
程序发生索引错误时,请尝试将你指定的索引减1,然后再次运行程序,看看结果是否正确
每当需要访问最后一个列表元素时,都可使用索引**-1**。对于列表长度发生变化的情形特别有效:
1 | motorcycles = ['honda', 'yamaha', 'suzuki'] |
索引**-1总是返回最后一个列表元素,这里为值‘suzuki’**。仅当列表为空时,这种访问最后一个元素的方式才会导致错误:
1 | motorcycles = [] |
知识点:
找不到解决办法时,请尝试将列表或其长度打印出来
列表可能与想象中的截然不同,在程序对其进行了动态处理时尤其如此。通过查看列表或其包含的元素数,可帮助找出这种逻辑错误
习题:
3-11 有意引发错误:如果你还没有在程序中遇到过索引错误,就尝试引发一个这种错误。在你的一个程序中,修改其中的索引,以引发索引错误。关闭程序前,务必消除这个错误
1 | names = ['James','Kobe','Jordan'] |
1 | --------------------------------------------------------------------------- |