阶段考试(月考解释版)

阶段考试(月考)

【一】介绍

满分100分,90分及格

考试范围:

  • 1.Python基础
  • 2.数据类型
  • 3.流程控制
  • 4.文件处理
  • 5.函数
  • 6.面向对象

【二】基础题(40分)

1.定义一个变量有三个特性,分别为?(1分)

一个变量具有三个特性,分别是内存空间地址、数据类型和存储值。

  • 内存空间地址:
    • 内存空间地址是计算机内存中存储数据的位置标识。
    • 每个数据在内存中都有一个唯一的地址,通过这个地址可以找到并访问该数据。
  • 数据类型:
    • 变量必须具有一个明确的数据类型,用于指定变量可以存储的数据的种类和范围。
    • 常见的数据类型包括整数(如int)、浮点数(如float)、布尔值(如bool)和字符串(如string)。
    • 通过指定数据类型,程序可以在内存中为变量分配适当的空间,并对其进行正确的操作。
  • 存储值:
    • 变量用于存储特定类型的数据值。
    • 这些值可以是数字、文本、布尔值等,具体取决于变量的数据类型。
    • 在程序执行过程中,变量的值可以被改变和修改,以适应不同的需求和计算过程。

等号比较的是什么?(1分)

  • 等号比较的是变量或表达式的值。

    • 当我们使用等号进行比较时,实际上是在判断两个操作数的值是否相等。
  • 等号的比较操作只比较变量或表达式的值,而不是它们的类型。

    • 如果需要同时比较值和类型,可以使用恒等号(===)或类似的运算符,

is比较的是什么?(1分)

  • "is" 比较的是两个对象是否指向同一个内存地址,即是否为同一个对象。
  • 虽然 "is" 运算符比较的是对象的内存地址,但并不代表它比较的是对象的值。
    • 如果想要比较对象的值是否相等,应使用 "==" 运算符进行值的比较。

2.使用链式赋值的方式将10赋值给变量x、y、z(1分)

  • 可以使用链式赋值的方式将10赋值给变量x、y、z,代码如下:
x = y = z = 10
  • 在上述代码中,将数字10赋值给变量x,并将x同时赋值给变量y和z,实现了链式赋值。此时,x、y和z都被赋值为10。

  • 可以通过打印输出验证:

print(x)  # 输出 10
print(y)  # 输出 10
print(z)  # 输出 10
  • 这样就完成了将10赋值给变量x、y、z的操作。

3.有一个工资列表[3.1,2.1,4.3,2.2,1.3,9.3],请取出前两个月的工资,分别赋值给两个变量名,用一行代码实现(1分)

  • 可以使用切片操作符(:)来取出工资列表中的前两个月的工资,并将其分别赋值给两个变量名,代码如下:
salaries = [3.1, 2.1, 4.3, 2.2, 1.3, 9.3]
month1, month2 = salaries[:2]
  • 在上述代码中,通过salaries[:2]使用切片操作符(:),取出salaries列表中索引为和1的元素,即前两个月的工资,然后使用逗号分隔,将这两个元素赋值给变量month1month2

  • 可以通过打印输出验证:

print(month1)  # 输出 3.1
print(month2)  # 输出 2.1
  • 这样就用一行代码完成了将前两个月的工资赋值给两个变量名的操作。

4.可变的数据类型有哪些,不可变的数据类型有哪些(1分)

  • 可变的数据类型包括列表(list)和字典(dictionary)。
    • 列表是用于存储多个元素的有序集合,可以通过索引访问、修改、删除其中的元素,因此属于可变类型。
    • 字典是一种无序的键-值对集合,可以通过键来索引和修改其中的值,也属于可变类型。
  • 不可变的数据类型包括数字(int, float)、字符串(str)、元组(tuple)。
    • 数字是表示数值的数据类型,它们的值在创建之后不可更改。
    • 字符串是字符的有序序列,一旦创建,其内容不可变。
    • 元组是用于存储多个元素的有序容器,一旦创建后,元素的内容和顺序都不可变。
  • 总结:
    • 可变的数据类型:

      • 列表(list):

        • 可以通过添加、删除、修改元素来改变列表的值。
      • 字典(dictionary):

        • 可以通过添加、删除、修改键值对来改变字典的值。
      • 集合(set):

        • 可以通过添加、删除元素来改变集合的值。
      • 字节数组(bytearray):

        • 可以通过修改元素来改变字节数组的值。
    • 不可变的数据类型:

      • 数字类型(int、float、complex):

        • 数字类型的值不可修改。
      • 字符串(string):

        • 字符串的值不可修改。
      • 元组(tuple):

        • 元组的值不可修改。
      • 字节串(bytes):

        • 字节串的值不可修改。
      • range对象(range):

        • range对象的值不可修改。
      • 布尔类型(bool):

        • 布尔类型的值只有True和False两种,不可修改。
      • 空值类型(NoneType):

        • 空值类型的值只有None,不可修改。

5.容器类型有?序列类型有?(1分)

  • 容器类型是指能够包含其他对象的数据类型,常见的容器类型有列表(list)、元组(tuple)、集合(set)、字典(dictionary)等。

  • 序列类型是一种特殊的容器类型,它按照元素在容器中的位置进行存储和访问。

    • 序列类型包括字符串(str)、列表(list)、元组(tuple)。
    • 字符串是字符的有序序列,列表是有序的可变序列,元组是有序的不可变序列。
  • 总结:

    • 容器类型:
      • 列表(list):
        • 有序可变的容器,可以存储任意类型的数据。
      • 元组(tuple):
        • 有序不可变的容器,也可以存储任意类型的数据。
      • 字典(dictionary):
        • 无序的键值对集合,每个键值对之间是唯一的。
      • 集合(set):
        • 无序的唯一元素的集合。
    • 序列类型:
      • 字符串(string):
        • 由字符组成的有序序列,不可变。
      • 列表(list):
        • 上述提到的容器类型,也属于序列类型。
      • 元组(tuple):
        • 上述提到的容器类型,也属于序列类型。
      • 字节串(bytes):
        • 由字节组成的有序序列,不可变。
      • 字节数组(bytearray):
        • 由字节组成的有序序列,可变。
      • range对象(range):
        • 表示指定范围内的数字序列。

6.请说明python2与python3中的默认编码是什么?(1分)

  • 在Python 2中,默认编码是ASCII(American Standard Code for Information Interchange)编码。

    • ASCII编码只能表示128个字符,包括英文字母、数字和一些特殊字符,对于非英文字符的处理支持有限。
  • 而在Python 3中,默认编码则是UTF-8(Unicode Transformation Format-8)编码。

    • UTF-8编码是一种可变长度的Unicode编码方式,可以表示几乎所有的字符,包括世界上各国的文字、符号等。
  • 由于Python 2已经不再得到官方支持,建议在开发新项目时使用Python 3,并将源代码文件保存为UTF-8编码,以确保更好的跨平台和字符支持。

  • 所以总结:

    • Python 2的默认编码是ASCII编码;
    • Python 3的默认编码是UTF-8编码。

7.如何保证程序不出现乱码问题?(1分)

  • 要确保程序不出现乱码问题,可以采取以下几个措施:

    • 使用正确的字符编码:

      • 确保程序源代码文件的编码与程序中处理的数据的码一致。

      • 常用的编码包括UTF-8、GBK、ISO-8859-1等,在使用时应根据具体需求选择合适的编码。

    • 设置默认编码:

      • 在Python中,可以使用sys.setdefaultencoding()方法设置默认编码。

      • 但需要注意的是,从Python 3开始,默认已经移除了该方法,因为默认编码应该由操作系统环境决定。

    • 显式地进行编码和解码:

      • 在对字符串进行读取、写入、发送或打印等操作时,需要明确指定编码和解码方式,以保证数据流的正确传输和显示。
    • 使用Unicode进行内部处理:

      • 尽量在程序内部使用Unicode编码处理字符串,这样可以更好地支持各种字符集和国际化。
    • 注意文件的读写方式:

      • 在读取和写入文件时,可以使用带编码参数的文件打开函数,例如open(filename, 'r', encoding='utf-8'),以确保文件以正确的编码进行读写操作。
    • 针对特定情况进行异常处理:

      • 如果在程序中遇到无法解码或编码的字符,可以针对具体情况进行异常处理,例如跳过该字符、替换为特定字符或报错提示用户。

总的来说,保证程序不出现乱码问题需要在代码层面正确处理字符编码和解码操作,并注意使用合适的编码方式。

8.unicode,utf-8,gbk,ascii用个几个字节表示英文,用几个字节表示中文(0.5分)#-\*-coding:utf-8-\*- 的作用是什么?(0.5分)

  • Unicode是一种字符集,它为世界上几乎所有的字符提供了一个唯一的标识符,每个字符对应一个码位。
    • Unicode用32位(4字节)表示每个字符。
  • UTF-8是一种变长编码方式,它可以将Unicode中的字符编码为1至4个字节。
    • 对于英文字符,在UTF-8编码下占用1个字节;
    • 对于汉字和其他非英文字符,根据具体字符所在的范围和码位,可能占用2至4个字节。
    • 常见的中文字符通常需要3个字节表示
  • GBK是一种针对中文字符的字符编码方式
    • 它占用2个字节来表示一个汉字
    • 而英文字符占用1个字节。
  • ASCII是一种最早的字符编码标准
    • 它使用7位(1个字节)来表示128个常用字符。
  • # -*- coding:utf-8 -*- 这行代码是用来指定当前代码文件的字符编码方式为UTF-8。
    • 在Python中,这行代码通常放在脚本的开头或模块注释的下方,它用来告诉Python解释器如何正确地处理源代码中的字符。
    • 指定编码方式可以确保解释器正确地读取和解析源代码文件中的字符,并避免出现乱码以及与编码相关的错误。

9.在python3中的str是什么编码的,如何把python3中的str转成utf-8格式的bytes(1分)

  • 在Python 3中的str类型是以Unicode编码表示的,它不再依赖于特定的字符编码方式。
    • 这意味着Python 3中的str对象可以包含任意的Unicode字符。
  • 要将Python 3中的str转换为UTF-8格式的bytes
    • 可以使用字符串的encode方法,并指定编码方式为UTF-8。示例如下:
text = "你好,世界!"
utf8_bytes = text.encode('utf-8')
print(utf8_bytes)
  • 运行以上代码后,将会输出以下结果:
utf8_bytes = b'\xe4\xbd\xa\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81' 
text = utf8_bytes.decode('utf-8')
print(text)
  • 运行以上代码后,将会输出以下结果:
class A(object):def __init__(self):print('A')super(A, self).__init__()class B(object):def __init__(self):print('B')super(B, self).__init__()class C(A):def __init__(self):print('C')super(C, self).__init__()class D(A):def __init__(self):print('D')super(D, self).__init__()class E(B, C):def __init__(self):print('E')super(E, self).__init__()class F(C, B, D):def __init__(self):print('F')super(F, self).__init__()class G(D, B):def __init__(self):print('G')super(G, self).__init__()if __name__ == '__main__':g = G()# G# D# A# Bprint('-----------------------')f = F()# F# C# B# D# A

解释:

  • 创建对象g = G()
    • 首先调用G类的构造函数,打印"G"
    • 然后调用D类的构造函数,打印"D"
    • 接着调用A类的构造函数,打印"A"
    • 最后调用B类的构造函数,打印"B"。
  • 创建对象f = F()
    • 首先调用F类的构造函数,打印"F"
    • 然后按照多重继承的顺序依次调用CBD类的构造函数,打印"C"、"B"和"D"
    • 最后调用A类的构造函数,打印"A"。

多重继承的执行顺序

  • 多重继承的执行顺序遵循一个称为C3线性化算法的规则。
    • 在这个算法中,首先按照从左到右的顺序解析所有的父类,并确保不会出现重复的类。
    • 然后,根据拓扑顺序合并各个父类的方法,最终得到一个线性的方法解析顺序。

super()

  • E类的定义中,它继承了BC类,而C类又继承自A
    • 所以方法解析顺序是E -> B -> C -> A
  • 注意,在多重继承的情况下,通过super()调用父类的方法时,Python会按照方法解析顺序进行调用。
    • 同样地,在F类和G类中也是遵循这个方法解析顺序。
    • 因此,在输出结果中可以看到先后调用了各个类的构造函数。

13.什么是可迭代对象,什么是迭代器对象?(1分)

可迭代对象

  • 可迭代对象(Iterable)是指实现了__iter__()方法的对象,在使用for循环遍历时能够提供一个迭代器。
    • 可迭代对象可以直接用于for循环中,或者通过调用iter()函数将其转换为迭代器对象。

迭代器对象

  • 迭代器对象(Iterator)是指实现了__iter__()__next__()方法的对象。
    • 迭代器对象能够记录并返回当前迭代的位置,每次调用__next__()方法都会返回下一个值,直到迭代结束,抛出StopIteration异常。

总结:

  • 可迭代对象是能够提供迭代器的对象,可以使用for循环进行遍历。
  • 迭代器对象实现了__iter__()__next__()方法,能够记录当前的迭代状态并返回下一个值。

14.迭代器对象有什么优点(1分)

迭代器对象具有以下几个优点:

  • 惰性计算(Lazy Evaluation):

    • 迭代器对象采用惰性计算的方式,即只在需要时才计算下一个值。

    • 这种特性使得迭代器对象可以处理大规模数据集,而不需要一次性加载全部数据到内存中,从而节省了内存资源。

  • 节约空间:

    • 由于迭代器对象每次只返回一个值,所以占用的内存空间较小,不受数据规模大小的限制。

    • 这对于处理大型数据集来说非常重要。

  • 支持无限序列:

    • 迭代器对象可以用来处理无限序列,因为它仅在需要时计算下一个值。

    • 这使得迭代器对象非常适合处理大规模数据流或者动态产生的数据。

  • 可以实现自定义迭代逻辑:

    • 通过实现__iter__()__next__()方法,我们可以自定义迭代器对象的行为。

    • 这样可以更加灵活地控制迭代过程,满足特定需求。

  • 增强代码可读性:

    • 使用迭代器对象可以提高代码的可读性和简洁性,尤其是在处理复杂的迭代逻辑时。
    • 迭代器的使用能够将复杂的循环逻辑封装在迭代器内部,使得代码更加清晰易懂。

综上所述,迭代器对象具有惰性计算、节约空间、支持无限序列、可自定义迭代逻辑以及增强代码可读性等优点。

15.简述for循环的原理(1分)

for循环是一种常用的迭代控制结构,用于重复执行指定的代码块。其原理如下:

  1. 创建迭代器:首先,获取被迭代对象的迭代器。被迭代对象可以是序列(如字符串、列表、元组等)、可迭代对象(如生成器、迭代器对象等)或者其他支持迭代的对象。

  2. 迭代执行:通过调用迭代器的__next__()方法,依次获取对象的下一个值。每次循环开始时,都会调用__next__()方法获取新的值。

  3. 判断条件:在每次迭代之前,判断迭代器是否还有下一个值。如果迭代器已经到达末尾,则终止循环。

  4. 执行循环体:如果条件满足(即还有下一个值),则执行循环体中的代码。循环体可以是单个语句或者一个代码块。

  5. 重复执行:完成一次循环后,回到步骤3,继续判断迭代器是否还有下一个值。如果有,则继续执行循环体;如果没有,则结束循环。

总结而言,for循环的原理是通过获取对象的迭代器,在每次循环中判断迭代器是否还有下一个值,并执行循环体中的代码,直到迭代器到达末尾。

这种机制使得我们可以便捷地对序列、可迭代对象和其他支持迭代的对象进行遍历和处理。

16.简述面向过程编程(1分)

面向过程编程是一种编程范式,它将程序视为一系列的过程或函数的集合,通过这些过程来实现程序的功能和逻辑。

面向过程编程着重于对问题的分析和解决方案的步骤化描述。

在面向过程编程中,程序的执行流程是线性的,从头到尾按照定义的过程依次执行。主要特点包括:

  • 以过程为中心:

    • 程序被分解为一系列独立的过程或函数,每个过程承担一个特定的功能。

    • 这些过程可以接受输入参数,并返回输出结果。

  • 数据和行为分离:

    • 在面向过程编程中,数据和操作是分离的。

    • 数据通过参数传递给过程,并在过程内部进行处理和操作。

  • 自顶向下的设计:

    • 面向过程编程通常采用自顶向下的设计方法,将问题分解为更小的、可独立实现的子过程,然后再组合起来解决整个问题。
  • 强调算法和过程:

    • 面向过程编程注重算法的设计和过程的定义,通过合理设计算法和过程的结构和逻辑,来实现程序的功能和效果。

面向过程编程适用于简单和直接的问题,例如一些简易的脚本、工具和小型应用程序等。

它强调的是过程和操作的线性顺序,对于复杂的问题和大型项目来说,面向对象编程往往更加适用,因为它更注重数据和行为的封装、抽象和组织。

17.比较两个值得大小,获得较大的一个值,用一行代码实现(1分)

  • 在大多数编程语言中,可以使用三元运算符来实现比较两个值的大小并获取较大值。以下是一行代码的示例:
names = ['kevin', 'jack', 'tony', 'tank']
upper_names = [name.upper() for name in names]
  • 以上代码将会得到['KEVIN', 'JACK', 'TONY', 'TANK']作为结果。

2、将names=[‘kevin’,’ 'jack_sb’, 'tank', 'tony']中以sb结尾的名字过滤掉,然后保存剩下的名字长度(1分)

  • 使用列表生成式可以通过添加条件判断语句来过滤掉不符合要求的元素,并将满足条件的元素进行操作。
    • 这里可以使用列表生成式过滤出不以sb结尾的名字,并保存剩下的名字长度。
names = ['kevin', 'jack_sb', 'tank', 'tony']
filtered_lengths = [len(name) for name in names if not name.endswith('sb')]
  • 以上代码将会得到[5, 4]作为结果。

3、求文件a.txt中最长的行的长度(长度按字符个数算,需要使用max函数)(1分)

  • 使用文件对象的readlines()方法可以一次性读取文件的所有行,并返回一个包含各行内容的列表。
    • 使用max()函数可以求得列表中的最大值,即最长的行的长度。
with open('a.txt', 'r') as file:lines = file.readlines()max_length = max(len(line) for line in lines)
  • 以上代码会将最长的行的长度赋值给max_length变量。

4、求文件a.txt中总共包含的字符个数?(1分)

  • 求文件a.txt中总共包含的字符个数:

  • 使用文件对象的read()方法可以一次性读取文件的所有内容,并返回一个包含文件内容的字符串。

    • 对这个字符串使用len()函数可以得到字符个数。
with open('a.txt', 'r') as file:content = file.read()total_characters = len(content)
  • 以上代码将会得到文件中总共包含的字符个数,赋值给total_characters变量。

5、思考(1分)

with open('a.txt') as f:g=(len(line) for line in f)print(sum(g)) #为何报错?

我的理解是未指明打开文件的方式以及编码格式没有指明

在该代码中,报错可能是由于文件未正确打开或已被关闭导致的。

为了正确读取文件内容,我们需要确保以下几点:
  1. 文件存在:请确保当前目录下存在名为"a.txt"的文件。
  2. 文件权限:请检查文件是否有足够的权限进行读取操作。
  3. 文件名正确:请确保传入open()函数的文件名是正确的,包括文件名的大小写和扩展名。
  4. 文件关闭:在读取文件结束之后,应该使用close()方法或者使用with语句来自动关闭文件。
  • 以下是一个修复错误的示例代码:
try:with open('a.txt') as f:g = (len(line) for line in f)print(sum(g))
except FileNotFoundError:print("找不到文件:a.txt")
except PermissionError:print("没有权限读取文件:a.txt")
  • 如果问题仍然存在,请确保满足上述条件并检查其他可能导致错误的情况。

6、文件shopping.txt内容如下

# 读取文件内容并计算总花费
# -*-coding: Utf-8 -*-
# @File : text1 .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/6/30# 读取文件内容并计算总花费
total_cost = 0
products = []with open('shopping.txt') as f:for line in f:data = line.strip().split(',')name = data[0]price = int(data[1])count = int(data[2])total_cost += price * countproduct_info = {'name': name, 'price': price, 'count': count}products.append(product_info)print("总共花了多少钱:>>>>", total_cost)
print("所有商品的信息:>>>>", products)# 单价大于10000的商品信息
expensive_products = [product for product in products if product['price'] > 10000]
print("单价大于10000的商品信息:>>>>", expensive_products)
  • 以上代码将首先计算总花费,然后打印所有商品的信息,最后打印单价大于10000的商品信息(满足题目中的条件)。

19.有一个存放员工名与其月薪的字典如下

salaries = {'kevin':300, 'jack':100000000, 'tony':10000, 'tank':200}# 1. 求薪资最高的员工姓名
highest_salary_employee = max(salaries, key=salaries.get)
print("薪资最高的员工姓名:", highest_salary_employee)# 2. 将字典映射成列表,元素为员工姓名和年薪
employee_salaries_list = [(name, salary*12) for name, salary in salaries.items()]
print("字典映射成的列表:", employee_salaries_list)# 3. 过滤出薪资大于10000的员工姓名
filtered_employees = [name for name, salary in salaries.items() if salary > 10000]
print("薪资大于10000的员工姓名:", filtered_employees)

以上代码可以在一行内实现您提出的三个问题。

  1. 使用max函数和key参数,根据字典中的值获取薪资最高的员工姓名。
  2. 使用列表推导式,将字典中的键和值组成元素,并将每个员工的月薪乘以12计算出年薪。
  3. 使用列表推导式,过滤出薪资大于10000的员工姓名。

20.简述yield与return的相同点与不同点(1分)

yield和return是在Python中用于返回值的关键字,它们既有相同点,也有不同点。

相同点:

  • 返回值:

    • yield和return都用于将值从函数中返回给调用者。
  • 中止函数执行:

    • 一旦遇到yield或return语句,函数的执行会暂时终止,并将相应的值返回。

不同点:

  • 继续执行:

    • 使用yield时,函数记住了它的状态(所有局部变量的当前值),并返回一个迭代器。
    • 每次通过调用next()函数或循环迭代时,函数都会从上次离开的位置继续执行,直到再次遇到yield语句。
  • 返回值类型:

    • yield返回的是一个生成器对象,可以迭代获取多个值;return直接返回一个值,并结束函数的执行。
  • 使用场景:

    • yield主要用于生成器函数,可以用于实现惰性计算、无限序列等;return主要用于普通函数,一般情况下只返回单个结果值。

总结:

  • yield和return都用于返回值,但具有不同的行为和用途。
    • yield用于生成器函数,可以实现迭代器的功能,支持多次返回值的延迟计算。
    • 而return则用于普通函数,表示函数的结束,并返回一个值。

21.下面这段代码的输出结果将是什么?请解释。(1分)

class Parent(object):x = 1class Child1(Parent):passclass Child2(Parent):passprint(Parent.x, Child1.x, Child2.x)
# 1 1 1
Child1.x = 2print(Parent.x, Child1.x, Child2.x)
# 1 2 1
Parent.x = 3print(Parent.x, Child1.x, Child2.x)
# 3 2 3

解释如下:

  • 初始状态下,ParentChild1Child2类都直接或间接地继承自object,且它们共享同一个类属性x,其初始值为1

    • 所以第一行输出为1 1 1
  • 接着,为Child1类设置了类属性x的值为2,而其他类并未修改x的值。

    • 因此,第二行输出为1 2 1
  • 最后,为Parent类设置了类属性x的值为3,而Child1类的x属性保持不变,而Child2类作为Parent的子类,会继承Parent类的变化,所以其x属性也被修改为3

    • 因此,第三行输出为3 2 3

因为类属性共享于所有实例和子类,当某个类修改了该属性的值时,会影响到所有使用该属性的位置,包括所有实例和子类。

22.类的属性和对象的属性有什么区别?(1分)

  • 定义位置:

    • 类的属性是定义在类的内部的,而对象的属性是定义在对象上的。
  • 访问方式:

    • 类的属性可以通过类名直接访问,也可以通过对象访问;对象的属性只能通过对象访问。
  • 作用范围:

    • 类的属性对于所有的对象都是共享的,即所有的对象都可以访问和修改类的属性;对象的属性是针对每个对象独立存在的,每个对象都有自己的属性副本。
  • 默认值:

    • 类的属性可以在类的定义中进行初始化,并且所有的对象都会共享这个初始化值;对象的属性通常在对象创建后进行初始化,每个对象可以有不同的初始值。
  • 修改方式:

    • 类的属性可以通过类名直接修改;对象的属性只能通过对象进行修改。

总的来说,类的属性是属于类本身的,对于所有的对象都是共享的;而对象的属性是属于各个对象的,每个对象都有独立的属性副本。

类的属性可以用于存储与类相关的信息,而对象的属性则可以用于存储与对象个性化相关的数据。

23.什么是新式类,什么是经典类,二者有什么区别?什么是深度优先,什么是广度优先?(1分)

新式类和经典类是Python中对类的两种不同的分类方式。

  • 新式类:

    • 新式类是指继承自object类或其子类的类。

    • 在Python3中,所有的类都默认是新式类。

  • 经典类:

    • 经典类是指没有显式继承自object类或其子类的类。
    • 在Python2中,如果在类的定义中没有显式继承自object类或其子类,则该类被认为是经典类。

区别:

  • 方法解析顺序的不同:

    • 在多继承的情况下
      • 新式类使用的是广度优先搜索(MRO)算法来确定方法的调用顺序

      • 而经典类使用的是深度优先搜索算法。

  • 对象模型的不同:

    • 新式类引入了一些新的概念

      • 如描述符、属性等,使得对象模型更加合理和清晰。
    • 而经典类的对象模型相对较简单,缺少一些高级特性。

深度优先和广度优先是两种不同的遍历算法。

  • 深度优先(Depth First Search,DFS):

    • 从根节点开始,沿着一个路径一直到达叶子节点,然后再返回到前一个节点,继续向下探索。

    • 在多继承中,深度优先会按照继承关系自上而下先深入到最底层的子类,然后再回溯到其他兄弟类。

  • 广度优先(Breadth First Search,BFS):

    • 从根节点开始,一层一层地向下遍历节点,保证每一层内的节点都被访问过。
    • 在多继承中,广度优先会按照继承关系自左向右依次遍历每个类,保证每个类都能被访问到。

在Python中,默认情况下,新式类的方法解析顺序使用广度优先(C3线性化算法),而经典类使用深度优先。

但是可以通过super()函数和特殊方法__bases__来进行修改和控制执行顺序。

24.什么是绑定到对象的方法,、如何定义,如何调用,给谁用?有什么特性(1分)

【一】普通版

绑定到对象的方法是指定义在类中的函数,可以通过类的实例对象来调用。

它与其他类型的方法(如静态方法和类方法)相比具有以下特点:

  • 定义方式:

    • 绑定到对象的方法是在类中通过普通的函数定义,并且第一个参数通常命名为self,用于表示对象实例自身。
  • 调用方式:

    • 绑定到对象的方法需要通过类的实例对象来调用,直接使用点.操作符即可。
  • 作用对象:

    • 绑定到对象的方法是针对类的实例对象进行操作的,并且方法中的self参数会自动传入当前实例对象,以便方法可以访问对象的属性和方法。
  • 自动绑定:

    • 当通过实例对象调用绑定到对象的方法时,方法内部的self参数会自动绑定到该实例对象,所以无需手动传入对象参数。
  • 访问对象属性和方法:

    • 在绑定到对象的方法中,可以通过self参数来访问和修改对象的属性和调用其他的对象方法。

绑定到对象的方法通常用于对特定对象的操作和行为

例如在类中定义了一个Person类,可以定义一个walk方法来描述人走路的操作

然后通过实例对象来调用该方法,实现对具体人的行走的控制和管理。

调用时只需要在实例对象上使用点操作符,例如person_instance.walk()即可调用该方法。

示例

  • 绑定到对象的方法是指在面向对象编程中,将方法与特定对象实例关联起来的一种机制。
    • 通过这种绑定,对象可以使用自己所具有的方法来操作和处理数据。
  • 在Python中,定义绑定到对象的方法非常简单。
    • 通常,我们会在类中定义方法,并且这些方法会自动关联到该类的实例对象。
    • 例如,考虑以下示例代码:
class Circle:def __init__(self, radius):self.radius = radiusdef area(self):return 3.14 * self.radius**2# 创建Circle类的实例对象
my_circle = Circle(5)# 调用绑定到对象的方法
circle_area = my_circle.area()
print(circle_area)  # 输出: 78.5
  • 在上述代码中,我们定义了一个名为Circle的类,其中包含了一个area方法,该方法计算圆的面积。
    • 通过调用该方法时使用my_circle.area()语法,我们实际上是在调用my_circle对象上绑定的area方法,并使用my_circle对象的属性(radius)进行计算。
  • 绑定到对象的方法可以让对象自身拥有独立的行为和操作,它们能够访问对象的属性,并且可以根据不同的对象实例产生不同的结果。
    • 这种特性使得面向对象编程更加灵活和可扩展,提供了一种便捷的方式来组织和操作相关的数据与逻辑。
    • 绑定到对象的方法可以被调用的对象本身使用,也可以在其他地方通过对象访问调用。

【二】@classmethod方法

  • @classmethod是Python中一种特殊的装饰器,用于定义类方法(class method)。
    • 类方法是绑定到类而不是类的实例的方法。
    • 通过使用装饰器@classmethod,可以将普通的函数转换为类方法。
  • 类方法与实例方法(即绑定到类的实例的方法)以及静态方法(仅在类中名称空间内定义的方法,与实例无关)有所不同。它们具有以下特点:
  1. 类方法是通过类本身进行调用的,而不是通过类的实例进行调用。因此,在类方法中没有self参数,而是使用cls参数来代表该类自身。
  2. 类方法可以访问和修改类级别的属性和变量,这些属性和变量是与类关联的,而不是具体的实例。这使得类方法非常适合执行只需访问类级别数据的操作。
  3. 类方法可以在不创建类的实例的情况下使用。这意味着你可以直接通过类本身来调用类方法。
  4. 类方法可以被子类继承,并且在子类中也可以通过子类进行调用。

下面是一个示例,展示了如何使用@classmethod定义和调用类方法:

class MyClass:class_variable = "Class Variable"@classmethoddef class_method(cls):print("This is a class method")print("Accessing class variable:", cls.class_variable)# 调用类方法
MyClass.class_method()

输出结果将是:

class MyClass:@staticmethoddef static_method():# 静态方法的实现逻辑pass
2.调用静态方法:
  • 由于静态方法不依赖于实例,可以通过类名直接调用静态方法,而无需创建类的实例。

示例代码如下:

MyClass.static_method()
3.特性和注意事项:
  • 静态方法属于类,不属于任何实例。因此,不能访问或修改实例的属性或调用实例的方法。
  • 静态方法可以访问类级别的属性和方法。这些属性和方法定义在类的整个生命周期内保持不变。
  • 静态方法也可以作为工具函数,与类无关,但被放在类中以组织代码。
  • 静态方法可以被子类继承,并且可以在子类中被覆盖重写。

25.有字符串'email1:378533872@qq.com email2:333312312@163.com eamil3:jacksb123@gmail.com'匹配出所有的邮箱地址:['378533872@qq.com', '333312312@163.com', 'alexsb123@gmail.com'](1分)

  • 要从给定的字符串中匹配出所有的邮箱地址,可以使用正则表达式来实现。
    • 正则表达式可以通过定义一定的模式来查找符合该模式的字符串。
  • 下面是使用Python的re模块来匹配出所有邮箱地址的代码示例:
import reemail_string = 'email1:378533872@qq.com email2:333312312@163.com eamil3:jacksb123@gmail.com'
pattern = r'\b[A-Za-z-9._%+-]+@[A-Za-z-9.-]+\.[A-Z|a-z]{2,}\b'emails = re.findall(pattern, email_string)
print(emails)  # 输出: ['378533872@qq.com', '333312312@163.com', 'jacksb123@gmail.com']
  • 在上述代码中,我们使用了\b[A-Za-z-9._%+-]+@[A-Za-z-9.-]+\.[A-Z|a-z]{2,}\b作为正则表达式的模式
    • 该模式可以匹配大部分常见的邮箱地址格式。
    • 其中,
      • \b表示单词边界,
      • [A-Za-z-9._%+-]+表示匹配字符、数字、以及一些特殊字符,
      • @[A-Za-z-9.-]+\.[A-Z|a-z]{2,}表示匹配@符号后面的域名部分,
      • {2,}表示该部分至少包含两个字符(如com、gov等)。
  • 通过调用re.findall()函数,并传入正则表达式模式和待匹配的字符串,即可返回所有匹配的结果,将邮箱地址保存在一个列表中,并输出结果。

注意:

以上代码仅针对普遍情况下的常见邮箱地址格式,对于一些特殊的邮箱格式可能无法完全匹配。

在实际使用中,可以根据具体需求来调整正则表达式的模式以适应更广泛的匹配范围。

【三】综合题(60分)

考试内容:从零开始编写ATM项目所有功能(面向过程版本和面向对象版本人选其一)

• 新建项目,整个编程期间,pycharm窗口最大化,不允许切换窗口,再次强调!!!考试期间不允许切换窗口,不允许窗口最小化!!!!

• 项目中用到的变量名,函数名,文件名,模块名都需要跟老师的不一样,可以考虑加入自己的名字作为前缀(非常丑陋,但为了防止作弊)

• 所有功能需要正常运行

本人比较懒,懒得写了,有意者可以看看我写的选课系统

链接地址:选课系统项目工程 - Chimengmeng - 博客园 (cnblogs.com)


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部