python相关面试题总结(二)

  1. 1<(2==2) 和 1<2 == 2结果分别是什么?为什么?
1<(2==2) # False
1<2 ==2 # True
#解释
1 ==True 为True
0 == False 为True
1<(2==2) 相当于1<1 所以为错误
1<2 == 2 被分解成1<2 and 2==2 所以为True

详情请见

python相关面试题总结(二)_第1张图片
运算符

  1. [i%2 for i in range(10)] 和 (i % 2 for i in range(10)) 输出结果分别是什么?
[0,0,1,1,2,2,3,3,4,4]
一个生成器: at 0x1010aa620>

23.python2 和python3有哪些显著的区别?

print

print在 Python 2 中是一个声明,而不是一个函数调用。
python3 中print是一个函数

整除

Python 2.7.6
3 / 2 = 1
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0
Python 3.6.1
3 / 2 = 1.5
3 // 2 = 1
3 / 2.0 = 1.5
3 // 2.0 = 1.0

Unicode

Python 2 有 ASCII str() 类型,unicode() 是单独的,不是 byte 类型。
现在, 在 Python 3,我们最终有了 Unicode (utf-8) 字符串,以及一个字节类:byte 和 bytearrays。

range xrange

在 Python 2 中 xrange() 创建迭代对象的用法是非常流行的。比如: for 循环或者是列表/集合/字典推导式。
这个表现十分像生成器(比如。“惰性求值”)。但是这个 xrange-iterable 是无穷的,意味着你可以无限遍历。
由于它的惰性求值,如果你不得仅仅不遍历它一次,xrange() 函数 比 range() 更快(比如 for 循环)。尽管如此,对比迭代一次,不建议你重复迭代多次,因为生成器每次都从头开始。
在 Python 3 中,range() 是像 xrange() 那样实现以至于一个专门的 xrange() 函数都不再存在(在 Python 3 中 xrange() 会抛出命名异常)。

For循环变量和全局命名空间泄漏

python 2
print 'Python', python_version()
i = 1
print 'before: i =', i
print 'comprehension: ', [i for i in range(5)]
print 'after: i =', I

python3
print('Python', python_version())
i = 1
print('before: i =', i)
print('comprehension:', [i for i in range(5)])
print('after: i =', i)

通过input()解析用户的输入
详情略
返回可迭代对象,而不是列表

详情请移步

24.请描述unicode,utf-8,gbk等编码之间的关系

#阶段一:现代计算机起源于美国,最早诞生也是基于英文考虑的ASCII
ASCII:一个Bytes代表一个字符(英文字符/键盘上的所有其他字符),1Bytes=8bit,8bit可以表示0-2**8-1种变化,即可以表示256个字符

ASCII最初只用了后七位,127个数字,已经完全能够代表键盘上所有的字符了(英文字符/键盘的所有其他字符),后来为了将拉丁文也编码进了ASCII表,将最高位也占用了

#阶段二:为了满足中文和英文,中国人定制了GBK
GBK:2Bytes代表一个中文字符,1Bytes表示一个英文字符
为了满足其他国家,各个国家纷纷定制了自己的编码
日本把日文编到Shift_JIS里,韩国把韩文编到Euc-kr里

#阶段三:各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。如何解决这个问题呢???

#!!!!!!!!!!!!非常重要!!!!!!!!!!!!
说白了乱码问题的本质就是不统一,如果我们能统一全世界,规定全世界只能使用一种文字符号,然后统一使用一种编码,那么乱码问题将不复存在,
ps:就像当年秦始皇统一中国一样,书同文车同轨,所有的麻烦事全部解决
很明显,上述的假设是不可能成立的。很多地方或老的系统、应用软件仍会采用各种各样的编码,这是历史遗留问题。于是我们必须找出一种解决方案或者说编码方案,需要同时满足:
#1、能够兼容万国字符
#2、与全世界所有的字符编码都有映射关系,这样就可以转换成任意国家的字符编码

这就是unicode(定长), 统一用2Bytes代表一个字符, 虽然2**16-1=65535,但unicode却可以存放100w+个字符,因为unicode存放了与其他编码的映射关系,准确地说unicode并不是一种严格意义上的字符编码表,下载pdf来查看unicode的详情:
链接:https://pan.baidu.com/s/1dEV3RYp

很明显对于通篇都是英文的文本来说,unicode的式无疑是多了一倍的存储空间(二进制最终都是以电或者磁的方式存储到存储介质中的)

于是产生了UTF-8(可变长,全称Unicode Transformation Format),对英文字符只用1Bytes表示,对中文字符用3Bytes,对其他生僻字用更多的Bytes去存


#总结:内存中统一采用unicode,浪费空间来换取可以转换成任意编码(不乱码),硬盘可以采用各种编码,如utf-8,保证存放于硬盘或者基于网络传输的数据量很小,提高传输效率与稳定性。

!!!重点!!!

25.请描述with的用法?如果自己的类需要支持with语句,应该如何书写?

基本格式
with context_expression [as target(s)]:
    with-body

这里 context_expression 要返回一个上下文管理器对象,该对象并不赋值给 as 子句中的 target(s) ,
如果指定了 as 子句的话,会将上下文管理器的 __enter__() 方法的返回值赋值给 target(s)。
target(s) 可以是单个变量,或者由“()”括起来的元组(不能是仅仅由“,”分隔的变量列表,必须加“()”)。

自定义的上下文管理器要实现上下文管理协议所需要的 __enter__() 和 __exit__() 两个方法
context_manager.__enter__() :进入上下文管理器的运行时上下文,在语句体执行前调用。with 语句将该方法的返回值赋值给 as 子句中的 target,如果指定了 as 子句的话
context_manager.__exit__(exc_type, exc_value, exc_traceback) :退出与上下文管理器相关的运行时上下文,返回一个布尔值表示是否对发生的异常进行处理。

详见
26.python中如果判断一个对象是否可调用对象?那些对象可以是可调用对象?如何定义一个类,使其对象本身就是可调用对象?
可调用对象:任何可通过函数操作符()来调用的对象。Python有4种可调用对象:函数,方法,类,以及一些类的实例。 
为了是一些类的实例是可调用对象必须在类中定义相应的__call__方法
27.什么是装饰器?写一个装饰器,可以打印输出方法执行时长的信息。
装饰器:返回值是函数的高阶函数,主要作用是实现在不改变原函数的情况下对原函数进行扩展.减少代码的重复编写及使用

def deco(func):
    def inner(*args, **kwargs):
        now = time.time()
        ret = func(*args, **kwargs)
        print(time.time() - now)
        return ret
    return inner

@deco
def func():
    time.sleep(1)
    return 'hello'
print(func())

装饰器详解

  1. 什么是进程,线程,协程,说一说python对他们的支持?
进程是一个具有独立功能的程序关于某个数据集合的一次运行活动。它可以申请和拥有系统资源,是一个动态的概念,是一个活动的实体。
它不只是程序的代码,还包括当前的活动,通过程序计数器的值和处理寄存器的内容来表示。

线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。一个标准的线程由线程ID,当前指令指针(PC),寄存器集合和堆栈组 成。
另外,线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个 进程的其它线程共享进程所拥有的全部资源

协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
#1. python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)
#2. 单线程内开启协程,一旦遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(!!!非io操作的切换与效率无关)

详情请见
29.def f(a,b=[])这种写法中有什么陷阱?

变量b传递给函数的是指针,指针指向的是列表在内存中的地址,在函数调用中对list的操作是对原地址进行操作.
从而影响原有变量(默认参数的内容就变了,不再是函数定义时的[]了).

30.哪些情况下,y! = x - (x-y)会成立?
x,y是两个不相等的非空集合
31.用python实现"九九乘法表",用两种不同的方式实现

for i in range(1, 10):
    print('')
    for j in range(1, i + 1):
        print(j, '*', i, '=', i * j, end='  ')

def f(i):
    if i >= 1:

        f(i - 1)
        print('')
        for j in range(1, i + 1):
            print('%s*%s=%s' % (j, i, i * j), end=' ')

f(9)

32.如何在Python中拷贝一个对象?并说明它们之间的区别

注意赋值和浅拷贝的区别
如l1 = ['a','b','c'] # 这段代码是是对l1 的初始化操作,开辟一个内存空间存储列表,l1 这个变量指向这个列表
l2 = l1 # 这属于赋值操作
# 如果更改l1,l2也会一起改变,因为两个变量指向的是同一个位置
import copy
浅拷贝:不管多么复杂的数据结构,浅拷贝都只会copy一层
copy.copy(...),在多层嵌套时可能会一个数据可改变可能会影响其他的数据.
深拷贝:深拷贝会完全复制原变量相关的所有数据,在内存中生成一套完全一样的内容,在这个过程中我们对这两个变量中的一个进行任意修改都不会影响其他变量.
深拷贝就是在内存中重新开辟一块空间,不管数据结构多么复杂,只要遇到可能发生改变的数据类型,就重新开辟一块内存空间把内容复制下来,直到最后一层,不再有复杂的数据类型,就保持其原引用。这样,不管数据结构多么的复杂,数据之间的修改都不会相互影响
copy.deepcopy(...)

详情请见
33.谈谈你对Python装饰器的理解
python装饰器就是接收某一个函数作为参数并且返回值为函数的高阶函数,
主要作用是实现在不改变原函数的情况下对原函数进行扩展.减少代码的重复编写及使用.
34.Python里面match()和search()的区别?(**)
参见其他题目
35.获取list的元素个数,和向末尾追加元素所用的方法分别是?

.count(*)# 计算某个元素的个数
.append() # 添加元素的方法
.sort()# 对列表进行排序

36.在数组中找到具有最大和的连续子数组(至少包含一个数字)
例如给定数组[-2,1,-3,4,-1,1,1,-5,4]
连续子阵列[4,-1,2,1]具有最大和6.

def maxSubArray(nums):
    # write your code here
    n = len(nums)
    maxSum = sum(nums)
    curSum = 0
    for i in range(n):
        # 从i开始求和,如果当前和大于maxSum,则赋值给maxSum
        curSum += nums[i]
        if curSum > maxSum:
            maxSum = curSum
        # 前面的和如果已经小于0了,那么加上下一个元素值,肯定是小于下一个元素值
        # 所以如果前面加起来的值小于0了,则舍弃前面的和,从下一位开始继续求和
        if curSum < 0:
            curSum = 0
    return maxSum

l = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
print(maxSubArray(l))

37 . new 和 init

class B(object):
    def fn(self):
        print 'B fn'
    def __init__(self):
        print "B INIT"


class A(object):
    def fn(self):
        print 'A fn'

    def __new__(cls,a):
            print "NEW", a
            if a>10:
                return super(A, cls).__new__(cls)
            return B()

    def __init__(self,a):
        print "INIT", a

a1 = A(5)
a1.fn()
a2=A(20)
a2.fn()
NEW 5
B INIT
B fn
NEW 20
INIT 20
A fn

38.getattr方法的应用

class A(object):
    def __init__(self,a,b):
        self.a1 = a
        self.b1 = b
        print 'init'
    def mydefault(self,*args):
        print 'default:' + str(args[0])
    def __getattr__(self,name):
        print "other fn:",name
        return self.mydefault

a1 = A(10,20)
a1.fn1(33)
a1.fn2('hello')
a1.fn3(10)

39.包管理
一个包里有三个模块,mod1.py, mod2.py, mod3.py,但使用from demopack import *导入模块时,如何保证只有mod1、mod3被导入了。

答案:增加init.py文件,并在文件中增加:

__all__ = ['mod1','mod3']

40.闭包
写一个函数,接收整数参数n,返回一个函数,函数的功能是把函数的参数和n相乘并把结果返回。

def mulby(num):
    def gn(val):
        return num * val

    return gn


zw = mulby(7)
print(zw(9));

你可能感兴趣的:(python相关面试题总结(二))