测试工程师python编程面试考点笔记

1、可变参数类型

*args 元组
**kwargs 字典

def fun(a, *args, **kwargs):
    print(type(a))
    print(type(args))
    print(type(kwargs))
    print(a, args, kwargs)

fun('a', 'a', 'a')
输出:
<class 'str'>
<class 'tuple'>
<class 'dict'>
a ('a', 'a') {}

2、return于yield的区别


return会阻断循环
yield并不阻断整个循环,把每次运行结果返回

def fun01():
    for i in range(1, 5):
        return i  # return阻断了循环

def fun02():
    for i in range(1, 5):
        yield i   # yield并不阻断整个循环,把每次运行结果返回

print(fun01())
print(fun02())
print(type(fun02()))
for i in fun02():
    print(i)

输出结果:

1
<generator object fun02 at 0x000002FE0ED060F8>
<class 'generator'>
1
2
3
4

3、类变量、实例变量、类对象、实例对象的区别


类变量和实例变量的区别:
(1)类变量不通过实例化后可直接打印输出,类变量存储在类的内存中。
(2)如果同时有类变量和实例变量,程序执行时,首先去找实例变量,如果实例变量不存在,就去执行类变量。
(3)类变量是所有对象共有,其中一个对象将它值改变,其他对象得到的就是改变后的结果;而实例变量则属对象私有,某一个对象将其值改变,不影响其他对象;

类对象和实例对象:
(1)类对象是将具有相似属性和方法的对象总结抽象为类对象,可以定义相似的一些属性和方法,不同的实例对象去引用类对象的属性和方法,能减少代码的重复率。
(2)实例对象又称实例化对象,不是抽象而是一类对象中具体的一例对象。

class Dog:     # 类对象
    x = 4
    y = 5
    def __init__(self, x, y):
        self.x = x
        self.y = y
        print("x= " + str(x))
        print("y= " + str(y))

    def add(self):
        return self.x + self.y

# 实例对象
d = Dog(1, 2)
d.z = 7   # 实例变量
print(d.z)
print(d.x)  # 实例变量
print(d.y)  # 实例变量
print(Dog.x)  # 类变量
print(Dog.add(d))  # 传入的参数是一个实例对象
print(d.add())

输出结果:

x= 1
y= 2
7
1
2
4
3
3

4、对象的深浅拷贝

不可变数据(3 个):一旦创建就不可以修改,Number(数字)、String(字符串)、Tuple(元组);
可变数据(3 个):List(列表)、Dictionary(字典)、Set(集合)。

(1)=赋值:数据完全共享
在内存中指向同一个对象,如果是可变数据类型,修改其中一个,另一个必定改变。如果是不可变数据类型,修改了其中一个另一个也不会改变

a1 = ('a', 'b', 'c')  # 不可变类型
a2 = ['a', 'b', 'c']  # 可变类型
b1 = a1  # 赋值:数据完全共享
b2 = a2
b2[1] = '2'
# 不可变数据类型,打印值和内存地址完全相同
print(a1)
print(b1)
print(id(a1))
print(id(b1))
# 可变数据类型,修改其中一个,另一个也跟着改变
print(a2)
print(b2)
print(id(a2))
print(id(b2))

输出结果:

('a', 'b', 'c')
('a', 'b', 'c')
2606032875024
2606032875024
['a', '2', 'c']
['a', '2', 'c']
2606034375560
2606034375560

(2)浅拷贝:数据半共享
赋值其数据独立内存存放,但是只拷贝成功第一层
如果是可变数据类型内存地址会不一样;如果是不可变数据类型,内存地址一样。

import copy

a1 = ('a', 'b', 'c')  # 不可变类型
a2 = ['a', 'b', [1, 2, 3]]  # 可变类型
b1 = copy.copy(a1)  # 浅拷贝:数据半拷贝(只成功拷贝第一层)
b2 = copy.copy(a2)
print(a2)
print(b2)
b2[1] = 'c'  # 第一层数据拷贝成功,a2未被修改
b2[2][0] = 0   # 第二层的数据并没有拷贝成功,地址指向的还是a2的第二层的内存地址,所以相当于‘等号赋值’,所以a2第二层数据也变成0
# 不可变数据类型,内存地址一样
print(a1)
print(b1)
print(id(a1))
print(id(b1))
# 可变数据类型,内存地址不一样
print(a2)
print(b2)
print(id(a2))
print(id(b2))

输出结果:

['a', 'b', [1, 2, 3]]
['a', 'b', [1, 2, 3]]
('a', 'b', 'c')
('a', 'b', 'c')
2182345584144
2182345584144
['a', 'b', [0, 2, 3]]
['a', 'c', [0, 2, 3]]
2182347084936
2182347086088

(3)深拷贝:数据完全不共享
复制其数据完完全全放独立的一个内存,完全拷贝,数据不共享;
但是如果是不可变数据类型,内存地址一样。

import copy

a1 = ('a', 'b', 'c')  # 不可变类型
a2 = ['a', 'b', [1, 2, 3]]  # 可变类型
b1 = copy.deepcopy(a1)  # 深拷贝:数据完全不共享
b2 = copy.deepcopy(a2)
b2[1] = 'c'  # 深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享,a2未被修改
b2[2][0] = 0   # 深拷贝就是完完全全复制了一份,且数据不会互相影响,因为内存不共享,a2未被修改
# 不可变数据类型,内存地址一样
print(a1)
print(b1)
print(id(a1))
print(id(b1))
# 可变数据类型,内存地址不一样
print(a2)
print(b2)
print(id(a2))
print(id(b2))

输出结果:

('a', 'b', 'c')
('a', 'b', 'c')
2942052527632
2942052527632
['a', 'b', [1, 2, 3]]
['a', 'c', [0, 2, 3]]
2939935118472
2939935119624

5、Python装饰器详解

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。

import time

def runtime(fun1):
    def get_time(*args, **kwargs):
        print(time.time())
        fun1(*args, **kwargs)
    return get_time

@runtime
def run(*args, a):
    print(*args)
    print(a)

run("123", a= "abc")

输出结果:

1585396559.5230289
123
abc

6、多种推导式的实现

问题:给定list例如:list1 = [1, 2, 3],一行代码实现生成一个新list里的元素为list1里元素的平方
(1)使用lambda表达式

list1 = [1, 2, 3]
result = list(map(lambda x: x*x, list1))
print(result)
输出结果:
[1, 4, 9]

(2)使用推导式(列表推导式)

list1 = [1, 2, 3]
list2 = [i*i for i in list1]
print(list2)
输出结果:
[1, 4, 9]

推导式拓展:
例如list1=[1, 2, 3]需要筛选大于1的数的平方,放入列表list2

list1 = [1, 2, 3]
list2 = [i*i for i in list1 if i > 1]
print(list2)
输出结果:[4, 9]

集合推导式:
给定集合list1 = {1, 2, 3}需要返回集合里数的立方给集合list2

list1 = {1, 2, 3}
list2 = {i**3 for i in list1}
print(list2)
输出结果:{8, 1, 27} # 集合时无序的

字典推导式用法:

my_dict = {"key1": 5, "key2": 10, "key3": 20}
# 取出字典里的所有key
keys = [key for key, value in my_dict.items()]
print(keys)
# 取出字典里的所有value
values = [value for key, value in my_dict.items()]
print(values)
# 将key和value颠倒组成字典my_dict1
my_dict1 = {value: key for key, value in my_dict.items()}
print(my_dict1)
# 只取key=“key1”的key和value组成新字典my_dict2
my_dict2 = {key: value for key, value in my_dict.items() if key == "key1"}
print(my_dict2)

输出结果:

['key1', 'key2', 'key3']
[5, 10, 20]
{5: 'key1', 10: 'key2', 20: 'key3'}
{'key1': 5}

7、排序算法


常见的排序算法:插入排序、希尔排序、直接排序、堆排序、冒泡排序、快速排序、归并排序、基数排序等
常问:冒泡排序和快速排序

复杂度:
时间复杂度:指算法在计算的过程中所需要的计算工作量
空间复杂度:指算法在计算过程中所需要的内存空间

常见的时间复杂度:
常数阶0(1),对数阶0(log2n),线性阶0(n),线性对数阶0(nlog2n),平方阶0(n^2), 立方阶0(n^3);随着问题的规模n,不断的增大,上述的时间复杂度就不断的增大,意味着算法的指向效率越低。

(1)冒泡排序的实现
相邻的两个数据进行比较,大的向下沉,最后一个元素是最大的;时间复杂度0(n^2)

def bubble_sort(listb):  # 冒泡排序
    count = len(listb)
    for i in range(0, count):
        for j in range(i+1, count):
            if listb[i] > listb[j]:
                # 使用python特有的方法,来进行两数交换
                listb[i], listb[j] = listb[j], listb[i]
    return listb

list1 = bubble_sort([2, 54, 36, 12, 78])
print(list1)
输出结果:[2, 12, 36, 54, 78]

(2)快速排序的实现
思想:递归
列表中取出第一个元素,作为标准;把比第一个元素销得都放在左侧,把比第一个元素大的都放在右侧;递归完成时就是排序结束的时候;
快排的时间复杂度0(nlog2n)

def quick_sort(listq):
    if listq == []:
        return []
    else:
        first = listq[0]
        # 推导式实现
        less = quick_sort([l for l in listq[1:] if l < first])  # 左侧筛选
        more = quick_sort([m for m in listq[1:] if m >= first])  # 右侧筛选
    	return less + [first] + more

list1 = quick_sort([12, 2, 35, 67, 5, 35, 60])
print(list1)
输出结果:[2, 5, 12, 35, 35, 60, 67]

8、python中的私有变量

Python中,变量名类似__x__的,以双下划线开头,并且以双下划线结尾的,是特殊变量,特殊变量是可以直接访问的(比如 doc, init__等),不是private变量,
所以,不能用__name
、__sex__这样的变量名定义私有变量。

(1)直接访问私有变量:
在这里插入图片描述
如上所示:
私有变量不能直接通过:Person.__name直接访问,而是必须在类内部通过方法返回私有变量;

(2)正确访问私有变量

class Person:
    __name = "张三" # 私有变量
    address = "北京"

print(dir(Person))  # 返回Person里面的一些方法和属性
print(Person._Person__name)  # 访问私有变量
print(Person.address)

输出结果:

['_Person__name', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'address']
张三
北京

如dir(Person)输出所示,内部的__name变量已经被Python解释器自动改成了_Person__name,所以,我们仍然可以通过 _Person__name 来访问__name私有变量。

9、python中的类的方法种类及区别

类的方法种类:
实例方法:实例可以操作的方法;可以操作实例变量;
类方法:类可以直接调用,可以操作类变量
静态方法:脱离了类而存在的,没有参数
私有方法:def __drink(self):格式
详细使用如代码:

class Person:
    name = "李四"
    def eat(self):  # 实例方法:实例可以操作的方法;可以操作实例变量;
        self.name = "张三"
        print("人需要吃饭")
        print("姓名:" + self.name)

    @classmethod   # 类方法 类可以直接调用,可以操作类变量
    def sleep(cls):
        print(cls.name + "是人需要睡觉")  # name调用类里的值“李四”

    @staticmethod  # 静态方法 脱离了类而存在的,没有参数
    def run():
        print("跑步")

    def __drink(self):  # 私有方法
        print("人需要喝水")

p = Person()
print(p.eat())  # 调用实例方法
Person.sleep()  # 调用类方法,类方法需要用类去调用
Person.run()  # 调用静态方法
p._Person__drink()  # 私有方法调用(不常用到)

输出数据:

人需要吃饭
姓名:张三
None
李四是人需要睡觉
跑步
人需要喝水

10、如何理解面对对象

面向对象是一直编程思想,是编程世界向现实世界的一种延伸,也就是说万物皆可描述;我们用编程语言也可以描述世界万物,把这种思想理解为面对对象。
类:它就是面对对象的一种表现形式。
大象放冰箱分几步?
打开冰箱 (冰箱的方法)
装进大象
关上冰箱 (冰箱的方法)
(1)函数和面向对象编程的区别
相同点:都是把程序进行封装、方便重复利用,提高效率。
不同点:函数重点是用于整体调用,一般用于一段不可更改的程序,仅仅是解决代码重用性的问题。而面向对象不仅解决代码重用性,还包括继承、多态等,使用上更加灵活。
(2)面对对象的特点
a、封装:把需要重用的函数或者功能封装,方便其他程序直接调用
如下代码,将人的一些行为封装到Person里面,然后可以调用这些eat、sleep、drink

class Person:
    def eat(self):
        print("人需要吃饭")

    def sleep(self):
        print("人需要睡觉")

    def drink(self):
        print("人需要喝水")

p = Person()
p.eat()

b、继承:子项继承父项的某些功能,在程序中表现某种联系
代码举例:

class Person:
    def eat(self):
        print("需要吃饭")

    def sleep(self):
        print("需要睡觉")

    def drink(self):
        print("需要喝水")

class Animal(Person):  # Animal继承person
    def run(self):
        print("会跑")

animal = Animal()
animal.eat()
输出结果:需要吃饭

c、多态:一个函数有多种表现形式,调用一个方法有多种形式,但是表现出的方法是不一样的。

class Person:
    def eat(self):
        print("需要吃饭")

    def drink(self):
        print("人需要喝水")

class Dog(Person):
    def drink(self):
        print("狗需要喝水")

p = Person()
p.drink()
d = Dog()
d.drink()
输出结果:
人需要喝水
狗需要喝水
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值