Python面试

时间:2019-09-17
本文章向大家介绍Python面试,主要包括Python面试使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

1.args和kwargs是什么意思?

答:args表示可变参数(variadic arguments),它允许你传入0个或任意个无名参数,这些参数在函数调用时自动组装为一个tuple; **kwargs表示关键字参数(keyword arguments),它允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict。同时使用*args和**kwargs的时候,必须保证*args在**kwargs之前。

扩展阅读:

https://blog.csdn.net/mbugatti/article/details/53884455

2.python里面如何拷贝一个对象?

答:

(1) 赋值(=),就是创建了对象的一个新的引用,修改其中任意一个变量都会影响到另一个;

(2)浅拷贝(copy.copy()),创建一个新的对象,但它包含的是对原始对象中包含项的引用(如果用引用的方式修改其中一个对象,另一个也会被改变);{1,完全切片方法;2,工厂函数,如list();3,copy模块的copy()函数}

(3)深拷贝(copy.deepcopy()),创建一个新的对象,并且递归的复制它所包含的对象(修改其中一个,另一个不会改变)

注意:并不是所有的对象都可以拷贝

扩展阅读:

http://www.cnblogs.com/wilber2013/p/4645353.html

3.简要描述python的垃圾回收机制

答:python中的垃圾回收是以引用计数为主,标记-清除和分代收集为辅。

引用计数:python在内存中存储每个对象的引用计数,如果计数变成0,该对象就会消失,分配给该对象的内存就会释放出来。

标记-清除:一些容器对象,比如说list、dict、tuple、instance等可能会出现引用循环,对于这些循环,垃圾回收器会定时回收这些循环(对象之间通过引用(指针)连在一起,构成一个有向图,对象构成这个有向图的节点,而引用关系构成这个有向图的边)。

分代收集:python把内存根据对象存活时间划分为三代,对象创建之后,垃圾回收器会分配它们所属的代。每个对象都会被分配一个代,而被分配更年轻的代是被优先处理的,因此越晚创建的对象越容易被回收。

扩展阅读:

https://www.jianshu.com/p/1e375fb40506

4.什么是lambda函数?它有什么好处?

答:lambda表达式,通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。

Python允许你定义一种单行的小函数。定义lambda函数的形式如下(lambda参数:表达式)lambda函数默认返回表达式的值。你也可以将其赋值给一个变量。lambda函数可以接受任意个参数,包括可选参数,但是表达式只有一个。

扩展阅读:

https://www.zhihu.com/question/20125256

5.python如何实现单例模式?

答:单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个单例而且该单例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,单例模式是最好的解决方案。

new()在__init__()之前被调用,用于生成实例对象。利用这个方法和累的属性的特点可以实现设计模式的单例模式。单例模式是指创建唯一对象,单例模式设计的类只能实例。

1.使用__new__方法

class Singleton(object):
  def __new__(cls, *args, **kw):
      if not hasattr(cls, '_instance'):
          orig = super(Singleton, cls)
          cls._instance = orig.__new__(cls, *args, **kw)
      return cls._instance

class MyClass(Singleton):
  a = 1

2.共享属性

class Borg(object):
  _state = {}
  def __new__(cls, *args, **kw):
      ob = super(Borg, cls).__new__(cls, *args, **kw)
      ob.__dict__ = cls._state
      return ob

class MyClass2(Borg):
  a = 1

3.装饰器版本

def singleton(cls, *args, **kw):
  instances = {}
  def getinstance():
      if cls not in instances:
          instances[cls] = cls(*args, **kw)
      return instances[cls]
  return getinstance

@singleton
class MyClass:
...

4.import方法

class My_Singleton(object):
  def foo(self):
      pass

my_singleton = My_Singleton()

# to use
from mysingleton import my_singleton

my_singleton.foo()

扩展阅读:

https://blog.csdn.net/sirodeng/article/details/17426543

6.python自省

答:自省就是面向对象的语言所写的程序在运行时,所能知道对象的类型,简单一句就是运行时能够获得对象的类型,比如type(),dir(),getattr(),hasattr(),isinstance().

a = [1,2,3]
b = {'a':1,'b':2,'c':3}
c = True
print type(a),type(b),type(c) # <type 'list'> <type 'dict'> <type 'bool'>
print isinstance(a,list)  # True

扩展阅读:

https://kb.cnblogs.com/page/87128/

7.谈一谈python的装饰器

答:装饰器本质上是一个python函数,它可以让其他函数在不作任何变动的情况下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景。比如:插入日志、性能测试,事务处理、缓存、权限验证等。有了装饰器我们就可以抽离出大量的与函数功能无关的雷同代码进行重用。

扩展阅读:https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000

8.什么是鸭子类型?

答:在鸭子类型中,关注的不是对象的类型本身,而是他如何使用的。例如,在不适用鸭子类型的语言中,我们可以编写一个函数,它接受一个类型为鸭的对象,并调用它的走和叫方法。在使用鸭子类型的语言中,这样的一个函数可以接受一个任意类型的对象,并调用它的走和叫方法。

class duck():
  def walk(self):
      print('I am duck,I can walk...')
  def swim(self):
      print('I am duck,I can swim...')
  def call(self):
      print('I am duck,I can call...')

duck1=duck()
duck1.walk()
    # I am duck,I can walk...
duck1.call()      # I am duck,I can call...

扩展阅读:

https://blog.csdn.net/handsomekang/article/details/40270009

9.@classmethod和@staticmethod

答:@classmethod修饰符对应的函数不需要实例化,不需要self参数,第一个参数需要是表示自身类的cls参数,cls参数可以用来调用类的属性,类的方法,实例化对象等。@staticmethod返回函数的静态方法,该方法不强制要求传递参数,如下声明一个静态方法:

Class C(object):

@staticmethod

Def f(arg1, arg2,…):

以上实例声明了静态方法f,类可以不用实例化就可以调用该方法C.f(),也可以实例化后调用C().f()。

扩展阅读:

https://zhuanlan.zhihu.com/p/28010894

10.谈一谈python中的元类

答:一般来说,我们都是在代码里定义类,用定义的类来创建实例。而使用元类,步骤又是同,定义元类,用元类创建类,再使用创建出来的类来创建实例。元类的主要目的就是为了当创建类时能够自动地改变类。

扩展阅读:

https://blog.csdn.net/wenyu826/article/details/66972933

1.台阶问题/斐波那契

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少中跳法:

fib = lambda n: n if n <= 2 else fib(n - 1) + fib(n - 2)

第二种方法:

def memo(func):
   cache = {}
   def wrap(*args):
       if args not in cache:
           cache[args] = func(*args)
       return cache[args]
   return wrap


@memo
def fib(i):
   if i < 2:
       return 1
   return fib(i-1) + fib(i-2)

第三种方法:

def fib(n):
   a, b = 0, 1
   for _ in range(n):
       a, b = b, a + b
   return b

2.去除列表中的重复元素

用集合

list(set(l))

用字典

l1 = ['b','c','d','b','c','a','a']
l2 = {}.fromkeys(l1).keys()
print (l2)

列表推导式

l1 = ['b','c','d','b','c','a','a']
l2 = []
[l2.append(i) for i in l1 if not i in l2]

3.合并两个有序列表

尾递归

def _recursion_merge_sort2(l1, l2, tmp):
   if len(l1) == 0 or len(l2) == 0:
       tmp.extend(l1)
       tmp.extend(l2)
       return tmp
   else:
       if l1[0] < l2[0]:
           tmp.append(l1[0])
           del l1[0]
       else:
           tmp.append(l2[0])
           del l2[0]
       return _recursion_merge_sort2(l1, l2, tmp)

def recursion_merge_sort2(l1, l2):
   return _recursion_merge_sort2(l1, l2, [])

循环算法

思路:

定义一个新的空列表

比较两个列表的首个元素

小的就插入到新列表里

把已经插入新列表的元素从旧列表删除

直到两个旧列表有一个为空

再把旧列表加到新列表后面

def loop_merge_sort(l1, l2):
   tmp = []
   while len(l1) > 0 and len(l2) > 0:
       if l1[0] < l2[0]:
           tmp.append(l1[0])
           del l1[0]
       else:
           tmp.append(l2[0])
           del l2[0]
   tmp.extend(l1)
   tmp.extend(l2)
   return tmp

pop弹出

a = [1,2,3,7]
b = [3,4,5]

def merge_sortedlist(a,b):
   c = []
   while a and b:
       if a[0] >= b[0]:
           c.append(b.pop(0))
       else:
           c.append(a.pop(0))
   while a:
       c.append(a.pop(0))
   while b:
       c.append(b.pop(0))
   return c
print (merge_sortedlist(a,b))

4.二分查找

#coding:utf-8
def binary_search(list,item):
   low = 0
   high = len(list)-1
   while low<=high:
       mid = int((low+high)/2)
       guess = list[mid]
       if guess>item:
           high = mid-1
       elif guess<item:
           low = mid+1
       else:
           return mid
   return None
mylist = [1,3,5,7,9]
print (binary_search(mylist,3))

参考: http://blog.csdn.net/u013205877/article/details/76411718

5.快排

#coding:utf-8
def quicksort(list):
   if len(list)<2:
       return list
   else:
       midpivot = list[0]
       lessbeforemidpivot = [i for i in list[1:] if i<=midpivot]
       biggerafterpivot = [i for i in list[1:] if i > midpivot]
       finallylist = quicksort(lessbeforemidpivot)+[midpivot]+quicksort(biggerafterpivot)
       return finallylist

print (quicksort([2,4,6,7,1,2,5]))

参考:https://blog.csdn.net/mrlevo520/article/details/77829204

6.使用python实现单例模式

方法一:可以使用__new__方法

在__new__方法中把类实例绑定到类变量_instance上,如果cls._instance为None表示该类还没有实例化过,实例化该类并返回。如果cls_instance不为None表示该类已实例化,直接返回cls_instance

class SingleTon(object):
   def __new__(cls,*args,**kwargs):
       if not hasattr(cls,'_instance'):
           cls._instance = object.__new__(cls,*args,**kwargs)
       return cls._instance
class TestClass(SingleTon):
   a = 1

test1 = TestClass()
test2 = TestClass()
print (test1.a,test2.a)

test1.a=2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法二:使用装饰器,建立过实例的就放到instances里面,下次建立的时候先检查里面有没有

def SingleTon(cls,*args,**kwargs):
   instances = {}
   print (instances)
   def _singleton():
       if cls not in instances:
           instances[cls] = cls(*args,**kwargs)
       print (instances)
       return instances[cls]
   return _singleton

@SingleTon
class LastClass(object):
   a = 1
test1 = LastClass()
print (test1.a)
test2 = LastClass()
print (test2.a)

方法三:使用__metaclass__(元类)关于元类看看这个吧:http://blog.jobbole.com/21351/

class SignalTon(type):
   def __init__(cls,name,bases,dict):
       super(SignalTon, cls).__init__(name,bases,dict)
       cls._instance = None

   def __call__(cls, *args, **kwargs):
       if cls._instance is None:
           cls._instance = super(SignalTon,cls).__call__(*args,**kwargs)
       return cls._instance

class TestClass(object):
   __metaclass__ = SignalTon

test1 = TestClass()
test2 = TestClass()

test1.a = 2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法四:共享属性

所谓单例就是所有的引用(实例,对象)拥有相同的属性和方法,同一个类的实例天生都会有相同的方法,那我们只需要保证同一个类所产生的实例都具有相同的属性。所有实例共享属性最简单直接的方法就是共享__dict__属性指向。

class SingleTon(object):
   _state = {}
   def __new__(cls, *args, **kwargs):
       obj = object.__new__(cls,*args,**kwargs)
       obj.__dict__ = cls._state
       return obj

class TestClass(SingleTon):
   a = 1

test1 = TestClass()
test2 = TestClass()
print (test1.a,test2.a)
test1.a = 2
print (test1.a,test2.a)
print (id(test1),id(test2))

方法五:使用同一个模版,写在mysingleton.py中

class My_Singleton(object):
   def foo(self):
       pass

my_singleton = My_Singleton()

#写在要使用这个实例的py文件里面,在不同的引用的地方都引用相同的实例,以此实现单例模式
from mysingleton import my_singleton
my_singleton.foo()

7.前中后序遍历

深度遍历改变顺序就好了

#coding:utf-8
#二叉树的遍历
#简单的二叉树节点类
class Node(object):
   def __init__(self,value,left,right):
       self.value = value
       self.left = left
       self.right = right

#中序遍历:遍历左子树,访问当前节点,遍历右子树

def mid_travelsal(root):
   if root.left is None:
       mid_travelsal(root.left)
   #访问当前节点
   print(root.value)
   if root.right is not None:
       mid_travelsal(root.right)

#前序遍历:访问当前节点,遍历左子树,遍历右子树

def pre_travelsal(root):
   print (root.value)
   if root.left is not None:
       pre_travelsal(root.left)
   if root.right is not None:
       pre_travelsal(root.right)

#后续遍历:遍历左子树,遍历右子树,访问当前节点

def post_trvelsal(root):
   if root.left is not None:
       post_trvelsal(root.left)
   if root.right is not None:
       post_trvelsal(root.right)
   print (root.value)

8.super函数的原理

#阅读下面的代码,它的输出结果是什么?
class A(object):
 def __init__(self):
  print ("enter A")
  super(A, self).__init__()  # new
  print ("leave A")

class B(object):
 def __init__(self):
  print ("enter B")
  super(B, self).__init__()  # new
  print ("leave B")

class C(A):
 def __init__(self):
  print ("enter C")
  super(C, self).__init__()
  print ("leave C")

class D(A):
 def __init__(self):
  print ("enter D")
  super(D, self).__init__()
  print ("leave D")
class E(B, C):
 def __init__(self):
  print ("enter E")
  super(E, self).__init__()  # change
  print ("leave E")

class F(E, D):
 def __init__(self):
  print ("enter F")
  super(F, self).__init__()  # change
  print ("leave F")

#输出

enter F
enter E
enter B
enter C
enter D
enter A
leave A
leave D
leave C
leave B
leave E
leave F

参考:http://www.cnblogs.com/lovemo1314/archive/2011/05/03/2035005.html

原文地址:https://www.cnblogs.com/kolane/p/11537517.html