一、列表
之前的数据类型一般都是单个值,而不能再存储像矩阵、数组这种结构存储多个元素,要是需要达到这样的目标、需要使用新的数据类型,Python中提供了4种数据结构来存储多个对象,称它们为容器类型(Container Types),包括如下几种类型:
- 列表List
- 元组Tuple
- 字典Dictionary
- 集合Set
1.创建列表
其实,字符串其实也是一种序列,是由字符组成的序列。
字符串可以通过切片访问部分元素:
1# sequence of characters 2s="Corley!" 3s[2:4]
输出:
1'rl'
如需本节同步
ipynb文件,可以直接点击加QQ群 <a target="_blank" href="https://qm.qq.com/cgi-bin/qm/qr?k=rgE7cwG7OGHgfEucpRIQoSlYCTOEkmEr&jump_from=webapi"><img border="0" src="https://pub.idqqimg.com/wpa/images/group.png" alt="Python极客部落" title="Python极客部落">963624318</a> 在群文件夹商业数据分析从入门到入职中下载即可。
字符串是一个字符序列,列表是一个对象的序列。当对象的顺序很重要时就会使用列表。 创建和访问列表如下:
1#sequence of anything 2p = ['C','o','r','l','e','y','!'] 3p[2:4]
输出:
1['r', 'l']
可以看到,列表是用[]定义的,元素放入其中,用,隔开。
再如:
1def how_many_days(month): 2 days_in_month=[31,28,31,30,31,30,31,31,30,31,30,31] 3 return days_in_month[month-1] 4 5display(how_many_days(2), how_many_days(5), how_many_days(10))
输出:
128 2 331 4 531
可以看到,直接获取到了2、5、8月的天数。
还可以直接创建空列表,如下:
1empty_list = [] 2another_empty_list = list() 3display(empty_list,another_empty_list)
输出:
1[] 2 3[]
可以看到,输出了两个空列表。
还可以从字符串中分割出列表,如下:
1weekday_str = 'Monday,Tuesday,Wednesday,Thursday,Friday' 2weekdays = weekday_str.split(',') 3weekdays
输出:
1['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
以列表作为元素创建列表如下:
1obj_list = ["string", 1, True, 3.14] 2list_of_list = [empty_list, weekdays, obj_list] 3list_of_list
输出:
1[[], 2 ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'], 3 ['string', 1, True, 3.14]]
此即列表的嵌套。 再如:
1dal_memeber= [['Corley',18],['Jack',18],['Shirely',48],['Tom',18]] 2print(dal_memeber) 3print(dal_memeber[0]) 4print(dal_memeber[0][1])
输出:
1[['Corley', 18], ['Jack', 18], ['Shirely', 48], ['Tom', 18]] 2['Corley', 18] 318
列表可以定位和切片如下:
1display(weekdays[0],weekdays[1:3])
输出:
1'Monday' 2 3['Tuesday', 'Wednesday']
还可以通过赋值改变列表中的元素,如下:
1weekdays[0] = "Sunday" 2weekdays
输出:
1['Sunday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
显然,第一个元素已经改变。
2.删除元素
还可以删除列表中的元素。
一种方式是使用del关键字,基于下标删除,如下:
1del weekdays[0] 2weekdays
输出:
1['Tuesday', 'Wednesday', 'Thursday', 'Friday']
显然,第一个元素被删除。
再如:
1al = ['A', 'B', 'C', 'D', 'E', 'F', 'G'] 2del al[3:] 3al
输出:
1['A', 'B', 'C']
一次性删除多个元素。
还有一种方式是使用remove()方法,基于元素删除。
如下:
1weekdays.remove('Friday') 2weekdays
输出:
1['Tuesday', 'Wednesday', 'Thursday']
但是如果列表中不存在这个元素时,会报错,如下:
1weekdays.remove('Friday') 2weekdays
报错:
1--------------------------------------------------------------------------- 2ValueError Traceback (most recent call last) 3<ipython-input-20-b508ecb8e563> in <module> 4----> 1 weekdays.remove('Friday') 5 2 weekdays 6 7ValueError: list.remove(x): x not in list
因为weekdays中没有元素'Friday',因此会报错。
此时可以先进行判断,如果元素存在于列表中则删除,否则不删除;
判断一个元素是否存在于列表中可以用in关键字,存在则返回True,否则返回False。
如下:
1if 'Friday' in weekdays: 2 weekdays.remove('Friday') 3else: 4 print('element not exists')
输出:
1element not exists
in的用法再如:
1weekdays = ['Monday','Tuesday','Wednesday','Thursday','Friday'] 2'Friday' in weekdays
输出:
1True
还可以判断某个元素是否不在列表中,如下:
1'Fri' not in weekdays
输出:
14 2 35
除了使用del和remove()删除元素,也可以使用pop()弹出元素,该方法不仅可以弹出元素,还能返回被弹出的元素,如果未传递参数,则默认弹出并返回最后一个元素,传递了下标参数则弹出并返回相应的元素。
如下:
1seasons = ['spring', 'summmer', 'autumn', 'winter'] 2last_season = seasons.pop() 3print("last_season = ", last_season, "\nseasons = ", seasons)
输出:
1last_season = winter 2seasons = ['spring', 'summmer', 'autumn']
再如:
1first_season = seasons.pop(0) 2print("first_season = ", first_season, "\nseasons = ", seasons)
输出:
1first_season = spring 2seasons = ['summmer', 'autumn']
3.添加元素
向列表中添加元素也有多种方式:
一种是使用append()方法,该方法是将元素添加到列表末尾。
如下:
1weekdays.append('Friday') 2weekdays
输出:
1['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Friday']
可以看到,列表中允许出现重复元素。
一种是insert()方法,可以指定位置添加元素。
如下:
1weekdays.insert(0, 'Monday') 2weekdays
输出:
1['Monday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Friday']
两个列表也可以直接相加、形成新的列表。 如下:
1weekend = ['Saturday', 'Sunday'] 2weekdays = weekdays + weekend 3weekdays
输出:
1['Monday', 2 'Monday', 3 'Tuesday', 4 'Wednesday', 5 'Thursday', 6 'Friday', 7 'Friday', 8 'Saturday', 9 'Sunday']
还可以根据元素获取其再在列表中的下标位置:
1display(weekdays.index('Thursday'),weekdays.index('Friday'))
输出:
14 2 35
可以看到,有重复元素时,会返回第一个下标。
4.列表排序
列表可以按照元素的大小进行排序:
列表方法sort()对列表本身进行原地排序;
通用函数sorted()返回列表的已排序副本。
如下:
1nums = [1,4,2,5,3] 2sorted_nums = sorted(nums) 3print("nums =", nums, "\nsorted_nums =", sorted_nums)
输出:
1nums = [1, 4, 2, 5, 3] 2sorted_nums = [1, 2, 3, 4, 5]
可以看到,nums列表经过排序并传递给sorted_nums。
再如:
1nums.sort() 2nums
输出:
1[1, 2, 3, 4, 5]
直接对列表本身排序; 同时,默认为升序。
还可以进行降序排序,指定参数reverse=True即可:
1sorted_nums = sorted(nums, reverse=True) 2nums.sort(reverse=True) 3display(sorted_nums, nums)
输出:
1[5, 4, 3, 2, 1] 2 3[5, 4, 3, 2, 1]
还可以对字符串进行排序:
1str_ls = ['apple', 'pear', 'lemon', 'peach'] 2str_ls.sort() 3str_ls
输出:
1['apple', 'lemon', 'peach', 'pear']
可以看到: 对字符串进行排序时,首先根据首字母排序,如果首字母相同,再根据下一个字母排序,依此类推。
列表的方法sort()是对列表本身进行排序,返回值为None;
通用函数sorted()对包括列表在内的可迭代对象排序,返回一个排好序的新列表。
如下:
1display(sorted('joshuazhao1234'),''.join(sorted('ACBDZYX')))
输出:
1['1', '2', '3', '4', 'a', 'a', 'h', 'h', 'j', 'o', 'o', 's', 'u', 'z'] 2 3'ABCDXYZ'
join()方法是以传入的参数为分隔符拼接列表元素。
但是不能对不同类型的数据进行排序。 如下:
1obj_list = ["string",1, True, 3.14] 2obj_list.sort() 3obj_list
会报错:
1--------------------------------------------------------------------------- 2TypeError Traceback (most recent call last) 3<ipython-input-8-18b4b015f0f5> in <module> 4 1 obj_list = ["string",1, True, 3.14] 5----> 2 obj_list.sort() 6 3 obj_list 7 8TypeError: '<' not supported between instances of 'int' and 'str'
但是整型和浮点型之间可以进行排序,如下:
1obj_list = [1, 3.14] 2obj_list.sort() 3obj_list
输出:
1['1', '2', '3', '4', 'a', 'a', 'h', 'h', 'j', 'o', 'o', 's', 'u', 'z'] 2 3'ABCDXYZ'
5.列表赋值
将列表类型变量赋值给新的变量:
1#assign vs copy 2a = [1,2,3] 3b = a 4print("a = ", a, "\nb = ", b) 5print() 6a[0] = 2 7print("a = ", a, "\nb = ", b) 8print() 9b[1] = 3 10print("a = ", a, "\nb = ", b)
输出:
1a = [1, 2, 3] 2b = [1, 2, 3] 3 4a = [2, 2, 3] 5b = [2, 2, 3] 6 7a = [2, 3, 3] 8b = [2, 3, 3]
可以看到,在a发生改变之后,b也发生了改变,同时b发生改变之后,a也发生了改变; 这是发生了浅复制,只是将a对应的列表所指向的地址赋值给b,即a、b都指向同一个地址,所以列表改变a、b对应的值都会改变。
对列表进行赋值和创建列表还有其他一些操作:
1a = [1,2,3] 2b = a 3c = a.copy() 4d = a[:] 5e = list(a) 6print("a = ", a, "\nb = ", b, "\nc = ", c, "\nd = ", d, "\ne = ", e) 7print() 8a[0] = 2 9print("a = ", a, "\nb = ", b, "\nc = ", c, "\nd = ", d, "\ne = ", e)
输出:
1a = [1, 2, 3] 2b = [1, 2, 3] 3c = [1, 2, 3] 4d = [1, 2, 3] 5e = [1, 2, 3] 6 7a = [2, 2, 3] 8b = [2, 2, 3] 9c = [1, 2, 3] 10d = [1, 2, 3] 11e = [1, 2, 3]
可以看到,只有直接赋值b = a才会是浅复制,与原数组是同一个数组、同步变化;
其他方法都是通过a数组产生了一个新数组,与原数组不会同步变化。
6.列表推导式
Python支持列表推导式,它可以用一种非常自然、简单的方式来构造列表,就像数学家经常做的那样。
其定义格式为[expression for item in iterable]。
通常,定义一个从0到9的数字列表可能如下:
1num_list = [] 2for i in range(0, 10): 3 num_list.append(i) 4num_list
输出:
1[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
但是还可以有更优雅的实现方式,如:
1num_list = list(range(0,10)) 2num_list
但是还可以进一步优化,即使用列表推导式,如下:
1num_list = [i for i in range(0, 10)] 2num_list
输出与之前相同; 可以看到,列表推导式可以从一个旧的序列生成一个新的列表。
再如:
1num_list = [i**2 for i in range(0, 10)] 2num_list
可以生成0-9的平方的列表。
还可以对序列元素进行条件判断、过滤生成新列表,即带条件的列表推导式,格式为[expression for item in iterable if condition]。
例如创建一个从0到9的奇数列表,如下:
1num_list = [] 2for i in range(0, 10): 3 if i % 2 == 1: 4 num_list.append(i) 5num_list
输出:
1[1, 3, 5, 7, 9]
还可以使用如下方式:
1num_list = list(range(1,10,2)) 2num_list
更简单的方式还是使用带条件的列表推导式,如下:
1num_list = [i for i in range(0,10) if i % 2 == 1] 2num_list
再如:
1import math 2num_list = [i * i for i in range(0,int(math.sqrt(500))) if i % 3 == 2] 3num_list
输出:
1[4, 25, 64, 121, 196, 289, 400]
列表推导式还可以用于将一个列表分成两个列表,一个列表中所有数字都低于分割元素,另一个列表包含所有大于或等于分割元素。 如下:
1import random 2num_list = random.sample(range(10), 10) 3target = 5 4print("list =",num_list) 5print("target =", target) 6 7l1 = [x for x in num_list if x < target] 8l2 = [x for x in num_list if x >= target] 9print("l1:", l1) 10print("l2:", l2)
输出:
1list = [0, 5, 8, 4, 1, 6, 9, 2, 3, 7] 2target = 5 3l1: [0, 4, 1, 2, 3] 4l2: [5, 8, 6, 9, 7]
其中,l2也可以通过以下方式获得:
1l2 = [x for x in num_list if x not in l1] 2print("l2:", l2)
不使用列表推导式实现嵌套定义多维数组或矩阵,如下:
1rows = range(1,4) 2cols = range(1,3) 3 4cells = [] 5for row in rows: 6 for col in cols: 7 cells.append((row, col)) 8cells
输出:
1[(1, 1), (1, 2), (2, 1), (2, 2), (3, 1), (3, 2)]
如果要使用列表推导式,需要使用嵌套,如下:
1cells = [(r, c) for r in rows for c in cols] 2cells
输出相同。
二、元组
与列表类似,元组也是任意项的序列。 然而,元组是不可变的,定义后不能增加、删除或更改。
1.元组基本操作
创建一个空元组如下:
1empty_tuple = () 2empty_tuple
输出:
1()
创建一个不为空的列表:
1week_tuple = ('Monday', 'Tuesday') 2week_tuple
输出:
1('Monday', 'Tuesday')
还可以通过下面的方式创建:
1tpl = 123,456,789 2tpl
输出:
1(123, 456, 789)
在实际生活中,123,456,789就是一个九位数,每3位用逗号分割,但是Python中成为了长度为3的元组。
访问元素的方式和列表类似,如下:
1display(week_tuple[1], tpl[2])
输出:
1'Tuesday' 2 3789
要创建只有一个元素的元组,不能直接用括号将元素括起来,还应该在这个元素后面加1个逗号,。
如下:
1single_tuple1 = ('Monday',) 2single_tuple2 = ('Monday') 3display(type(single_tuple1), type(single_tuple2))
输出:
1tuple 2 3str
可以看到,直接用括号括起来的一个元素就相当于其元素本身,并未形成列表。
列表和元组都支持一次性将元素赋值给个数与元素个数相等的变量如下:
1tom_list = ['Tom', 'Male', 20] 2name, gender, age = tom_list 3print("Name = ", name, "\nGender = ", gender, "\nAge = ", age) 4 5tom_tuple = ('Tom', 'Male', 20) 6name, gender, age = tom_tuple 7print("Name = ", name, "\nGender = ", gender, "\nAge = ", age)
输出:
1Name = Tom 2Gender = Male 3Age = 20 4Name = Tom 5Gender = Male 6Age = 20
此时就可以不用再单个赋值、提高了效率。
元组可以用于交换两个变量的值。 如下:
1a = 1 2b = 2 3print("a = ", a, ", b = ", b) 4 5a, b = b, a 6print("a = ", a, ", b = ", b)
输出:
1a = 1 , b = 2 2a = 2 , b = 1
2.元组和列表的对比
与列表相比,元组有以下特点: (1)元组使用更少的空间(动态); (2)不能错误地破坏元组项,即不能改变元素,元组属于不可变类型; (3)可以用元组作为字典的键; (4)函数参数作为元组传递。
元组不能进行修改。 如下:
1week_tuple[1] = 'Thursday' 2week_tuple
报错:
1TypeError Traceback (most recent call last) 2<ipython-input-24-4df244291e3f> in <module> 3----> 1 week_tuple[1] = 'Thursday' 4 2 week_tuple 5 6TypeError: 'tuple' object does not support item assignment
但是可以通过使用原元组生成新的元组。 如下:
1tpl2 = week_tuple[0], 2 2tpl2
输出:
1('Monday', 2)
可以看到,通过使用原元组的元素,生成了新的元组。
三、字典
字典类似于列表,但是项目的顺序并不重要,它们不会根据偏移量(索引)进行选择。 相反,您可以指定一个与每个值关联的唯一键。 键通常是一个字符串,但它可以是Python的任何不可变类型。
字典就像实际生活中的字典,根据索引来查找元素,而不是通过下标。
1.创建字典
创建一个空字典如下:
1empty_dict = {} 2empty_dict
输出:
1{}
创建一个包含元素的字典,如下:
1pizza = { 2 "size":"medium", 3 "type":"pepperoni", 4 "crust":"Thick", 5 "qty": 1, 6 "deliver":True, 7} 8pizza
输出:
1{'size': 'medium', 2 'type': 'pepperoni', 3 'crust': 'Thick', 4 'qty': 1, 5 'deliver': True}
可以看到,该元组共有5个键值对;
其中,'size': 'medium'就是一个键值对,'size'是键,'medium'是值。
创建字典时,键重复时就会覆盖:
1pizza = { 2 "size":"small", 3 "size":"medium", 4 "type":"pepperoni", 5 "crust":"Thick", 6 "qty": 1, 7 "deliver":True, 8} 9pizza
输出:
1{'size': 'medium', 2 'type': 'pepperoni', 3 'crust': 'Thick', 4 'qty': 1, 5 'deliver': True}
可以看到,键重复时,只会保留后面的值,前面的都会被覆盖。
2.访问字典
访问字典时,是根据键访问对应的值。 如下:
1print(pizza['type'])
输出:
1pepperoni
如果访问未定义的键,就会报错:
1print(pizza['topping'])
报错:
1--------------------------------------------------------------------------- 2KeyError Traceback (most recent call last) 3<ipython-input-31-ca25624dca51> in <module> 4----> 1 print(pizza['topping']) 5 6KeyError: 'topping'
此时可以使用get()方法访问元素,因为如果不存在对应的键时,不会报错而是返回空:
1display(pizza.get('type'),pizza.get('topping'))
输出:
1'pepperoni' 2 3None
可以看到,此时如果未访问到元素时不会报错,返回了None。
还可以获取字典中的所有键、所有值和所有键值对。 如下:
1display(pizza.keys(),pizza.values(),pizza.items())
输出:
1dict_keys(['size', 'type', 'crust', 'qty', 'deliver']) 2 3dict_values(['medium', 'pepperoni', 'Thick', 1, True]) 4 5dict_items([('size', 'medium'), ('type', 'pepperoni'), ('crust', 'Thick'), ('qty', 1), ('deliver', True)])
3.更新字典
更新字典可以直接给对应的键赋值即可。 如下:
1pizza['topping'] = ['cheese','mushroom'] 2pizza
输出:
1{'size': 'medium', 2 'type': 'pepperoni', 3 'crust': 'Thick', 4 'qty': 1, 5 'deliver': True, 6 'topping': ['cheese', 'mushroom']}
上面是添加键值对,也可以修改键值对中的值。 如下:
1pizza['qty'] = 10 2pizza
输出:
1{'size': 'medium', 2 'type': 'pepperoni', 3 'crust': 'Thick', 4 'qty': 10, 5 'deliver': True, 6 'topping': ['cheese', 'mushroom']}
4.删除字典
删除字典中的键值对使用del关键字。
如下:
1del pizza['topping'] 2pizza
输出:
1{'size': 'medium', 2 'type': 'pepperoni', 3 'crust': 'Thick', 4 'qty': 10, 5 'deliver': True}
还可以直接清空字典。 如下:
1pizza.clear() 2pizza
输出:
1{}
四、集合
集合和数学中的集合很类似,没有重复的元素。 集合就像字典,它的值被丢弃,只留下键。
1.创建集合
可以创建一个空集合:
1empty_set = set() 2empty_set
输出:
1set()
创建非空的集合如下:
1even_set = {2,4,6,6,8,10} 2even_set
输出:
1{2, 4, 6, 8, 10}
可以看到,重复的元素被合并,只保留一个元素,因此集合中不存在重复元素。
2.集合运算
集合的运算包括了数学中对集合的运算,如并集、交集、差集等。
如下:
1num_set = {3,6,9,12,15,18} 2display(num_set & even_set, num_set | even_set, num_set - even_set, even_set - num_set, even_set ^ num_set,(even_set | num_set) - (even_set & num_set))
输出:
1{6} 2 3{2, 3, 4, 6, 8, 9, 10, 12, 15, 18} 4 5{3, 9, 12, 15, 18} 6 7{2, 4, 8, 10} 8 9{2, 3, 4, 8, 9, 10, 12, 15, 18} 10 11{2, 3, 4, 8, 9, 10, 12, 15, 18}
五、数据结构操作
1.转化为列表
可以将字符串、元组、字典、集合等数据结构转化为列表。
如下:
1display(list('ababc'),list((1,2,3,4)),list({'name': 'Ed', 'employer': 'Oracle'}),list({'name': 'Ed', 'employer': 'Oracle'}.values()),sorted(list({5,6,7,8})))
输出:
1['a', 'b', 'a', 'b', 'c'] 2 3[1, 2, 3, 4] 4 5['name', 'employer'] 6 7['Ed', 'Oracle'] 8 9[5, 6, 7, 8]
可以看到,在对字典进行转化为列表时,默认使用的是键,可以通过调用values()获取到值再进行转化;
元组转换与列表转换相同;
在将字典或集合转换为列表时,不能保持字典或集合的顺序。
2.转化为字典
转化为字典,需要有成对出现的元素,来保证可以组成键值对,否则不能进行正常转换。
如一般的字符串就不能转化为字典,如下:
1dict('ababc')
报错:
1--------------------------------------------------------------------------- 2ValueError Traceback (most recent call last) 3<ipython-input-47-f82ea82e76c5> in <module> 4----> 1 dict('ababc') 5 6ValueError: dictionary update sequence element #0 has length 1; 2 is required 7
普通列表转换也会报错,如下:
1dict([1,2,3])
报错:
1--------------------------------------------------------------------------- 2TypeError Traceback (most recent call last) 3<ipython-input-48-e308b22febdd> in <module> 4----> 1 dict([1,2,3]) 5 6TypeError: cannot convert dictionary update sequence element #0 to a sequence
有成对出现的数据,即元素的长度为2,就可以进行正常转换。 如下:
1dict(['ab', 'cd', 'ef'])
输出:
1{'a': 'b', 'c': 'd', 'e': 'f'}
可以看到,此时因为列表是由长度为2的字符串组成的,因此可以将第1个字符作为键,第2个字符作为值
再如:
1dict([['a', 'b'], ('c', 'd'), ('e', 'f')])
输出:
1{'a': 'b', 'c': 'd', 'e': 'f'}
可以总结出: 在转化成字典时,被转化的对象必须是序列,并且序列中的每个元素长度为2。
3.zip
zip()函数可以将两个或多个序列生成对应位置元素生成元组作为元素的新序列。
如下:
1s1 = 'abcdefg' 2s2 = 'hijklmn' 3list(zip(s1, s2))
输出:
1[('a', 'h'), 2 ('b', 'i'), 3 ('c', 'j'), 4 ('d', 'k'), 5 ('e', 'l'), 6 ('f', 'm'), 7 ('g', 'n')]
如果两个序列的长度不一致时,会以长度较短的序列为准。
还可以将合成后的序列拆分成原来的序列,如下:
1s3, s4 = zip(*d) 2print(list(s3)) 3print(list(s4))
输出:
1['a', 'b', 'c', 'd', 'e', 'f', 'g'] 2['h', 'i', 'j', 'k', 'l', 'm', 'n']
可以使用相同的函数进行解压缩,只需要在变量前面加一个*即可实现。
4.Mutable和Immutable
Python中数据类型的可变与不可变是通过Mutable和Immutable来控制的:
Mutable即可变类型,包括列表、字典和集合等,还包括自定义的类型,如果需要将其定义为不可变类型,需要重写object的__setattr__和__delattr__方法;
Immutable即不可变类型,包括整型、浮点型、布尔型、字符串和元组等。
如下:
1s='hello' 2print("{} id is {}".format(s,id(s))) 3s='Yello' 4print("{} id is {}".format(s,id(s))) 5s= s+'w' 6print("{} id is {}".format(s,id(s)))
输出:
1hello id is 3116696357488 2Yello id is 3116695670320 3Yellow id is 3116696394800
其中,id()用于获取一个变量在内存中的地址,唯一标识一个变量,在变量重新赋值、发生改变之后,就成为一个新的变量,地址也发生改变。
对于整数来说,情况相同,如下:
1i=1 2print("{} id is {}".format(i,id(i))) 3i=10 4print("{} id is {}".format(i,id(i))) 5i=10+1 6print("{} id is {}".format(i,id(i)))
输出:
11 id is 140709660735264 210 id is 140709660735552 311 id is 140709660735584
对于不可变的变量,不能进行修改,否则会报错:
1s = 'hello' 2s[0] = 'b'
报错:
1--------------------------------------------------------------------------- 2TypeError Traceback (most recent call last) 3<ipython-input-57-ee36c369d295> in <module> 4 1 s = 'hello' 5----> 2 s[0] = 'b' 6 7TypeError: 'str' object does not support item assignment
这在有时候会带来一些问题。
对于可变类型,引用调用(call by reference) 如下:
1try_result=[] #cold refresh 2def try_func(arg,result): 3 print("inside before result is labeled {}, value {}".format(id(result),result)) 4 result.append(arg) 5 print("inside after result is labeled {}, value {}".format(id(result),result)) 6 print("inside try_result is labeled {}, value is {}".format(id(try_result),try_result)) 7 8print("before try_result is labeled {}, value is {}".format(id(try_result),try_result)) 9try_func('a',try_result) 10print("after try_result is labeled {}, value is {}".format(id(try_result),try_result)) 11 12try_result.append('b') 13print(try_result) 14 15try_func('a',try_result)
输出:
1before try_result is labeled 3116696770752, value is [] 2inside before result is labeled 3116696770752, value [] 3inside after result is labeled 3116696770752, value ['a'] 4inside try_result is labeled 3116696770752, value is ['a'] 5after try_result is labeled 3116696770752, value is ['a'] 6['a', 'b'] 7inside before result is labeled 3116696770752, value ['a', 'b'] 8inside after result is labeled 3116696770752, value ['a', 'b', 'a'] 9inside try_result is labeled 3116696770752, value is ['a', 'b', 'a']
此时,try_result是以全局变量的形式定义的;
并且,在整个过程中,因为列表是可变类型,虽然值发生了变化,但是id即地址并没有改变。
而对于不可变类型,值传递(pass by value) 如下:
1imu_number = 10 2def updateNumber(number): 3 print("inside number is labeled {}, value {}".format(id(number),number)) 4 print("inside imu_number is labeled {}, value {}".format(id(imu_number),imu_number)) 5 number = 20 6 print("inside number is {}, outside imu_number is {}".format(number,imu_number)) 7 8print("before imu_number is labeled {}, value {}".format(id(imu_number),imu_number)) 9updateNumber(imu_number) 10print("after imu_number is labeled {}, value {}".format(id(imu_number),imu_number))
输出:
1before imu_number is labeled 140709660735552, value 10 2inside number is labeled 140709660735552, value 10 3inside imu_number is labeled 140709660735552, value 10 4inside number is 20, outside imu_number is 10 5after imu_number is labeled 140709660735552, value 10
可以看到,在整个过程中imu_number的id都没有发生变化; 并且在函数内部和外部,imu_number的值也未发生改变。
需要注意: 给参数提供的默认值是在定义函数时计算的,而不是在函数运行时计算的; 尽量不要使用可变数据类型(如列表或字典)作为默认参数。
如下:
1def buggy(arg, result=[]): 2 print(id(result)) 3 result.append(arg) 4 print(result) 5 6buggy('a') 7buggy('b')
输出:
13116693617856 2['a'] 33116693617856 4['a', 'b']
可以看到,第二次调用时列表中已经包含元素'a',因此再依次调用会存在两个元素,这是因为参数默认值只是在定义函数便确定,之后不会再此使用提供的默认值而是经过计算后的值。
要是需要每次都是空列表中添加值,可以通过赋值给参数不可变的类型,如下:
1def nonbuggy(arg, result=None): 2 if result is None: 3 result = [] 4 print(id(result)) 5 result.append(arg) 6 print(result) 7 8nonbuggy('a') 9nonbuggy('b')
输出:
13116695253696 2['a'] 33116696770496 4['b']
可以看到,此时执行函数时都是向空列表中添加元素。
5.遍历序列数据结构
要是需要遍历一个序列中的元素,可以如下:
1weekdays = ['Monday','Tuesday','Wednesday','Thursday','Friday'] 2i = 0 3while i < len(weekdays): 4 print(weekdays[i]) 5 i +=1
输出:
1Monday 2Tuesday 3Wednesday 4Thursday 5Friday
还可以如下:
1for i in range(len(weekdays)): 2 print(weekdays[i])
输出结果与之前一致。
但是还可以直接用for循环遍历序列,如列表可以直接使用for循环。 如下:
1for day in weekdays: 2 print(day)
输出结果与前面相同; 显然,这种方式更加简单。
还可以使用enumerate()函数对列表对应生成序号。
如下:
1for key,day in enumerate(weekdays): 2 print(str(key)+" "+day)
输出:
10 Monday 21 Tuesday 32 Wednesday 43 Thursday 54 Friday
字典有更丰富的遍历方式。 如下:
1pizza = { 2 "size":"medium", 3 "size":"small", 4 "type":"pepperoni", 5 "crust":"Thick", 6 "qty": 1, 7 "deliver":True, 8} 9 10for k in pizza: 11 print(k) 12print() 13for k, v in pizza.items(): 14 print("key is {}, value is {}".format(k,v)) 15print() 16for v in pizza.values(): 17 print(v)
输出:
1size 2type 3crust 4qty 5deliver 6 7key is size, value is small 8key is type, value is pepperoni 9key is crust, value is Thick 10key is qty, value is 1 11key is deliver, value is True 12 13small 14pepperoni 15Thick 161 17True
可以看到,第一种方式是默认访问的字典的键; 第二种方式访问键值对;第三种方式访问字典的值。
本文原文首发来自博客专栏数据分析,由本人转发至https://www.helloworld.net/p/9o4YT7phjmiJ3,其他平台均属侵权,可点击https://blog.csdn.net/CUFEECR/article/details/108811587查看原文,也可点击https://blog.csdn.net/CUFEECR浏览更多优质原创内容。
