python 常见面试题

  • 1. 装饰器(给函数增加功能)
# 多个装饰器的装饰过程就是:离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程
​
def test_a(func):
     def test_b():
         return func
     return test
 
@test
def func():
     pass

# @类装饰器名:等价于“函数引用 = 类名(函数引用)”,所以需要提供一个__init__方法,并多增加一个fn参数。
​
# 在__call__方法里进行对fn函数的装饰,可以添加额外的功能。
class 类装饰器名(obj):
  def __init__(self, 引用):
      self.func = 原函数引用
  def __call__:
      # 扩展方法
      self.func(*var, **kwvar) # 执行原函数
      # 扩展方法
  • 2. 上下文管理器(执行过程是先执行魔法方法enter, 然后执行with内的函数语句,最后执行exit魔法方法)
# 上下文管理器

# 使用with 可以使代码更简洁 
with open('test.txt', 'w') as f:
    f.write('Python')

# 上下文管理器的执行过程
# 自定义一个上下文管理器,模拟with文件操作
class MyOpen(object):
    def __init__(self,path,mode):
        # 记录要操作的文件路径和模式
        self.__path = path
        self.__mode = mode
 
    def __enter__(self):
        print('代码执行到了__enter__......')
        # 打开文件
        self.__handle = open(self.__path,self.__mode)
        # 返回打开的文件对象引用, 用来给  as 后的变量f赋值
        return self.__handle
 
    # 退出方法中,用来实现善后处理工作
    def __exit__(self, exc_type, exc_val, exc_tb):
        print('代码执行到了__exit__......')      
        self.__handle.close()
 
# a+ 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。
with MyOpen('test.txt','a+') as f:
    # 创建写入文件
    f.write("Hello Python!!!")
    print("文件写入成功")
  • 3. 进程锁

场景描述,多个请求过来,有一个表字段递增,所以每次仅允许同时处理一个请求,所以需要进程锁,来释放和保护进程。

# Python守护进程、进程互斥锁、进程间通信ICP(Queue队列)、生产者消费者模型
# 上面知识点会另起一片blog介绍
from multiprocessing import Process, Lock
 
def f(l, i):
    l.acquire()    #锁住进程
    try:
        print('hello world', i)
    finally:
        l.release()    #释放锁
 
if __name__ == '__main__':
    lock = Lock()
    for num in range(10):
        Process(target=f, args=(lock, num)).start()
  • 4. 排序算法
# 冒泡排序
# 冒泡排序时间复杂度On2/先假设a[0]最小,遍历后面元素,有小的则替换,依次确定a[2]~a[n]的数据
def bubble_sort(arr):
    for i in range(1, len(arr)):
        for j in range(0, len(arr)-i):
            if arr[j] > arr[j+1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
    return arr



# 快速排序:
# 利用空间换时间,假设a[0]最小,a[n]最大,一直到确定所有元素位置
def quick(li, left, right):
    if left < right:  # 如果左索引<右索引
        mid = part(li, left, right)  # 调用part进行分区 返回一个索引赋给mid
        quick(li, left, mid - 1)  # 递归调用quick 直到left=mid-1
        quick(li, mid + 1, right)  # 递归调用quick 直到mid+1=right


li = list(range(1000))

quick(li, 0, len(li) - 1)
print(li)
  • 5. 使用python创建一个栈
# 栈 先进后出。
class Stack(obj): #构造函数
    def __init__(self):
        self.values = []
    
    def push(self, value): # 新数据     
        self.values.append(value)
​
    def pop(self):  # 抛出(返回)栈鼎数据
        return self.values.pop()
​
    def is_empty(self): #空栈测试,返回布尔
        return self.size() == 0
​
    def size(self): # 返回栈内数目
        return len(self.values)
​
    def peak(self): # 返回栈鼎数据,但不删除
        return self.values[self.size()-1]

 

  • 6. yield
迭代器:yield 的好处是迭代能力,比起用类的实例保存状态来计算下一个 next() 的值要简洁的多.
而且对象的保存,不会执行任何函数代码,直到对其调用next()方法才开始执行。
​
return返回值,在第一次调用函数,yield返回迭代对象;
  • 7. 判断两个字符串是不是换位字符串
# # 判断两个字符串是不是换位字符串
# 将存在字符和数量存储到字典中
# 判断字典是否相等
def test(test_str):
    c = []
    d = {}
    for i in range(0, len(test_str)):
        if a[i - 1] not in c:
            c.append(i)
            d[test_str[i-1]] = 1
        else:
            d[test_str[i-1]] += 1
    return d
​
if __name__ == '__main__':
    a = "aaaabbc"
    b = "abcbaaa"
​
    hash_str1 = test(a)
    hash_str2 = test(b)
    print(hash_str1,hash_str2)
    if hash_str1 == hash_str2:
        print('True')
    else:
        print('False')
  • 8. 匿名函数
$ sum = lambda i,j:i+j

$ print(sum(22,33))

$ 55

 

  • 9.单例模式

确保某一个类只有一个实例,而且自行实例化并向实例化并向整个系统提供这个实例,这个称为单例类,单例模式是一种对象创建型模型。

# 实例化一个单例
class Singleton(object):
    __instance = None
    def __new__(cls, age, name):
        #如果类属性__instance的值为None,
        #那么就创建一个对象,并且赋值为这个对象的引用,保证下次调用这个方法时
        #能够知道之前已经创建过对象了,这样就保证了只有1个对象
        if not cls.__instance:
            cls.__instance = object.__new__(cls)
        return cls.__instance
a = Singleton(18, "dongGe")
b = Singleton(8, "dongGe")
print(id(a)) print(id(b))
a.age = 19 #给a指向的对象添加一个属性 
print(b.age)#获取b指向的对象的age属性

 

  • 10.python 的内存管理及垃圾回收
import sys
sys.getsizeof("")        # 49
sys.getsizeof([])        # 64
sys.getsizeof(())        # 48
sys.getsizeof(set())     # 224
sys.getsizeof(dict())    # 240

# 作为参照
sys.getsizeof(1)         # 28
sys.getsizeof(True)      # 28

sys.getsizeof([1,2,3])   # 88
[1,2,3].clear()          # 清空后64,即[]
sys.getsizeof({1,2,3})   # 224
{1,2,3}.clear()          # 清空后224,即set()
sys.getsizeof({'a':1,'b':2,'c':3})  # 240
{'a':1,'b':2,'c':3}.clear()  # 清空后72{},即dict()

见 这里 ? https://blog.csdn.net/zzy_zatan/article/details/100018480

  • 11. GIL锁
全局解释器锁?
    对于有io操作的线程,当一个线程在做io操作的时候,
因为io操作不需要cpu,所以,这个时候,python会释放python全局锁,
这样其他需要运行的线程就会使用该锁。 
对于cpu密集型的线程,比如一个线程可能一直需要使用cpu做计算,
那么python中会有一个执行指令的计数器,当一个线程执行了一定数量的指令时,
该线程就会停止执行并让出当前的锁,这样其他的线程就可以执行代码了。 
    由上面可知,至少有两种情况python会做线程切换,一是一但有IO操作时,
会有线程切换,二是当一个线程连续执行了一定数量的指令时,会出现线程切换。
当然此处的线程切换不一定就一定会切换到其他线程执行,因为如果当前线程
优先级比较高的话,可能在让出锁以后,又继续获得锁,并优先执行。
  • 12. if _name__ =  "__main__"的理解
##存为if__name.py

def main():##必须定义为main()不能为其他字符表示。
    print("hello world %s"%__name__)
if __name__=='__main__':##目的对于调用该文件的其他文件来说确保,该文件的方法
    ##只执行一次。这样就是本身也可以执行,其他文件调用它而不至于执行两次。
    main()##在改文件内if会满足,而其他文件调用时,不会满足if。
    
##存为main__name.py
import if__name

if__name.main()##得到
##hello world if__name,说明__name__为'if__name',从而不会执行被引用文件的if判断下的语句。目的避免执行被引用文件两次

  • 13.深拷贝和浅拷贝
a = 1 
b = a #  赋值是浅拷贝

# 对于list、dict、set等数据而言
a = [11,22,33]
import copy

c = copy.copy(a) #  浅拷贝:值不变,内存地址改变
d = copy.deepcopy(a) #  深拷贝:值不变,内存地址改变

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值