阶段考试(月考)
【一】介绍
满分100分,90分及格
考试范围:
- 1.Python基础
- 2.数据类型
- 3.流程控制
- 4.文件处理
- 5.函数
- 6.面向对象
【二】基础题(40分)
1.定义一个变量有三个特性,分别为?(1分)
一个变量具有三个特性,分别是标识符、数据类型和存储值。
- 标识符:
- 变量必须有一个唯一的名称,用于在程序中引用该变量。
- 标识符由字母、数字和下划线组成,必须以字母或下划线开头。
- 例如,x、myVariable、_count 是有效的标识符。
- 数据类型:
- 变量必须具有一个明确的数据类型,用于指定变量可以存储的数据的种类和范围。
- 常见的数据类型包括整数(如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的元素,即前两个月的工资,然后使用逗号分隔,将这两个元素赋值给变量month1
和month2
。 -
可以通过打印输出验证:
print(month1) # 输出 3.1
print(month2) # 输出 2.1
- 这样就用一行代码完成了将前两个月的工资赋值给两个变量名的操作。
4.可变的数据类型有哪些,不可变的数据类型有哪些(1分)
- 可变的数据类型包括列表(list)和字典(dictionary)。
- 列表是用于存储多个元素的有序集合,可以通过索引访问、修改、删除其中的元素,因此属于可变类型。
- 字典是一种无序的键-值对集合,可以通过键来索引和修改其中的值,也属于可变类型。
- 不可变的数据类型包括数字(int, float)、字符串(str)、元组(tuple)。
- 数字是表示数值的数据类型,它们的值在创建之后不可更改。
- 字符串是字符的有序序列,一旦创建,其内容不可变。
- 元组是用于存储多个元素的有序容器,一旦创建后,元素的内容和顺序都不可变。
- 总结:
可变的数据类型:列表(list)、字典(dictionary)
不可变的数据类型:数字(int, float)、字符串(str)、元组(tuple)
5.容器类型有?序列类型有?(1分)
-
容器类型是指能够包含其他对象的数据类型,常见的容器类型有列表(list)、元组(tuple)、集合(set)、字典(dictionary)等。
-
序列类型是一种特殊的容器类型,它按照元素在容器中的位置进行存储和访问。
- 序列类型包括字符串(str)、列表(list)、元组(tuple)。
- 字符串是字符的有序序列,列表是有序的可变序列,元组是有序的不可变序列。
-
所以总结:
- 容器类型:列表(list)、元组(tuple)、集合(set)、字典(dictionary)
- 序列类型:字符串(str)、列表(list)、元组(tuple)
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个字节。
- 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中的
- 要将Python 3中的
str
转换为UTF-8格式的bytes
- 可以使用字符串的
encode
方法,并指定编码方式为UTF-8。示例如下:
- 可以使用字符串的
text = "你好,世界!"
utf8_bytes = text.encode('utf-8')
print(utf8_bytes)
- 运行以上代码后,将会输出以下结果:
b'\xe4\xbd\xa\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81'
- 其中,
b'...'
表示创建的字节序列,每个\x
后的两位数字表示一个字节的十六进制值,对应了文本中的每个字符所占的字节。 - 以上结果就是将Unicode字符串转换为UTF-8编码的字节序列的过程。
10.在python3中如何把utf-8格式的bytes解码成str(1分)
- 在Python 3中,可以使用
decode()
方法将UTF-8格式的字节解码为字符串(str
)。示例如下:
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)
- 运行以上代码后,将会输出以下结果:
你好,世界!
- 以上代码通过
decode()
方法将UTF-8格式的字节序列utf8_bytes
解码为Unicode字符串text
。 - 解码时需要指定正确的编码方式,这里是使用UTF-8进行解码。
- 注意,在解码时需确保使用与编码时相同的编码方式,以避免出现乱码或其他解码错误。
11.什么是名称空间?名称空间的加载顺序是?查找名字的顺序是?(1分)
名称空间(Namespace)是指在程序中存储和管理变量名字的一种机制。它定义了变量名在代码中的可见性和生命周期。
在Python中,名称空间可以分为以下几种类型:
- 内置命名空间(Built-in Namespace):包含Python解释器内置的函数、模块等。
- 全局命名空间(Global Namespace):在模块级别定义的变量都属于全局命名空间。
- 局部命名空间(Local Namespace):在函数、方法或类中定义的变量都属于局部命名空间。
- 内置作用域(Built-in Scope):包含内置命名空间中的变量名。
名称空间的加载顺序如下:
- 首先加载内置命名空间,在Python解释器启动时就被加载。
- 接着加载全局命名空间,在模块导入或执行过程中创建和加载。
- 最后加载局部命名空间,在函数、方法、类等定义和执行过程中创建和加载。
查找名字的顺序是按照以下规则进行:
- 在局部命名空间中查找变量名,如果找到,则停止搜索。
- 如果局部命名空间中没有找到,继续在上层的嵌套命名空间(例如函数所在的模块的全局命名空间)中查找。
- 如果在所有命名空间中都没有找到,最后在内置命名空间中查找。
这种搜索变量的过程被称为LEGB规则(Local - Enclosing - Global - Built-in)。
- L:局部命名空间(Local Namespace)
- E:嵌套命名空间(Enclosing Namespace),比如一个函数中嵌套的函数
- G:全局命名空间(Global Namespace)
- B:内置命名空间(Built-in Namespace)
12.多重继承的执行顺序,请解答以下输出结果是什么?并解释。(3分)
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
# B
print('-----------------------')
f = F()
# F
# C
# B
# D
# A
解释:
- 创建对象
g = G()
时- 首先调用
G
类的构造函数,打印"G" - 然后调用
D
类的构造函数,打印"D" - 接着调用
A
类的构造函数,打印"A" - 最后调用
B
类的构造函数,打印"B"。
- 首先调用
- 创建对象
f = F()
时- 首先调用
F
类的构造函数,打印"F" - 然后按照多重继承的顺序依次调用
C
、B
和D
类的构造函数,打印"C"、"B"和"D" - 最后调用
A
类的构造函数,打印"A"。
- 首先调用
多重继承的执行顺序
- 多重继承的执行顺序遵循一个称为C3线性化算法的规则。
- 在这个算法中,首先按照从左到右的顺序解析所有的父类,并确保不会出现重复的类。
- 然后,根据拓扑顺序合并各个父类的方法,最终得到一个线性的方法解析顺序。
super()
- 在
E
类的定义中,它继承了B
和C
类,而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循环是一种常用的迭代控制结构,用于重复执行指定的代码块。其原理如下:
-
创建迭代器:首先,获取被迭代对象的迭代器。被迭代对象可以是序列(如字符串、列表、元组等)、可迭代对象(如生成器、迭代器对象等)或者其他支持迭代的对象。
-
迭代执行:通过调用迭代器的
__next__()
方法,依次获取对象的下一个值。每次循环开始时,都会调用__next__()
方法获取新的值。 -
判断条件:在每次迭代之前,判断迭代器是否还有下一个值。如果迭代器已经到达末尾,则终止循环。
-
执行循环体:如果条件满足(即还有下一个值),则执行循环体中的代码。循环体可以是单个语句或者一个代码块。
-
重复执行:完成一次循环后,回到步骤3,继续判断迭代器是否还有下一个值。如果有,则继续执行循环体;如果没有,则结束循环。
总结而言,for循环的原理是通过获取对象的迭代器,在每次循环中判断迭代器是否还有下一个值,并执行循环体中的代码,直到迭代器到达末尾。
这种机制使得我们可以便捷地对序列、可迭代对象和其他支持迭代的对象进行遍历和处理。
16.简述面向过程编程(1分)
面向过程编程是一种编程范式,它将程序视为一系列的过程或函数的集合,通过这些过程来实现程序的功能和逻辑。
面向过程编程着重于对问题的分析和解决方案的步骤化描述。
在面向过程编程中,程序的执行流程是线性的,从头到尾按照定义的过程依次执行。主要特点包括:
-
以过程为中心:
-
程序被分解为一系列独立的过程或函数,每个过程承担一个特定的功能。
-
这些过程可以接受输入参数,并返回输出结果。
-
-
数据和行为分离:
-
在面向过程编程中,数据和操作是分离的。
-
数据通过参数传递给过程,并在过程内部进行处理和操作。
-
-
自顶向下的设计:
- 面向过程编程通常采用自顶向下的设计方法,将问题分解为更小的、可独立实现的子过程,然后再组合起来解决整个问题。
-
强调算法和过程:
- 面向过程编程注重算法的设计和过程的定义,通过合理设计算法和过程的结构和逻辑,来实现程序的功能和效果。
面向过程编程适用于简单和直接的问题,例如一些简易的脚本、工具和小型应用程序等。
它强调的是过程和操作的线性顺序,对于复杂的问题和大型项目来说,面向对象编程往往更加适用,因为它更注重数据和行为的封装、抽象和组织。
17.比较两个值得大小,获得较大的一个值,用一行代码实现(1分)
- 在大多数编程语言中,可以使用三元运算符来实现比较两个值的大小并获取较大值。以下是一行代码的示例:
max_value = value1 if value1 > value2 else value2
- 这行代码首先比较value1与value2的大小关系
- 如果value1大于value2,则将max_value赋值为value1,否则将max_value赋值为value2。
- 通过这样简单的条件判断,即可得到较大的值。
- 请注意,value1和value2可以是任何可进行比较的数据类型,例如整数、浮点数或字符串等。
18.使用列表生成式或生成器表达式解决下列问题
1、将names=[‘kevin’,'jack','tony','tank']
中的名字全部变大写(1分)
- 使用列表生成式可以快速地将列表中的每个元素进行操作
- 这里可以使用列表生成式将
names
中的名字变为大写形式。
- 这里可以使用列表生成式将
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)) #为何报错?
我的理解是未指明打开文件的方式以及编码格式没有指明
在该代码中,报错可能是由于文件未正确打开或已被关闭导致的。
为了正确读取文件内容,我们需要确保以下几点:
- 文件存在:请确保当前目录下存在名为"a.txt"的文件。
- 文件权限:请检查文件是否有足够的权限进行读取操作。
- 文件名正确:请确保传入
open()
函数的文件名是正确的,包括文件名的大小写和扩展名。 - 文件关闭:在读取文件结束之后,应该使用
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内容如下
mac,20000,3
lenovo,3000,10
tesla,1000000,10
chicken,200,1
求总共花了多少钱?(2分)
打印出所有商品的信息,格式为[{'name':'xxx','price':333,'count':3},...]
求单价大于10000的商品信息,格式同上(2分)
# 读取文件内容并计算总花费
total_cost =
products = []
with open('shopping.txt') as f:
for line in f:
data = line.strip().split(',')
name = data[]
price = int(data[1])
count = int(data[2])
total_cost += price * count
product_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':3000,
'jack':100000000,
'tony':10000,
'tank':2000
}
请用一行代码实现
1、求薪资最高的那名员工姓名(2分)
2、将字典映射成一个列表,[(‘kevin', 36000), ('jack', 1200000000), ('tony', 120000), ('tank’, 24000)],列表内每一个元素是员工姓名、员工的年薪(1分)
3、过滤出薪资大于10000的员工姓名(1分)
以下是使用一行代码解决您提出的问题的示例代码:
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)
以上代码可以在一行内实现您提出的三个问题。
- 使用
max
函数和key
参数,根据字典中的值获取薪资最高的员工姓名。- 使用列表推导式,将字典中的键和值组成元素,并将每个员工的月薪乘以12计算出年薪。
- 使用列表推导式,过滤出薪资大于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 = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
# 1 1 1
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
# 1 2 1
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
# 3 2 3
解释如下:
-
初始状态下,
Parent
、Child1
和Child2
类都直接或间接地继承自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 = radius
def 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
)进行计算。
- 通过调用该方法时使用
- 绑定到对象的方法可以让对象自身拥有独立的行为和操作,它们能够访问对象的属性,并且可以根据不同的对象实例产生不同的结果。
- 这种特性使得面向对象编程更加灵活和可扩展,提供了一种便捷的方式来组织和操作相关的数据与逻辑。
- 绑定到对象的方法可以被调用的对象本身使用,也可以在其他地方通过对象访问调用。
25.有字符串'email1:[email protected] email2:[email protected] eamil3:[email protected]'匹配出所有的邮箱地址:['[email protected]', '[email protected]', '[email protected]'](1分)
- 要从给定的字符串中匹配出所有的邮箱地址,可以使用正则表达式来实现。
- 正则表达式可以通过定义一定的模式来查找符合该模式的字符串。
- 下面是使用Python的re模块来匹配出所有邮箱地址的代码示例:
import re
email_string = 'email1:[email protected] email2:[email protected] eamil3:[email protected]'
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) # 输出: ['[email protected]', '[email protected]', '[email protected]']
- 在上述代码中,我们使用了
\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窗口最大化,不允许切换窗口,再次强调!!!考试期间不允许切换窗口,不允许窗口最小化!!!!
• 项目中用到的变量名,函数名,文件名,模块名都需要跟老师的不一样,可以考虑加入自己的名字作为前缀(非常丑陋,但为了防止作弊)
• 所有功能需要正常运行
标签:__,解释,迭代,字符,对象,代码,阶段,print,考试 From: https://www.cnblogs.com/dream-ze/p/17516029.html本人比较懒,懒得写了,有意者可以看看我写的选课系统