python面试集合


文章目录

  • python面试集合
  • 前言
  • 一、python基础(难度:⭐️)
  • 二、Python进阶
  • 1.装饰器(难度⭐️⭐️⭐️⭐️)



前言

这是一篇面向python的面试精华解析,从基础到高级都有涉及


一、python基础(难度:⭐️)

  1. python的对象类型
    不可变(immutable)对象类型:int,float,decimal,complex,bool,str,tuple,range,frozenset,bytes
    可变(mutable)对象类型:list,dict,set,bytearray,user-defined,classes (unless specifically made immutable)
  2. 变量
    Python中的变量都是指针。因为变量是指针,所以所有的变量无类型限制,可以指向任意对象。指针的内存空间大小是与类型无关的,其内存空间只是保存了所指向数据的内存地址。
    Python 的所有变量其实都是指向内存中的对象的一个指针,所有的变量都是!

此外,对象还分两类:一类是可修改的,一类是不可修改的。可修改(mutable)的类型叫做值类型,不可修改(immutable)类型叫做引用类型。

  1. 对象
    对象=确定内存空间+存储在这块内存空间中的值。

Java中,对象是分配在堆上的,存储真正的数据,而引用是在栈中开辟的内存空间用于引用某一个对象(值类型的变量也是存储到栈上)。

  1. 值类型(不可变对象)
    在Python中,数值(整型,浮点型),布尔型,字符串,元组属于值类型,本身不允许被修改(不可变类型),数值的修改实际上是让变量指向了一个新的对象(新创建的对象),所以不会发生共享内存问题。 这种方式同Java的不可变对象(String)实现方式相同。原始对象被Python的GC回收。
  2. 引用类型(可变类型)
    在Python中,列表,集合,字典是引用类型,本身允许修改(可变类型)修改引用类型的值,因为地址一致,所以都会被修改。
    进行两次a = [1, 2, 3]操作,两次a引用的地址值是不同的,也就是说其实创建了两个不同的对象,这一点明显不同于不可变数据类型,所以对于可变数据类型来说,具有同样值的对象是不同的对象,即在内存中保存了多个同样值的对象,地址值不同。
    对a进行的操作不会改变a引用的地址值。值的变化并不会引起新建对象,即地址是不会变的,只是地址中的内容变化了或者地址得到了扩充。
    不可变的例外:不可变对象的“值” 不能改变,但它的组成对象是能做到改变的。
    主要原因是元组内保存的是变量(也就是内存地址)。所以当变量指向对象发生变化时,如果导致变量发生变化(即不可变类型),此时元组保证该不可变类型不能修改。而如果当变量指向对象发生变化时,如果不会导致变量发生变化(即可变类型),此时元组中存储的该可变类型可以修改(因为变量本身并无变化)。
  3. 总结
    python中的不可变数据类型不允许变量的值发生变化,如果改变了变量的值,相当于是新建了一个对象,而对于相同的值的对象,在内存中则只有一个对象,内部会有一个引用计数来记录有多少个变量引用这个对象;

可变数据类型允许变量的值发生变化,即如果对变量进行append、+=等这种操作后,只是改变了变量的值,而不会新建一个对象,变量引用的对象的地址也不会变化,不过对于相同的值的不同对象,在内存中则会存在不同的对象,即每个对象都有自己的地址,相当于内存中对于同值的对象保存了多份,这里不存在引用计数,是实实在在的对象。
7. 参数传递
而Python所有的都是对象,都是引用,所以所谓的值类型都是不可变类型。所以Python中的参数传递都是传递引用,也就是传递的是内存地址。只不过对于不可变类型,传递引用和传递值没什么区别。而对于可变类型,传递引用是真的传递内存的地址。
8. python只允许引用传递是为方便内存管理,因为python使用的内存回收机制是计数器回收。
9. 值传递: 表示直接传递变量的值,把传递过来的变量的值复制到形参中,这样在函数内部的操作不会影响到外部的变量。

引用传递: 把引用理解为变量(标识符)与数据之间的引用关系,标识符通过引用指向某块内存地址。而引用传递,传递过来的就是这个关系,当你修改内容的时候,就是修改这个标识符所指向的内存地址中的内容,因为外部也是指向这个内存中的内容的,所以,在函数内部修改就会影响函数外部的内容。

另外:列表,字典,集合是容器类型,嵌套引用。

二、Python进阶

1.装饰器(难度⭐️⭐️⭐️⭐️)

使用语法糖
代码如下(不带参数的装饰器):

def logger(func):
    def wrapper(*args,**kwargs):
        print("hello,i will run {} function:".format(func.__name__))
        func(*args,**kwargs)
    return wrapper

@logger
def add(a,b):
    print('{} + {} = {}'.format(a,b,a + b))
add(1,2)

代码如下(带参数的装饰器):

def small_talk(language):
    def wrappe(func):
        def defin(*args,**kwargs):
            print("{}".format(func.__name__))
            if language == 'china':
                print("你好")
            elif language == 'English':
                print('hello')
            else:
                print("I dont know")
            func(*args,**kwargs)
        return defin
    return wrappe
@small_talk("china")
def wang():
    print('说')
@small_talk("English")
def dawei():
    print('say')
wang()
dawei()

代码如下(不带参的类装饰器):
注:基于类的装饰器必须要实现__init____call__两个内置方法
__init__ :接收被装饰函数 __call__ :实现装饰逻辑。

class logger(object):
    def __init__(self,func):
        self.func = func
    def __call__(self, *args, **kwargs):
        print("[INFO]: the function {func}() is running..." \
              .format(func=self.func.__name__))
        return self.func( *args, **kwargs)
@logger
def say(sth):
    print('say {}'.format(sth))

代码如下(带参的类装饰器):
注:__init__ :现在接收的是传入参数而不是被修饰函数 __call__ :实现装饰逻辑。

class logger(object):
    def __init__(self,level = "INFO"):
        self.level = level
    def  __call__(self, func):
        def wrapper(*args,**kwargs):
            print("[{level}]:the fuction {func}() is running"\
                  .format(level = self.level,func = func.__name__))
            func(*args,**kwargs)
        return wrapper

@logger(level="WARing")
def report(info):
    print("{}".format(info))
report("wrong")

代码如下(内置装饰器:property):
用@property装饰过的函数,会将一个函数定义成一个属性,属性的值就是该函数return的内容。

class Student(object):
    def __init__(self, name):
        self.name = name
        self.name = None
    def set_age(self, age):
        if not isinstance(age, int):
            raise ValueError('输入不合法:年龄必须为数值!')
        if not 0 < age < 100:
            raise ValueError('输入不合法:年龄范围必须0-100')
        self._age=age

    def get_age(self):
        return self._age

    def del_age(self):
        self._age = None
xiaoming = Student("小明")
xiaoming.set_age(20)
xiaoming.del_age()