1-22常见python面试题

1–python2中 range 和 xrange的区别:

两者用法相同,不同的是range返回的结果是一个列表,而xrange的结果是一个生成器,前者是直接开辟一块内存空间来保存列表,后者是边循环边使用,只有使用时才会开辟内存空间,所以当列表很长时,使用xrange性能要比range好

2–print(int(‘111’, 2)) 打印结果为7 第二个参数代表进制 改语句是将二进制的111输出为十进制整数

3–python获取命令行参数:

def main():
print(len(sys.argv))
print(sys.argv)

05、python中id、is、=、== 分别是比较什么的

id 返回的是对象在内存中的地址 =是赋值 ==判断两边是否相等

06、python的小数据池是什么

简单来说就是python对一定范围内的变量的复用,多次定义时不会重复开辟内存空间
  Python自动将-5~256的整数进行了缓存,当你将这些整数赋值给变量时,并不会重新创建对象,而是使用已经创建好的缓存对象。
  python会将一定规则的字符串在字符串驻留池中创建一份,当你将这些字符串赋值给变量时,并不会重新创建对象, 而是使用在字符串驻留池中创建好的对象。
  其实,无论是缓存还是字符串驻留池,都是python做的一个优化,就是将-5~256的整数,和一定规则的字符串,放在一个‘池’(容器,或者字典)中,无论程序中那些变量指向这些范围内的整数或者字符串,那么他直接在这个‘池’中引用,言外之意,就是内存中只创建  一个。
  优点:能够提高一些字符串,整数处理在时间和空间上的性能;需要值相同的字符串,整数的时候,直接从‘池’里拿来用,避免频繁地创建和销毁,提升效率,节约内存。
  缺点:在‘池’中创建或插入字符串、整数时,会花费更多的时间。
  int:那么大家都知道对于整数来说,小数据池的范围是-5~256 ,如果多个变量都是指向同一个(在这个范围内的)数字,他们在内存中指向的都是一个内存地址。

07、truncate的作用?

truncate() 方法用于截断文件,如果指定了可选参数 size,则表示截断文件为 size 个字符。 如果没有指定 size,则从当前位置起截断;截断之后 size 后面的所有字符被删除。

08、如何调整文件中的指针?

fo.tell()获取当前光标位置

fo.seek(offset, type) #offset移动的偏移量 type 0代表从文件开头开始算起,1代表从当前位置开始算起,2代表从文件末尾算起

09、f.write(‘hello’),hello是写进了文件还是只是存在内存当中?如何使写的内容主动存储到文件中?

写在了内存中,主动存储:f. flush()

10、流程控制当中:pass、continue、break、exit分别是什么作用
pass:相当于站位符,比如定义完函数,若不写函数体会报错,此时写一个pass就不会报错。pass不会执行任何操作
continue:一般在for while循环中用来跳过某次循环,继续执行下一次循环
break: 一般在for while中跳出整个循环体
exit(num) num可省略的参数。通常情况下0表示程序正常退出,1表示程序遇到了某个错误而导致退出。实际运用中可以使用任何整型数据,表示不同的自定义错误类型

11、python当中的赋值、浅拷贝、深拷贝有什么区别?
简单总结:
#赋值:不仅仅值完全一样,而且内存中指向同一地址
#深拷贝就是恩断义绝,不再有任何联系
#浅拷贝是藕断丝连,列表的第一级元素不会因为改变而改变,但是原始列表和浅拷贝对象的子列表仍然会指向同一内存地址,修改其中任何一个必然后引起另外一个的变化,完全切片相当于浅拷贝

improt copy
def cp():
    a = [1,2,[3]]
    b = copy.copy(a)
    c = a
    d = a[:]
    a[-1].append(4)
    print('a:',a) #[1, 2, [3, 4]]
    print('b:',b) #[1, 2, [3, 4]]
    print('c:',c) #[1, 2, [3, 4]]
    print(a is b) #False
    print(a is c) #True
    print(a is d) #False
    print(c is d) #False
if __name__ == '__main__':
   cp()

12、python中的可变数据类型有哪些?为什么叫做可变数据类型?
可变数据类型:list dict
python中的不可变数据类型,不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象;
可变数据类型,允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。

13、python中lambda、map、filter、reduce这些内置函数的作用?利用这些函数,找出1到100中所有的奇数。
Lambda函数又称匿名函数,匿名函数就是没有名字的函数,

    pf = lambda n,m : n * m
    print(pf('3',4)) # 3333  注意这里的类型是字符串
    print(pf(3,4))	# 12 整型 
    #其实上面的函数等同于下面
    def pf(n,m):
    	return n * m

	#map(function,iterable,...)函数时py的内置函数,--参数1 函数名,-- 参数2 一个或者多个可迭代对象,
	#返回集合 py2返回列表 py3返回迭代对象
	def mp():
    re = map(lambda x,y : x*y, [2,3,],[4,5])
    print(re) #<map object at 0x0000020993E2F520> 这行包括以下都是py3的输出结果  py2会返回列表
    print(type(re)) #<class 'map'>
    for m in re:
        print(m) # 8 15
   
	#filter(function,iterable)内置函数--参数1一个函数名--参数2可迭代对象 
	#函数用于过滤序列,过滤掉不符合条件的元素,返回由符合条件元素组成的新(py2返回列表)(py3返回迭代对象)。
	def fl():
	    def is_jishu(n):
	        return n % 2 == 1
	    re = filter(is_jishu, [1,2,3,4,5,6,7])
	    print(list(re)) #[1, 3, 5, 7]
	#reduce(function, iterable[, initializer]):将一个数据集合(链表,元组等)中的所有数据进行下列操作:用传给 reduce 中的函数 function(有两个参数)先对集合中的第 1、2 个元素进行操作,得到的结果再与第三个数据用 function 函数运算,最后得到一个结果。
	#Python3.x reduce() 已经被移到 functools 模块里,如果我们要使用,需要引入 functools 模块来调用 reduce() 函数:from functools imoport reduce
	#参数1--函数,有两个参数, 参数2--可迭代对象, 参数3--可选参数,初始值
	def rd():
	    print([i for i in range(1,10)]) #列表推导式 [1, 2, 3, 4, 5, 6, 7, 8, 9]
	    print(type(range(1,10))) # <class 'range'>
	    print(list(range(1,10))) # [1, 2, 3, 4, 5, 6, 7, 8, 9]
	    re = reduce(lambda x,y : x+y, [i for i in range(1,10)]) #45
	    reduce(lambda x,y : x+y, [i for i in range(1,10)], 100) #145
	    print(re)
	rd()  # 45

14、为什么*args和kwargs叫做函数的非固定参数?它们是什么数据类型?**

	def weizhi(*args,**kwargs):
	    print('不定长位置参数:',args)
	    print('不定长关键字参数:',end='')
	    print(kwargs)
	weizhi(1,2,3,4,56,**{
    
    'a':'aaa','b':'bbb'},c='ccc')
	#上面代码输出:
	#不定长位置参数: (1, 2, 3, 4, 56)
	#不定长关键字参数:{'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}
    weizhi(a='aa',*(11,22,33),d='dd')
    #上面代码输出:
    #不定长位置参数: (11, 22, 33)
	#不定长关键字参数:{'a': 'aa', 'd': 'dd'}

15、函数的作用域有哪些?作用域的查找顺序?

	#函数的租用与有全局作用域、局部作用域、嵌套作用域
	#作用域的查找顺序是由内向外查找,直到查找到最外层,查不到就会报错
	b = 99 #全局作用域
	def foo():
	    a = 100; #此处a是局部作用域变量 在函数外部引用a是会报错的
	    print(a)
	    print(b) #局部可以引用全局变量
	    #print(c) #不可用
	    def bar():
	        c = 'cccc' #嵌套作用域定义的变量在局部作用域下不可用
	        print(a,b,c)
	    bar()

16、给出最后print的结果

 def multipliers():
            return [lambda x : i * x for i in range(4)]
        print([m(2) for m in multipliers()])
 #输出 [6, 6, 6, 6], 没看明白这块代码

17、字符串的拼接可以使用+和join完成,两者有什么区别?
(1)使用+:
由于字符串在py中属于不可变对象,如果要连接如下字符串:s1+s2+s3+…+sN,执行一次+操作便会在内存中申请一块新的内存空间,并将上一次操作的结果和本次操作的右操作数复制到新申请的内存空间,即当执行s1+s2的时候会申请一块内存,并将s1、s2复制到该内存中,依次类推,这样就要进行N-1次内存空间的申请了,非常影响效率。
(2)当使用join时,会一开始就计算出所需要的总的内存空间,也就是说只需要进行一次内存空间的申请,相比 使用 + ,效率提升巨大。

import timeit
strlist = ["It is a long value string will not keep in memory" for n in range(100000)]
def join_test():
    return ''.join(strlist)
def jia_test():
    res = ''
    for k,v in enumerate(strlist):
        res = res + v
    return res


if __name__ == '__main__':
    joinTm = timeit.Timer("join_test", "from __main__ import join_test")
    #print(joinTm.timeit(number=100000000)) #1.0149533
    print(joinTm.timeit(number=10000000000)) #101.60292290000001
    jiaTm = timeit.Timer("jia_test", "from __main__ import jia_test")
    #print(jiaTm.timeit(number=100000000)) #1.0162013
    print(jiaTm.timeit(number=10000000000)) #101.61203029999999
#PS为啥我测不出差距所在呢???奇怪看了好多帖子都说拼接次数越多的时候join越快。。。。。望大神指点

18、python的自省是指的什么?
在日常生活中,自省(introspection)是一种自我检查行为。
在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
说的更简单直白一点:自省就是面向对象的语言所写的程序在运行时,能够知道对象的类型。简单一句就是,运行时能够获知对象的类型。
例如python, buby, object-C, c++都有自省的能力,这里面的c++的自省的能力最弱,只能够知道是什么类型,而像python可以知道是什么类型,还有什么属性。
最好的理解自省就是通过例子: Type introspection 这里是各种编程语言中自省(introspection)的例子(这个链接里的例子很重要,也许你很难通过叙述理解什么是introspection,但是通过这些例子,一下子你就可以理解了)
回到Python,Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

19、一行代码实现1-100偶数求和,至少5种方式

	#目前只想到这两种方法
	ou = reduce(lambda n,m:n+m,filter(lambda x:x % 2==0,range(1,101)))
    print(ou)
    ol = sum(list(range(0,101,2)))
    print(ol)
   

20、什么是闭包函数,闭包函数满足什么样的条件?请写一个常见的闭包函数。

#闭包
#1 在一个外函数中定义了一个内函数。
#2 内函数里运用了外函数的临时变量。
#3 并且外函数的返回值是内函数的引用。
#一般情况下,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一
#种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给
#了内部函数,然后自己再结束。
def outer(a):#outer是外部函数
    b = 10
    def inner():#inner是内部函数
        print(a + b) #在内函数中,用到了外函数
    return inner #外函数的返回值是内函数的引用


if __name__ == '__main__':
	#在此处返回的是内部函数的引用.--分析outer函数内,此时外函数有两个临时变量a=9、b=10
	#并且创建了内部函数inner并将内部函数的引用返回给func
	#外部函数的结束时发现,内部函数有对临时变量a、b的引用,就不会释放变量内存,而是将临时变量绑定给内部函数inner
    func = outer(9) #func存的是外函数的返回值,也就是内函数的引用
    func() #这里相当于执行inner(),得到19
    print(type(func)) #返回的是 <class funciton>
一:
1---------外部函数返回了内部函数的引用:
***首先,我们先要明白引用是什么?在py中一切皆对象包括class def int float string list dict等都是对象
当定义a=1时发生了什么? 首先py会在内存中开辟一块空间存了1,a会引用1这个值的内存位置的引用,这里类似于C中的指针,引用你可以理解成内存地址,这样容易理解。所以你在使用变量a的时候,就会马上通过引用找到对应的值是1
***相同的道理,在python中定义一个函数def demo():  的时候,内存当中会开辟一些空间,存下这个函数的代码、内部的局部变量等等。这个demo只不过是一个变量名字,它里面存了这个函数所在位置的引用而已。我们还可以进行x = demo, y = demo, 这样的操作就相当于,把demo里存的东西赋值给x和y,这样x 和y 都指向了demo函数所在的引用,在这之后我们可以用x() 或者 y() 来调用我们自己创建的demo() ,调用的实际上根本就是一个函数,x、y和demo三个变量名存了同一个函数的引用。
***最后,由外函数返回了内函数的引用,所以在外部func=outer(1) 得到的func实际上是inner的函数引用,执行func()就是相当于执行 inner()
2---------外部函数吧临时变量绑定给内函数,一个函数正常结束的时候,会把临时变量释放给内存,但是如果此时在函数内部还有函数引用了外部函数的临时变量,这个时候外部函数不会释放临时变量,而是把用到的临时变量绑定到内部函数上,故外部函数虽已结束,但是内部函数仍然能够引用外部函数的临时变量.

二:
闭包中内函数修改外函数局部变量
在闭包内函数中,可以随意使用外函数绑定来的临时变量,但是如果想修改外函数临时变量数值的时候发现出问题了!
  在基本的python语法当中,一个函数可以随意读取全局数据,但是要修改全局数据的时候有两种方法:
       1 global 声明全局变量
       2 全局变量是可变类型数据的时候可以修改
  在闭包内函数也是类似的情况。在内函数中想修改闭包变量(外函数绑定给内函数的局部变量)的时候:
  1 在python3中,可以用nonlocal 关键字声明 一个变量, 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。
  2 在python2中,没有nonlocal这个关键字,可以把闭包变量改成可变类型数据进行修改,比如列表。
	#修改闭包变量的实例
	# outer是外部函数 a和b都是外函数的临时变量
	def outer( a ):
	    b = 10  # a和b都是闭包变量
	    c = [a] #这里对应修改闭包变量的方法2
	    # inner是内函数
	    def inner():
	        #内函数中想修改闭包变量
	        nonlocal  b  # 方法1 nonlocal关键字声明
	        b+=1
	        c[0] += 1 # 方法二,把闭包变量修改成可变数据类型 比如列表
	        print(c[0])
	        print(b)
	    # 外函数的返回值是内函数的引用
	    return inner
	
	if __name__ == '__main__':
	    demo = outer(9)
	    demo() # 10  11
使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量:

	def outer(x):
	     def inner(y):
	         nonlocal x
	         x+=y
	         return x
	     return inner
	a = outer(10)
	print(a(1)) #11 #两次分别打印出11和14,由此可见,每次调用inner的时候,使用的闭包变量x实际上是同一个
	print(a(3))	#14
	
#闭包用途:
#a. 装饰器!装饰器是做什么的?其中一个应用就是,我们工作中写了一个登录功能,我们想统计这个功能执行花了多长时间,我们可以用装饰器装饰这个登录模块,装饰器帮我们完成登录函数执行之前和之后取时间。
#b.面向对象!经历了上面的分析,我们发现外函数的临时变量送给了内函数。大家回想一下类对象的情况,对象有好多类似的属性和方法,所以我们创建类,用类创建出来的对象都具有相同的属性方法。闭包也是实现面向对象的方法之一。在python当中虽然我们不这样用,在其他编程语言入比如javaScript中,经常用闭包来实现面向对象编程
#*******************************下面讲装饰器***********************************#
#我想计算某一函数的运行时间,但是计算时间的代码不想写在此函数代码体里
#装饰器
	import time
	from random import randint
	def show_time(func):
	    def inner():
	        start_tm = time.time()
	        func()
	        end_tm = time.time()
	        tm = end_tm - start_tm
	        print(f'运行时间:{tm}')
	    return inner
	def test():
	    print('***test function is running**')
	    time.sleep(randint(3,5))
	inner = show_time(test) #***test function is running**
	inner() #运行时间:5.000543594360352

#下面实现一个带参数的被装饰函数
#一下 满足 1-2-3三个条件 满足闭包的概念,装饰器本质上是一种闭包
	def count_time(func):
	    def inner(*args): #1--此处定义了内函数
	        print('我是内部函数打印了参数:')
	        print(args)
	        st = time.time()
	        func(*args) #2--在内部函数中用到了外部函数的临时变量 *args
	        et = time.time()
	        print(f'我是内部函数计算运行时间:{et-st}')
	    return inner #3--外部函数返回了内部函数的引用
	@count_time
	def can(*args):
	    print('我是被装饰函数的打印参数:')
	    print(args)
	    time.sleep(randint(1,2))
	can(*(1,3,4))
	#上面函数输出结果:
	#我是内部函数打印了参数:
	#(1, 3, 4)
	#我是被装饰函数的打印参数:
	#(1, 3, 4)
	#我是内部函数计算运行时间:1.0006871223449707
****************************************************************
# 使用装饰器的缺点:
# 1.位置错误的代码 不能在装饰器之外添加逻辑功能
# 2.不能装饰@staticmethod 或者 @classmethod已经装饰过的方法
# 3.装饰器会对原函数的元信息进行更改,比如函数的docstring,__name__,参数列表
# 常用的内置装饰器:
# 1.staticmethod: 类似实现了静态方法 注入以后,可以直接 : 类名.方法
# 2.property:经过property装饰过的函数 不再是一个函数,而是一个property,类似实现get,set方法
# 3.classmethod: 与staticmethod很相似,貌似就只有这一点区别:
# 第一个参数需要是表示自身类的 cls 参数,
# 可以来调用类的属性,类的方法,实例化对象等。
****************************************************************

21、什么是递归函数?请用递归函数实现10的阶乘
递归就是一个函数在其函数体内调用它本身的动作,执行递归函数会反复调用其本身,每执行一次都会进入新的一层,但是递归必须有结束条件,那么什么事结束条件呢?递归在执行时一直往前递推,知道遇到墙后返回,这道墙就是结束条件。可以看出递归中有两个要素:递推关系结束条件
注意: 递归的时候每调用函数一次,计算机都会给这次函数分配新的空间,也就是说,当被调函数返回的时候,调用函数中的变量依然会保持原先的值,否则递归不可能实现反向输出

	def jc(n):
	    if not isinstance(n,int):
	        print('必须为整数参数')
	    if n < 2:
	        if n<0:
	            print('负数无阶乘')
	        return n
	    else:
	        return n * jc(n-1)
	print(jc(10))

22、写一个简单的登录验证的装饰器。

	#编写一个装饰器,模拟登录的简单验证
	#只验证用户名和密码是否正确,如果用户名为 root 密码为 123 则正确,否则不正确
	def login_adorner(func):
	    def inner(user, password):
	        if user == 'root' and password == 123:
	            print('验证通过')
	            func(user, password)
	        else:
	            print('用户名或密码错误')
	    return inner;
	
	@login_adorner
	def denglu(user, password):
	    print('我是登陆动作')
	denglu('root',123)

Guess you like

Origin blog.csdn.net/sasibingdu/article/details/114668587