Python一些知识

2021/4/27 20:28:18

本文主要是介绍Python一些知识,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

不定期写一些学到的Python小知识

 
 

1 关于字典中键的一些了解

1.1 字典的查找过程

  1. 通过hash函数将key计算为哈希值;
  2. 通过哈希值确定一个位置,这个位置是一个存放着可能存在冲突的元素的数组(即“桶”,bucket),每个元素都是一个键值对,理想情况下,这个数组里只有1个元素;
  3. 遍历这个数组,找到目标key,返回对应的value。

代码如下:

def lookup(d, key):
	h = hash(key)
	cl = d.dath[h]
	for pair in cl:
	if key == pair[0]:
		return pair[1]
	else:
		raise KeyError, 'Key %s not found." % key

在字典查询的hash函数应满足两个原则:

  1. 如果两个key产生了不同的hash值,那么这两个key对象是不相等的;---- 这个保证能从字典中查找到需要的正确的元素
  2. 如果两个key产生相同的hash值,那么这两个key对象是相等的;---- 这个保证了查询效率

1.2 字典key要满足的要求

要作为字典的key,对象必须要支持__hash__函数,并且满足上面两个原则

1.3 LIst对象为什么不能作为key?

  1. list对象不支持__hash__函数

  2. list对象实现__hash__函数有两种实现方式:基于id和基于内容,然而两种方式对于list对象来说都有一定的副作用,所以Python规定内置的list对象不能作为字典的key。

  3. tuple对象可以作为字典的key,tuple对象就是基于内容实现的__hash__函数,但是若tuple中有元素是可变对象,一人不可以作为字典的key。

  4. 用户自定义的类型可以作为字典的key,默认的hash(object)id(object),默认的cmp(object1, object2)cmp(id(object1), id(object2))。特别注意的是,用户自定义类型是可变的,但依然可以作为字典的key。因为一般来说id比内容更重要,可以基于id来hash。若内容比id重要,可以在定义类的时候重载__hash__函数和__cmp__函数。

 
 

2 赋值/浅拷贝/深拷贝

2.1 几个概念

  • 变量:是一个系统表的元素,拥有指向对象的连接空间
  • 对象:被分配的一块内存,存储其所代表的值
  • 引用:是自动形成的从变量到对象的指针
  • 类型:属于对象,而非变量
  • 不可变对象:一旦创建就不可修改的对象,包括字符串/元组/数值类型
    (该对象所指向的内存中的值不能被改变。当改变没某个变量时,由于其所指的值不能被改变,相当于把原来的值复制一份后再改变,这会开辟一个新地址,变量再指向这个新的地址。)
  • 可变对象:可以改变的对象,包括列表/字典/集合
    (该对象所指向的内存中的值可以改变。变量改变后,实际上是所指的值直接发生改变,并没有发生复制行为,也没有开辟新的地址,也就是原地改变)

2.2 区别

  1. 赋值:只是复制了新对象的引用,不会开辟新的内存空间。
    并不会产生一个独立的对象单独存在,只是将原有的数据块打上一个新的标签,所以当其中一个标签被改变时,数据块就会发生变化,另一个标签也会随之改变。
  2. 浅拷贝:创建新的对象,其内容都是原对象的引用。
    浅拷贝分两种情况讨论:
    (1)当浅复制的值是不可变对象是和“赋值”一样,对象的id值与浅复制原来的值相同。
    (2)当浅复制的值是可变对象时会产生一个“稍微有点依赖的对象”存在
    • 第一种情况:复制的对象中无复杂的子对象,原来值的改变并不会影响浅复制的值,同时浅复制的值改变也不会影响原来的值。原来的id值与浅复制的id值不同。
    • 第二种情况:复制的对象中有复杂子对象,如果不改变其中复杂子对象,浅复制的值改变与原来的值改变互不影响。但是改变复杂子对象,浅复制的值改变与原来的值改变会互相影响。
  3. 深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。
    所以改变原有被复制对象不会对已经复制出来的新对象产生影响。不过对于不可变对象来说,不管是深拷贝还是浅拷贝,地址值和拷贝后的值都是一样的。

 
 

3. 列表生成式/生成器/迭代器

3.1 列表生成式

#### 三种格式

## 1
[x * x for x in range(1, 11)]

## 2
[x * x for x in range(1, 11) if x % 2 == 0]

## 3
[x * x if x % 2 == 0 else -x for x in range(1, 11)]

3.2生成器

通过列表生成器会占用很大的内存空间,而生成器可以是我们一边循环一边生成想要的数据。

创建方法:

## 1.
g = (x * x for x in range(1, 11)]
next(g) # 通过next()来获取每一个生成值

## 2.利用yield将函数转换成关键字
def fib(max):
	n, a, b = 0, 0, 1
	while n < max:
		yield b
		a, b = b, a + b
		n += 1
	return 'done'

## 3.捕获原来函数的返回值
g = fib(6)
while True:
	try:
		x = next(g)
		print('g', x)
	except StopIteraction as e:
		print('Generator return value:', e.value)
		break

3.3 迭代器

区分两个概念:

  1. 可以直接作用与for循环的对象统称为可迭代对象:Iterable
  2. 可以被next()函数调用并不断返回下一个值的对象成为迭代器:Iterator

list, tuple, dict, set, str, 生成器, 带yield的函数,这些虽然都是Iterable,但只有生成器是Iterator。要想将其他的数据类型也变成Iterator,可以使用iter()函数。



这篇关于Python一些知识的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程