• python面试题(转)


    下面的代码输出什么?

    list = ['a', 'b', 'c', 'd', 'e']
    print list[10:]

    上面的代码输出[],并且不会导致IndexError错误

    跟你想的一样,当取列表元素的时候,如果索引值超过了元素的个数(例如在上面的列表中,取list[10])将会导致IndexError错误。但是,取一个列表的切片的时候,如果起始索引超过了元素个数,将不会引起IndexError错误,仅返回一个空列表。

    这一特性将会导致一些非常难于追踪的bug,因为在运行时根本没有错误产生。

    下面的代码在Python2中的输出是什么?解释你的答案

    def div1(x,y):
        print "%s/%s = %s" % (x, y, x/y)
    
    def div2(x,y):
        print "%s//%s = %s" % (x, y, x//y)
    
    div1(5,2)
    div1(5.,2)
    div2(5,2)
    div2(5.,2.)

    另外,在Python3中上面的代码的输出有何不同(假设代码中的print语句都转化成了Python3中的语法结构)?

    Python2中,代码的输出是:

    5/2 = 2
    5.0/2 = 2.5
    5//2 = 2
    5.0//2.0 = 2.0

    默认情况下,如果两个操作数都是整数,Python2默认执行整数运算。所以,5/2 结果是2,而5./2结果是2.5

    注意你可以通过下面的import语句来覆盖Python2中的这一行为

    from __future__ import division 

    还要注意“双斜杠”(//)操作符将会一直执行整除,忽略操作数的类型。这就是为什么5.0//2.0即使在Python2中结果也是2.0

    但是在Python3并没有这一行为。两个操作数都是整数时,也不执行整数运算。在Python3中,输出如下:

    5/2 = 2.5
    5.0/2 = 2.5
    5//2 = 2
    5.0//2.0 = 2.0

    下面代码的输出是什么?请解释你的答案

    def extendList(val, list=[]):
        list.append(val)
        return list
    
    list1 = extendList(10)
    list2 = extendList(123,[])
    list3 = extendList('a')
    
    print "list1 = %s" % list1
    print "list2 = %s" % list2
    print "list3 = %s" % list3

    如何修改函数ExtendList的定义才能产生我们希望的行为?

    输出为:

    list1 = [10, 'a']
    list2 = [123]
    list3 = [10, 'a']

    很多人会错误地预计list1等于[10]list3等于['a'],认为extendList函数的list参数在每一次函数被调用时都会被设置为默认值[]

    但是,真实的情况是,默认的list只在函数定义的时候被创建一次。之后不指定list参数地调用extendList函数时,使用的都是同一个list。这是因为带默认参数的表达式是在函数定义的时候被计算的,而不是在函数调用时。

    question:既然Python的默认参数都是在定义时计算的,下次调用时会调用统一个list,那最后一个怎么不得24呢???

    所以,list1list3都是在操作同一个默认list,而list2是在操作它自己创建的一个独立的list(将自己的空list作为参数传递过去)

    extendlist的定义可以这样定义来达到我们预期的效果:

    def extendList(val, list=None):
        if list is None:
            list = []
        list.append(val)
        return list

    调用修改后的函数,输出是:

    list1 = [10]
    list2 = [123]
    list3 = ['a']

    下面代码的输出是什么?请解释你的答案

    class Parent(object):
        x = 1
    
    class Child1(Parent):
        pass
    
    class Child2(Parent):
        pass
    
    print Parent.x, Child1.x, Child2.x
    Child1.x = 2
    print Parent.x, Child1.x, Child2.x
    Parent.x = 3
    print Parent.x, Child1.x, Child2.x

    输出为:

    1 1 1
    1 2 1
    3 2 3

    让很多人感到疑惑和惊讶的是,最后一行的输出竟然不是3 2 1而是3 2 3. 为什么修改了Parent.X的值会影响到Child2.x,但是同时又没有改变Child1.x的值呢?

    这个问题的关键在于,在Python中,类中的变量在内部被当作字典处理。如果一个变量名在当前类的字典中没有被发现,系统将会在这个类的祖先(例如,它的父类)中继续寻找,直到找到为止(如果一个变量名在这个类和这个类的祖先中都没有,那么将会引发一个AttributeError错误)

    因此,在父类中将变量x赋值为1,那么x变量将可以被当前类和所有这个类的子类引用。这就是为什么第一个print语句输出为1 1 1.

    接下来,如果它的子类覆盖了这个值(例如, 当我们执行Child1.x = 2),那么这个变量的值仅仅在这个子类中发生了改变。这就是为什么第二个print语句输出1 2 1

    最后,如果父类改变了这个变量的值(例如,我们执行Parent.x = 3),所有没有覆盖这个参数值的子类(在这个例子中覆盖了参数的就是Child2)都会受到影响,这就是为什么第三个print语句的输出为3 2 3

    下面代码的输出是什么?请解释你的答案

    def multipliers():
        return [lambda x : i * x for i in range(4)]
    
    print [m(2) for m in multipliers()]

    怎么修改multipliers的定义才能达到期望的效果?

    上面代码的输出是[6, 6, 6, 6](不是[0, 2, 4, 6]).

    原因是python的闭包是延迟绑定(late binding)的。这表明在闭包中使用的变量直到内层函数被调用的时候才会被查找。结果是,当调用multipliers()返回的函数时,i参数的值会在这时被在调用环境中查找。所以,无论调用返回的哪个函数,for循环此时已经结束,i等于它最终的值3。因此,所有返回的函数都要乘以传递过来的3,因为上面的代码传递了2作为参数,所以他们都返回了6(即,3 * 2

    (顺便提一句,正如在书《The Hitchhiker’s Guide to Python》中提出来的一样, 有一种广泛传播的误解认为这个问题和lambda表达式有关,事实并非如此。通过labda表达式产生的函数并没有什么特别之处,使用普通的def定义的函数的行为和lambda表达式产生的函数的行为是一样的.)

    下面是一些可以绕过这个问题的方法。

    方法一是像下面一样使用Python的生成器(generator)

    def multipliers():
         for i in range(4): yield lambda x : i * x 

    另一个方法是创造一个闭包,通过使用一个默认参数来立即绑定它的参数

    def multipliers():
        return [lambda x, i=i : i * x for i in range(4)]

    或者,你也可以使用functools.partial函数:

    from functools import partial
    from operator import mul
    
    def multipliers():
        return [partial(mul, i) for i in range(4)]

    考虑下面的代码片段:

    1. list = [ [ ] ] * 5
    2. list  # output?
    3. list[0].append(10)
    4. list  # output?
    5. list[1].append(20)
    6. list  # output?
    7. list.append(30)
    8. list  # output?

    第2,4,6,8行的输出是什么?解释你的答案.

    输出如下:

    [[], [], [], [], []]
    [[10], [10], [10], [10], [10]]
    [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
    [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]

    下面是解释:

    第一行的输出凭直觉就能知道,很容易理解。即:list = [ [ ] ] * 5创建了一个元素是5个列表的列表。

    但是,这里要理解的关键是,list = [ [ ] ] * 5并没有创建一个包含5个不同列表的列表。创建的这个列表里的5个列表,是对同一个列表的引用(a a list of 5 references to the same list)。理解了这些,你就能更好地理解余下的输出。

    list[0].append(10)将数字10添加到第一个列表。但是由于5个列表是对同一个列表的引用,所以输出是[[10], [10], [10], [10], [10]]

    同样的,list[1].append(20)将20追加到第二个列表。但是同样,由于这5个列表引用同一个列表,所以输出:[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]].

    相比之下, list.append(30)是将一个全新的元素追加到“外层”的列表,所以产生了这样的输出:[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].

    有一个拥有N个元素的列表,用一个列表解析式生成一个新的列表,元素的值同时满足以下条件:

    (a) 偶数,以及
    (b) 在原列表中,索引为偶数
    

    例如,如果list[2]的值是偶数,那么这个元素应该也被包含在新列表中,因为它在原列表中的索引也是偶数(即 2). 但是, 如果list[3]是偶数,那这个值不应该被包含在新列表中,因为它在原列表中的索引是一个奇数。

    一个简单的解法如下:

    [x for x in list[::2] if x%2 == 0]

    例如,给出下面的列表:

    #        0   1   2   3    4    5    6    7    8
    list = [ 1 , 3 , 5 , 8 , 10 , 13 , 18 , 36 , 78 ]

    列表解析式[x for x in list[::2] if x%2 == 0] 会生成:

    [10, 18, 78]

    这个表达式首先取列表中索引是偶数的数字,然后过滤掉所有的奇数.

    转自:http://blog.csdn.net/ialexanderi/article/details/69388571

  • 相关阅读:
    13年7月memory point
    getDefinitionByName getDefinition 区别
    cocos2d-html5版日历组件
    一个js对象的代码结构
    计算机操作系统复习
    计算机组成原理复习
    最新的hustoj搭建姿势
    推荐算法学习笔记
    BUPT 2012复试机考 4T
    BUPT 2012复试机考 3T
  • 原文地址:https://www.cnblogs.com/shixisheng/p/7349188.html
Copyright © 2020-2023  润新知