think python学习笔记(12)

字典和列表
在字典中,列表可以作为值出现。
例如,当倒转字典的时候,可能有的键对应的值,就是由列表组成的

def invert_dict(d):
	inverse = dict()
	for key in d:
		val = d[key]
		if val not in inverse:
			inverse[val] = [key]
		else:
			inverse[val].append(key)
	return inverse

每次循环,key从d获得一个键和相应的值val。如果val不在inverse中,意味着我们之前没有见过它,因此我们生成一个新项并用一个单元素集合来初始化列表。

列表可以作为字典中的值,但是不可以是键
字典使用哈希表实现,这意味着键必须是可哈希的
哈希函数接受一个值并返回一个正数。
字典使用被称作哈希值的这些整数,来存储和查找键值对
如果键是不可变的,那么这种实现可以很好地工作。
如果键是可变的,例如列表,就会发生不好的事情。
例如,当生成一个键值对时,python哈希该键并将其存储在相应的位置。如果改变键然后再次哈希,对应的值就将被存储到另一个位置,字典将不会正确的工作。
字典也是可变的,所以它们不能作为键,但是可以用作值。

备忘录
避免运行程序时,同一形参被多次运算,随着参数的增加,运算量增大,运行效率会很低。
一个解决方法是保存已经计算过的值,将它们存在一个字典中。存储之前计算过的值以便今后使用,它被称为备忘录
下面使用备忘录实现fibonacci功能

known = {0:0,1:1}
def fibonacci(n):
	if n in known:
		return known[n]
	res = fibonacci(n-1) + fibonacci(n-2)
	known[n] = res
	return res

known初始化保存了两个已知的斐波那契数字
当函数被调用时,会先检查对应序列的斐波那契数列是否已经有计算好的值,这样就不用了重复进行迭代
如果当前序列对应的值还没有被计算过,那么就会在字典中加入新的项
这样可以很好地提升运行速度

全部变量
在上例中,known是在函数的外部创建的,因此它属于被称作_main_的特殊帧。因为它里面的变量可以被任意函数访问,它们也被称为全局变量。与函数结束就会消失的局部变量不一样,不同函数调用时全局变量一直都存在。
全局变量普遍用作标记
例如,一些程序使用一个被称作verbose的标记来控制输出的丰富程度:

verbose = True
def examples():
	if verbose:
		print('running example1')
been_called = False
def example2():
	been_called = True

运行后会发现,beencalled的值并为发生改变,原因在于这个语句其实相当于,创建了一个新的局部变量,函数运行结束后,局部变量也会消失,对全局变量并没有影响

要在函数内对全局变量重新赋值,必须在使用前声明该全局变量:

been_called = False
def example2():
	global been_called
	been_called = True

global语句告诉变歧义,在该函数中,该变量名指的都是全局变量,不要生成局部变量

如果全局变量是可变的,可以不加声明的修改它

known = {0:0,1:1}
def example4():
	known[2] = 1

所以可以不加声明的增加删除和替代全局列表或字典中的元素,因为这些操作的基础是,该变量已被初始化,所以会自动去找全局变量。
但是如果想对全局变量重新赋值,就必须声明

def example5():
	global known
	known = dict()

调试
调试大数据集的建议
缩小输入:
如果可能,减小数据结合的大小,例如文本文件,先读取前几行,在查找和解决错误的同时,逐步增加n的值
检查摘要和类型:
打印重要的只要,而不是全部数据集合
例如字典或列表中元素的数目
运行时错误的一个常见原因是,值的类型不正确。通常打印值的类型就够了
编写自检代码:
例如,编写计算平均值的程序,检查运算结果与列表中最大最小的值的关系。这被称作合理性检测,因为能检测出不合理的结果
另一种检查是比较两个不同计算的结果,查看是否一致,这被称为一致性检查
格式化输出:
格式化调试输出能够更容易定位一个错误。
pprint模块提供了一个pprint函数,它可以更可读的格式显示内建类型
print输出结果都在一行,不方便查看
pprint采用分行打印输出,打印出来的数据结构更加完整

元组
元组是不可变的
元组是一组值的序列,其中的值可以是任意的类型,使用整数索引,因此从这点上看,元组和列表非常相似,二者不同之处在于元组的不可变性

t = ('a','c','d')

虽然并非必须,元组通常用括号括起来,用逗号间隔开
使用单一元素创建元组时,需要在结尾处添加一个逗号

t1 = 'a',

将值放置在括号中并不会创建元组

t2 = ('a')
>>>type(t2)
>str

另一个创建元组的方法是使用内建函数tuple。在没有参数传递时,它会创建一个空元组:

t = tuple()

如果实参是一个序列(字符串,列表或者元组),结果将是一个包含序列内元素的元组

t = tuple('lupins')
>>>t
>('l','u','p','i','n','s')

因为tuple是内建函数名,所以应该避免将它用作变量名

列表中的大多数操作符也同样适用于元组,方括号运算度将索引一个元素

t[0]

切片运算符选取一个范围内的元素

t[1:3]

如果试图修改元组中的一个元素,会得到错误信息
因为元组是不可变的,无法改变其中的元素,但是可以使用其他元组替换现有元组

t = ('A',) + t[1:]

关系运算符也适用于元组和其他徐磊,python会首先比较序列中的第一个元素,如果它们相等,就继续比较下一组元素,以此类推,直至比值不同。在它之后的元素,可不会再参与比较

(0,1,2000000) < (0,3,4)

元组赋值
两个变量互换值的操作,传统方法需要使用一个临时变量
但是为了简便,可以通过元祖赋值来实现

 a,b = b,a

等号左侧是变量组成的元组,右侧是表达式组成的元组。每个值都被赋给了对应的变量。变量被重新赋值之前,将先对右侧的表达式进行求值。
左侧变量数和右侧值的数目必须相同

一般来说,右侧可以是任意类型的序列。
例:可以将一个电子邮箱分为用户名和域名

addr = 'monty@python.org'
uname,domain = addr.split('@')

split返回的对象,是一个有两个元素的列表,列表里的值,被分别赋给了两个变量

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值