python开发工程师常见面试题

python中 == 和 is 的区别是什么?

python对象包含三个基本要素:id(身份标识)type(数据类型)value(值)
== 比较操作符,is 统一性操作符。
is和==对对象比较判断的内容不同: == 比较判断两个对象的value是否相等,is比较判断的是两个对象的id(唯一身份标识)是否相同。

深拷贝和浅拷贝

深拷贝指的是复制内容,重新开辟一块内存,浅拷贝指的是两个变量同时指向一个内存ID。

import copy
a = [1, 2, 3, 4, 5]
b = a  # 浅拷贝
c = copy.deepcopy(a)  # 深拷贝
d = a[:]  # 深拷贝
e = copy.copy(a)  # 当拷贝对象为可变类型时,为深拷贝,为不可变类型时为浅拷贝。

私有化和Proprety

对于类中定义的私有属性,可以通过定义get()和set()方法在类的外部获取和修改值。但是,在类的外部,程序对类中方法和属性的调用有所不同,方法的调用格式为:实例名.方法名(参数),属性的调用格式为:实例名.属性名。方法和属性的调用格式并不统一,为了可以使用属性的方式调用类中的方法,可以在定义方法前面加上@property装饰器。

class Test(object):
    def __init__(self):
        self.__age = 100

    @property
    def num(self):
        print("-------getter--------")
        return self.__age

    @num.setter
    def num(self, newage):
        print("-------setter--------")
        self.__age = newage
        
t = Test()  # 创建实例
t.num = 200  # 修改属性__num的值
print(t.num)  # 获取属性__num

python的生成器

生成器一边循环,一遍计算,占用内存小,在使用的时候取值,降低CPU和内存空间,提高效率。一般使用for循环取值。
生成器的2种创建方式:

  1. 把列表生成式的 [ ] 改成 (),就创建了一个generator
  2. 函数中包含yield关键字,这个函数及时一个generator,调用函数就创建了一个生成器(generator)对象。
# (1)把列表生成式的 [ ] 改成 (),就创建了一个generator;
L = [x **2 for x in range(5)]  # 列表生成式创建列表
g = (x **2 for x in range(5))  # 创建生成器

# (2)函数中包含yield关键字,这个函数及时一个generator,调用函数就创建了一个生成器(generator)对象。
def fib(max):  # 定义生成器生成斐波那契数列
    n, a, b = 0, 1, 1
    while n < max:
        yield b
        a, b = b, a + b
        n += 1

obj = fib(5)  # 通过函数调用创建生成器对象。
for i in obj:
    print(i)

生成器工作原理 :

  1. generator能够迭代的关键是它有一个next()方法,工作原理就是通过调用next()方法,直到捕获一个异常;
  2. 带有yield的生成器同样可以用next()方法调用生成器对象取值,next()有两种调用方式:t.next() 和 next(t)。推荐使用for循环来取值(每执行一次,取生成器里面的一个值)。
  3. yield相当于return返回一个值,并且记住这个返回的位置,下次迭代时,代码从yield的吓一跳语句开始执行。
  4. .send()和next()一样,都能让生成器往下一步走(下次遇到yield停),但是send()能传一个值,可以强行修改上一个yield表达式值。

python迭代器

迭代器提供了一种不依赖索引的迭代取值方式。首先明白迭代器和可迭代对象的概念:

  • 可迭代对象:内置有__iter__()方法的对象,都成为可迭代对象(str, list, tuple, dict, set)。
  • 迭代器对象*:内置有__next__()方法的对象,执行该方法可以不依赖索引值;有内置有__iter__()方法的对象,执行迭代器的__iter__()方法得到的是迭代器本身。

因此,迭代器一定是可迭代对象,可迭代对象不一定是迭代器。执行可迭代对象下的__iter__()方法,返回一个迭代器对象,再通过迭代器对象的__next__()方法取值。

python的for循环

for循环本质为迭代器循环,其工作原理如下 :

  1. 先调用in后面对象的__iter__()方法,将其编程一个迭代器对象;
  2. 调用next(迭代器),将得到的返回值赋值给变量;
  3. 循环往复,直到next(迭代器)抛出异常,for循环自动捕捉异常后结束循环。
    带有else的for循环:当for 循环正常结束时,会执行else里面的语句;当被break中断时,不执行else里面的语句。
# 例如查找列表中是否有3的倍数,没有的话打印“没有3的倍数”,有则什么都不打印
# 通常方法需要定义一个布尔型的变量,如下代码
a = [1,2,3,4,5]
has_value = False
for value in a:
    if value % 3 == 0:
        has_value = True
        break
if not has_value:
    print("没有3的倍数")

# 上述代码可以实现功能,但是还有一种更加优雅的方式实现,避免了定义布尔型变量 
a = [1,2,3,4,5]
for value in a:
    if value % 3 == 0:
        break
else:
    print('没有3的倍数')

闭包

一个函数定义在另一个函数内,且 使用到了外部函数的参数,外部函数返回值为内部函数的函数名,这样的整个代码块称之为闭包。当外部函数参数确定时,内部函数参数可以反复调用。
闭包避免了使用全局变量,此外 ,闭包允许将函数与其所操作的数据关联起来。一般来说,当对象中只有一个方法时,使用闭包是更好的选择。

# 定义一个闭包
def adder(x):
    def wrapper(y):
        return x + y
    return wrapper

adder3 = adder(3)
b = adder3(4)  # b的值为7
c = adder3(6)  # c的值为9,此步解释了当外部参数x不变时,内部函数可以反复调用

python装饰器

装饰器的本质是把原来的函数装饰成新的函数,并且返回这个函数本身的高阶函数(一个函数作为参数传递给另一个函数,或者一个函数的返回值为另一个函数,满足其一则为高阶函数)。
以计算函数执行时间为例,介绍装饰器的使用。

  1. 装饰没有参数的函数
import time
import functools

def timer(func):  # 装饰器函数
    @functools.wraps(func)  # 显示为被装饰的函数的函数名
    def inner():  # 闭包函数
        st = time.time()
        func()
        print(time.time() - st)
    return inner

@timer
def func1():  # 需要计算执行时间的函数
    print('in func1')
    time.sleep(3)

if __name__ == '__main__':
    func1()
  1. 装饰带有参数的函数
import time
import functools


def timer(func):
    @functools.wraps(func)  # 显示为被装饰的函数的函数名
    def inner(*args, **kwargs):  # 闭包函数中输入形参,可以接收全部参数
        st = time.time()
        func(*args, **kwargs)  # 将参数传递给被装饰的函数
        print(time.time() - st)
    return inner

@timer
def func1(a, b, c):  # 需要计算执行时间的函数
    print('in func1')
    print('a = {}, b = {}, c = {}'.format(a, b, c))
    time.sleep(1)

if __name__ == '__main__':
    func1(12, 2113, 324)
  1. 装饰带有返回值的函数
import time
import functools


def timer(func):
    @functools.wraps(func)  # 显示为被装饰的函数的函数名
    def inner(a, b, c):
        st = time.time()
        ret = func(a, b, c)  # 通过ret接收返回值
        print(time.time() - st)
        return ret  # 将返回值返回
    return inner

@timer
def func1(a, b, c):  # 需要计算执行时间的函数
    print('in func1')
    time.sleep(1)
    return True

if __name__ == '__main__':
    a = func1()
    print(a)
  1. 通用装饰器(有参有返回值)
import time
import functools

def timer(func):
    @functools.wraps(func)  # 显示为被装饰的函数的函数名
    def inner(*args, **kwargs):
        st = time.time()
        ret = func(*args, **kwargs)
        print(time.time() - st)
        return ret
    return inner

@timer
def func1(a, b, c):  # 需要计算执行时间的函数
    print('in func1')
    print('a = {}, b = {}, c = {}'.format(a, b, c))
    time.sleep(1)
    return a + b + c

if __name__ == '__main__':
    a = func1(12, 2113, 324)
    print(a)

python内置装饰器有staticmethod, classmethod, property。

pyhton实例方法,类方法,静态方法

类对象:将具有相似属性和方法的对象总结抽象为类对象,可以定义相似的属性和方法,不同实例对象去引用类对象的属性和方法,减少代码的重复率 。
实例对象:又称实例化对象,是通过类对象实例化出来的实例
实例方法:第一个参数必须是实例对象(self,可以传递类的属性和方法),只能由实例对象调用
类方法:使用装饰器@classmethod装饰,第一个参数必须是当前类对象(cls,传递类的属性和方法,不能传递实例的属性和方法)。功能:将类本身作为对象进行操作的方法。
静态方法:使用装饰器 @staticmethod装饰,参数随意(没有self和cls参数),方法体中不能使用类或市里的任何属性和方法。实例对象和类对象都可以调用。功能:主要用来 存放逻辑性代码,逻辑上属于类,但是和类 本身没有关系 ,可以理解为静态方法试了独立的、单纯的函数,仅仅托管于某个类的名称空间中。

class Animal():
    __num = 0   # 类属性(已私有化,通过下面num方法访问),所有实例对象共有
    
    def __init__(self, name):
        self.__name = name  # 私有化实例属性

    def __new__(self, *args, **kargs):  # 重写__new__()方法,实现创建对象,__num自增1
        Animal.__add_num()
        return super(Animal, self).__new__(self)

    @classmethod
    def __add_num(cls):  # 类方法,可以通过"类名.方法名"调用
        cls.__num += 1

    @classmethod
    def print_hello(cls):
        print('hello, this is a classmethod!')

    @property
    def name(self):  # 实例方法
        return self.__name

    @property
    def num(self):  # 通过装饰器为__num提供访问方式
        return Animal.__num

    def jump(self):  # 实例方法
        print("I'm {}, i am jumping!")

    @staticmethod
    def add_ab(a, b):  # 静态方法,逻辑性代码,与类本身无关
        print(a + b)

if __name__ == '__main__':
    a = Animal('dog')  # 实例化对象a
    b = Animal('cat')  # 实例化对象b
    Animal.print_hello()  # 调用类方法
    print(a.num)
    print(b.num)
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值