Python的变量类型可以分为两类:可变和不可变数据类型
不可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址也会发生改变,就称不可变数据类型,包括:int(整型)、string(字符串)、tuple(元组);
可变数据类型:当该数据类型的对应变量的值发生了改变,那么它对应的内存地址不发生改变,就称可变数据类型。包括:set(集合)、list(列表)、dict(字典)。
Python参数传递采用的是“传对象引用”的方式,这种方式相当于值传递和引用传递的一种综合。
不可变参数类型是值传递:如果函数收到的是一个不可变数据类型(比如数字、字符或者元组)的引用,就不能直接修改原始对象,相当于通过“传值’来传递对象。
可变参数类型是引用传递:如果函数收到的是一个可变数据类型(比如字典或者列表)的引用,就能修改对象的原始值,相当于通过“传引用”来传递对象。
一个对象能不能作为字典的key,就取决于其有没有hash方法。
字典的键可以是任意不可变数据类型,需要注意的是tuple元组作为键时,tuple不能以任何方式包含可变对象。
四、Python是否可重载
所谓重载,就是多个相同函数名的函数,根据传入的参数个数,参数类型而执行不同的功能。所以函数重载实质上是为了解决编程中参数可变不统一的问题。
在python中,具有重载的思想却没有重载的概念,因为python并不需要重载。python是一门动态语言,不需要声明变量类型,函数中可以接受任何类型的参数也就无法根据参数类型来支持重载,python没有必要去考虑参数的类型问题,这些都可以在函数内部判断处理,并无必要去在写一个函数。python有多种传参方式,默认参数/可变参数/可变关键字参数可以处理函数参数中参数可变的问题。
1、 Dictionary内部是如何实现的?
Dictionary字典相当于一个HashMap,是通过散列表或说哈希表实现的。字典也是一个数组,但数组的索引是键经过哈希函数处理后得到的散列值。哈希函数的目的是使键均匀地分布在数组中,并且可以在内存中以O(1)的时间复杂度进行寻址,从而实现快速查找和修改。
2、hash表怎么解决冲突?
哈希表中哈希函数的设计困难在于将数据均匀分布在哈希表中,从而尽量减少哈希碰撞和冲突。由于不同的键可能具有相同的哈希值,即可能出现冲突,高级的哈希函数能够使冲突数目最小化。
哈希函数就是一个映射,因此哈希函数的设定很灵活,只要使得任何关键字由此所得的哈希函数值都落在表长允许的范围之内即可。本质上看哈希函数不可能做成一个一对一的映射关系,其本质是一个多对一的映射,这也就引出了一个概念:哈希冲突或者说哈希碰撞。哈希碰撞是不可避免的,但是一个好的哈希函数的设计需要尽量避免哈希碰撞。
Python2中使用使用开放地址法解决冲突。
CPython使用伪随机探测(pseudo-random probing)的散列表(hash table)作为字典的底层数据结构。由于这个实现细节,只有可哈希的对象才能作为字典的键。字典的三个基本操作(添加元素,获取元素和删除元素)的平均事件复杂度为O(1)。
3、可变数据类型为什么不能作为字典的键?
Python中所有不可变的内置类型都是可哈希的。可变数据类型(如列表,字典和集合)就是不可哈希的,因此不能作为字典的键。
4、常见的哈希碰撞解决方法
开放寻址法
开放寻址法中,所有的元素都存放在散列表里,当产生哈希冲突时,通过一个探测函数计算出下一个候选位置,如果下一个获选位置还是有冲突,那么不断通过探测函数往下找,直到找个一个空槽来存放待插入元素。
开放地址的意思是除了哈希函数得出的地址可用,当出现冲突的时候其他的地址也一样可用,常见的开放地址思想的方法有线性探测再散列,二次探测再散列等,这些方法都是在第一选择被占用的情况下的解决方法。
再哈希法
这个方法是按顺序规定多个哈希函数,每次查询的时候按顺序调用哈希函数,调用到第一个为空的时候返回不存在,调用到此键的时候返回其值。
链地址法
将所有关键字哈希值相同的记录都存在同一线性链表中,这样不需要占用其他的哈希地址,相同的哈希值在一条链表上,按顺序遍历就可以找到。
公共溢出区
其基本思想是:所有关键字和基本表中关键字为相同哈希值的记录,不管他们由哈希函数得到的哈希地址是什么,一旦发生冲突,都填入溢出表。
答:从三个方面来说,一对象的引用计数机制,
二垃圾回收机制,三内存池机制
一、对象的引用计数机制
Python 内部使用引用计数,来保持追踪内存中的对象,所有对象都有引用计数。
引用计数增加的情况:
a = 12
b=a
aList = [1, 2, a]
foobar(a)
引用计数减少的情况:
用 del 语句对对象别名显示的销毁
del b
引用超出作用域(函数运行结束,所有局部变量被销毁)
对象的一个别名赋值给其他对象
b = 33
对象被从一个窗口对象中移除
aList.remove(a)
窗口本身被销毁
del aList
sys.getrefcount( )函数可以获得对象的当前引用计数
多数情况下,引用计数比你猜测得要大得多。对于不可变数据(如数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
⒉垃圾回收
❶当一个对象的引用计数归零时,它将被垃圾收集机制处理掉。
❷当两个对象 a 和 b 相互引用时,del 语句可以减少 a 和 b 的引用计数,并销毁用于引用底层对象的名称。然而由于每个对象都包含一个对其他对象的应用,
因此引用计数不会归零,对象也不会销毁。(从而导致内存泄露)。为解决这一问题,解释器会定期执行一个循环检测器,搜索不可访问对象的循环并删除它们。
⒊内存池机制
Python 提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
❶Pymalloc 机制。为了加速 Python 的执行效率,Python 引入了一个内存池机制,用于管理对小块内存的申请和释放。
❷Python 中所有小于 256 个字节的对象都使用 pymalloc 实现的分配器,而大的对象则使用系统的 malloc。
❸对于 Python 对象,如整数,浮点数和 List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。
答:lambda 表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用, 也就是指匿名函数
lambda 函数:首要用途是指点短小的回调函数lambda [arguments]:expression
>>> a=lambdax,y:x+y
>>> a(3,11)
答:直接使用 tuple 和 list 函数就行了,type()可以判断对象的类型
答
使用 set 函数,set(list)使用字典函数,
>>>a=[1,2,4,2,4,5,6,5,7,8,9,0]
>>> b={}
>>>b=b.fromkeys(a)
>>>c=list(b.keys())
a=[1,2,4,2,4,5,7,10,5,5,7,8,9,0,3]
a.sort() last=a[-1]
for i inrange(len(a)-2,-1,-1): if last==a:
del a else:last=a print(a)
答:赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个。浅拷贝:创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另外一个也会修改改变){1,完全切片方法;2,工厂函数,如 list();
3,copy 模块的 copy()函数}
深拷贝:创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另外一个不会改变){copy 模块的 deep.deepcopy()函数}
答:try…except…except…[else…][finally…]
执行 try 下的语句,如果引发异常,则执行过程会跳到 except 语句。对每个 except 分支顺序尝试执行,如果引发的异常与 except 中的异常组匹配,执行相应的语句。
如果所有的 except 都不匹配,则异常会传递到下一个调用本代码的最高层 try 代码中。
try 下的语句正常执行,则执行 else 块代码。如果发生异常,就不会执行如果存在 finally 语句,最后总是会执行。
答:pass 语句不会执行任何操作,一般作为占位符或者创建占位程序,whileFalse:pass
答:列出一组数据,经常用在 for in range()循环中
答:可以使用 re 模块中的 sub()函数或者 subn()函数来进行查询和替换,
格式:sub(replacement, string[,count=0])(replacement 是被替换成的文本,string 是需要被替换的文本,count 是一个可选参数,指最大被替换的数量)
>>> import re
>>>p=re.compile(‘blue|white|red')
>>>print(p.sub(‘colour','blue socks and red shoes')) colour socks and colourshoes
>>>print(p.sub(‘colour','blue socks and red shoes',count=1)) colour socks and redshoes
答:re 模块中 match(pattern,string[,flags]),检查 string 的开头是否与 pattern 匹配。
re 模块中re.search(pattern,string[,flags]),在 string 搜索 pattern 的第一个匹配值。
>>>print(re.match(‘super', ‘superstition').span()) (0, 5)
>>>print(re.match(‘super', ‘insuperable')) None
>>>print(re.search(‘super', ‘superstition').span()) (0, 5)
>>>print(re.search(‘super', ‘insuperable').span()) (2, 7)
答:术语叫贪婪匹配( <.> )和非贪婪匹配(<.?> )
例如:
test
<.*> :
test
<.*?> :
答:random 模块
随机整数:random.randint(a,b)
:返回随机整数 x,a<=x<=b
random.randrange(start,stop,[,step])
:返回一个范围在(start,stop,step)之间的随机整数,不包括结束值。
随机实数:random.random( )
:返回 0 到 1 之间的浮点数
random.uniform(a,b)
:返回指定范围内的浮点数。
答:PyChecker 是一个 python 代码的静态分析工具,它可以帮助查找 python 代码的 bug, 会
对代码的复杂度和格式提出警告
Pylint 是另外一个工具可以进行 codingstandard 检查
答:解决方法是在 function 的开始插入一个 global 声明: def f() global x
答:单引号和双引号是等效的,如果要换行,需要符号(),三引号则可以直接换行,并且可以包含注释
如果要表示 Let’s go 这个字符串单引号:s4 = ‘Let\’s go’
双引号:s5 = “Let’s go”
s6 = ‘I realy like“python”!'
这就是单引号和双引号都可以表示字符串的原因了