Python面试题练习
1、实现1--100之和
1 #解答一 2 print sum(xrange(101)) 3 4 #解答二 5 s=0 6 for i in xrange(101): 7 s = s + i 8 print s
2、如何在一个函数内部修改全局变量
#coding=utf-8 name = "ryan" #全局变量 def fun(): country = "China" #局部变量 print name global name #声明全局变量 name = "joe" #修改全局变量 print name fun() print name
3、谈下GIL
GIL是python的全局解释器锁,同一进程中假如有多个线程运行,一个线程在运行python程序的时候会霸占python解释器(加了一把锁即GIL),使该进程内的其他线程无法运行,等该线程运行完后其他线程才能运行。如果线程运行过程中遇到耗时操作,则解释器锁解开,使其他线程运行。所以在多线程中,线程的运行仍是有先后顺序的,并不是同时进行。
多进程中因为每个进程都能被系统分配资源,相当于每个进程有了一个python解释器,所以多进程可以实现多个进程的同时运行,缺点是进程系统资源开销大。
4、实现列表去重的方法
#coding=utf-8 #解答一:使用Set集合 a = [1,2,3,3,4,4,4] a = list(set(a)) #解答二 a = [1,2,3,3,4,4,4] b=[] for i in a: if i not in b: b.append(i) a=b #解答三 a = [1,2,3,3,4,4,4] c={} for i in a: if a.count(i) > 1: c.update({a.count(i):i}) for i in c: for j in xrange(i-1): a.remove(c[i])
5、fun(*args,**kwargs)中的*args,**kwargs什么意思?
#*args是用来发送一个非键值对的可变数量的参数列表给一个函数 #**kwargs是用来发送一个不定长度的键值对的参数给一个函数
6、python2和python3的range(100)的区别
#python2返回列表,python3返回迭代器,节约内存
7、一句话解释什么样的语言能够用装饰器?
#函数可以作为参数传递的语言,可以使用装饰器
8、简述面向对象中__new__和__init__区别
9、简述with方法打开处理文件帮我我们做了什么?
10、if __name__ == '__main__' 如何正确理解?
#coding=utf-8 ''' 对于很多编程语言来说,程序都必须要有一个入口,比如 C,C++,以及完全面向对象的编程语言 Java,C# 等。如果你接触过这些语言,对于程序入口这个概念应该很好理解,C 和 C++ 都需要有一个 main 函数来作为程序的入口,也就是程序的运行会从 main 函数开始。同样,Java 和 C# 必须要有一个包含 Main 方法的主类来作为程序入口。 而 Python 则有不同,它属于脚本语言,不像编译型语言那样先将程序编译成二进制再运行,而是动态的逐行解释运行。也就是从脚本第一行开始运行,没有统一的入口。 一个 Python 源码文件除了可以被直接运行外,还可以作为模块(也就是库)被导入。不管是导入还是直接运行,最顶层的代码都会被运行(Python 用缩进来区分代码层次)。而实际上在导入的时候,有一部分代码我们是不希望被运行的。 ''' #举一个例子来说明一下,假设我们有一个 const.py 文件,内容如下: PI = 3.14 def main(): print "PI:", PI main() ''' 我们在这个文件里边定义了一些常量,然后又写了一个 main 函数来输出定义的常量,最后运行 main 函数就相当于对定义做一遍人工检查,看看值设置的都对不对。然后我们直接执行该文件(python const.py),输出: PI: 3.14 ''' ''' 现在,我们有一个 area.py 文件,用于计算圆的面积,该文件里边需要用到 const.py 文件中的 PI 变量,那么我们从 const.py 中把 PI 变量导入到 area.py 中: ''' from const import PI def calc_round_area(radius): return PI * (radius ** 2) def main(): print "round area: ", calc_round_area(2) main() ''' 运行 area.py,输出结果: PI: 3.14 round area: 12.56 可以看到,const 中的 main 函数也被运行了,实际上我们是不希望它被运行,提供 main 也只是为了对常量定义进行下测试。这时,if __name__ == '__main__' 就派上了用场。把 const.py 改一下: ''' PI = 3.14 def main(): print "PI:", PI if __name__ == "__main__": main() ''' 然后再运行 area.py,输出如下: round area: 12.56 再运行下 const.py,输出如下: PI: 3.14 这才是我们想要的效果。 if __name__ == '__main__' 就相当于是 Python 模拟的程序入口。Python 本身并没有规定这么写,这只是一种编码习惯。由于模块之间相互引用,不同模块可能都有这样的定义,而入口程序只能有一个。到底哪个入口程序被选中,这取决于 __name__ 的值。 ''' #https://www.cnblogs.com/yaohong/p/8660209.html
11、深浅拷贝的区别
#Python的数据结构总体分为两类: #1、字符串和数字 #2、列表、元组、字典等 一、字符串和数字 对于字符串和数字而言,赋值(=)、浅拷贝(copy)和深拷贝(deepcopy)其实都没有意义,因为它们都永远指向同一个内存地址。 >>> import copy >>> a1 = 100 >>> id(a1) 1426656816 # a1的内存地址 # 赋值 >>> a2 = a1 >>> id(a2) 1426656816 # 浅拷贝 >>> a3 = copy.copy(a1) >>> id(a3) 1426656816 # 深拷贝 >>> a4 = copy.deepcopy(a1) >>> id(a4) 1426656816 二、列表、元组、字典等 对于列表、字典而言,进行赋值(=)、浅拷贝(copy)和深拷贝(deepcopy),其引起的变化是不一样的。 2.1、赋值(=) names = ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2 = names names[1] = "Pear" print(names) print(name2) print("-----------------") names[3][1] = "Dog" print(names) print(name2) print(id(names)) print(id(name2)) # 输出 ['Angle', 'Pear', 'Athena', ['Banana', 'apple']] ['Angle', 'Pear', 'Athena', ['Banana', 'apple']] ----------------- ['Angle', 'Pear', 'Athena', ['Banana', 'Dog']] ['Angle', 'Pear', 'Athena', ['Banana', 'Dog']] 1504387406536 1504387406536 # 可以看到names 的每一次变化,name2也会改变,因为他们的内存地址是一样的 #这和字符串和数字是不一样的,当我们定义 a =1 ,b = a ,改变a时,b是不会有变化的。列表和字典等会跟着变化,因为他们的内存地址是一样的。 a = 1 b = a a = 100 print(a) print(b) # 输出 100 1 2.2、浅拷贝(copy) import copy names = ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2 = copy.copy(names) names[1] = "宙斯" print(names, "names的内存地址是{}".format(id(names))) print(name2, "name2的内存地址是{}".format(id(name2))) #输出 ['Angle', '宙斯', 'Athena', ['Banana', 'apple']] names的内存地址是1764417452744 ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2的内存地址是1764416035080 我们浅copy了一个name2,同时我们将names中的Zous的值改为中文,但是name2的没有改变。因为他们的内存地址是不一样的,改变其中一个不影响另外一个。 我们接下来看: import copy names = ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2 = copy.copy(names) names[1] = "宙斯" print(names, "names的内存地址是{}".format(id(names))) print(name2, "name2的内存地址是{}".format(id(name2))) names[3][1] = '苹果' print(names, id(names[3])) print(name2, id(name2[3])) # 输出 ['Angle', '宙斯', 'Athena', ['Banana', 'apple']] names的内存地址是2306153560776 ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2的内存地址是2306152155528 ['Angle', '宙斯', 'Athena', ['Banana', '苹果']] 2306153648968 ['Angle', 'Zous', 'Athena', ['Banana', '苹果']] 2306153648968 # 这次我们不仅改变了最外层的列表的值,还改变了列表中一个列表的值。 # 这次的结果是 里层的列表跟着做了改变 我们通过打印的内存地址可以明显看出,整个外层列表的内存地址是不一样的,但是里层的列表内存地址是一致的。 总结:浅拷贝(copy.copy(x))只是将列表等数据类型的第一层copy了一下,内存地址改变了。但是对于里层的数据类型的内存地址没有改变。 2.3、深拷贝(deepcopy) 深拷贝(copy.deepcopy(x))其实就是重新开辟了一个新的内存地址,存储deepcopy后的数据,和原来数据的内存地址完全不一样了,包括里层数据类型的内存地址。 import copy names = ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2 = copy.deepcopy(names) names[1] = "宙斯" print(names, "names的内存地址是{}".format(id(names))) print(name2, "name2的内存地址是{}".format(id(name2))) names[3][1] = '苹果' print(names, id(names[3])) print(name2, id(name2[3])) #输出 ['Angle', '宙斯', 'Athena', ['Banana', 'apple']] names的内存地址是2379824216776 ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] name2的内存地址是2379824217160 ['Angle', '宙斯', 'Athena', ['Banana', '苹果']] 2379824304968 ['Angle', 'Zous', 'Athena', ['Banana', 'apple']] 2379824305032 #可以看出,names不论是改变外层还是里层列表的数据,都不会影响到name2。
链接: https://www.cnblogs.com/bigberg/p/7246756.html