2023秋招面试 || python 熟练刷题记录
- 1、面向对象编程中:类属性、成员属性、实例属性
- 2、输出数值类型
- 3、__slots__类属性
- 4、文件IO
- 5、函数中的默认参数
- 6、python变量内存地址
- 8、浅复制与深复制
- 9、 函数参数列表
- 10 数据结构及不同数据结构支持的方法
- 11、 模块
- 12、python 作用域和命名空间
- 12、return和yeild区别
- 13、global标准库获取文件夹下匹配的所有文件
- 14、re标准库进行字符串模式匹配
- 15、dir()内置函数查找作用域内所有属性方法
- 16、python的打包分发和模块管理
- 16.0 基于github的模块打包方法
- 16.1 判断主模块还是子模块
- 17、 python中报的错误与异常
- 18、 @property 方法
(目的:用于个人纪录和后期复盘,每日更新中……)
来源:牛客网-题库-专项练习-软件开发-python
廖雪峰的官方网站
菜鸟教程 python100例
w3cschoocl
python中文教程
1、面向对象编程中:类属性、成员属性、实例属性
(来源:牛客网题目修改)
class Base(object):
count = 0
flag = 0
#flag与count都是类属性,区别:count在类方法中被调用,flag未被调用
def __init__(self):
self.count += 1
b1 = Base()
b2 = Base()
b1.count = b1.count + 1
b1.flag = b1.flag + 1
b1.special = 'b1special' #可以创建b1对象特有属性,并通过b1实例来调用
print(b1.count,end=" ") # 见详解1、
print(Base.flag,end=" ") # 见详解2、
print(b2.flag) # 见详解2、
print(b2.count) # 见详解3、
>>>
>1001
【分析】:
1、count是类属性,为全局共有,类属性可以为实例属性提供默认值。b1.count
和b1.flag
为实例属性,其默认值j均来源于类属性,为0。b1.count = b1.count + 1
因此,b1.count=1
。
2、实例属性为局部私有,不会影响到类属性的值,也不会影响到其他实例属性。因此Base.count=0
且b2.flag=0
3、
2、输出数值类型
print(type(1/2)) # python 3 -> <class 'float'>
print type(1/2) # python 2 -> <type 'int'> Python2 中除法默认向下取整
3、__slots__类属性
(来源:廖雪峰的官方网站、牛客网)
想要限制实例的属性怎么办?比如,只允许对Student实例添加name和age属性,不允实例随意添加特殊属性
>>> s = Student() # 创建新的实例
>>> s.name = 'Michael' # 绑定属性'name'
>>> s.age = 25 # 绑定属性'age'
>>> s.score = 99 # 绑定属性'score'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
【以上代码分析】__slots__属性用来限制实例对象的属性,实例对象的实例属性最多只能在__slots__属性值的范围内。
class Vector:
__slots__='x','y'
def __init__(self):
pass
class Vector3d(Vector):
__slots__='x','z'
def __init__(self):
pass
vector = Vector()
vector3d = Vector3d()
》》》Vector3d类的实例对象vector3d最多只能允许属性x、y和z
【以上代码分析】如果子类没有定义__slots__属性,则不会继承父类的__slots__属性,如果子类定义了__slots__属性,则子类对象允许的实例属性包括子类的__slots__加上父类的__slots_。
4、文件IO
Python中,打开文件语法为
text = oepn(filePath, 操作方式,编码方式)
常见操作方式
'r':读
'w':写
'a':追加
常见编码方式
utf-8
gbk
5、函数中的默认参数
执行以下程序,输出结果为()
def fun(a=(),b=[]):
a += (1,)
b.append(1)
return a,b
fun()
print(fun())
》》》
((1,), [1, 1])
【分析】
a是元组,不可修改。b是列表,可修改。
当执行第一个fun()时,先实例化了 a对象和b对象然后 a=(1,) b=[1]
当执行第二个fun()时,a是元组是不可变对象所以还是a=(1,),但是b因为是可变对象所以会在原来的内存空间变为[1,1]
Python的默认参数只在函数定义时被赋值一次,而不会每次调用函数时又创建新的引用。这意味着,函数定义完成后,默认参数已经存在固定的内存地址了,如果使用一个可变的默认参数并对其进行改变,那么以后对该函数的调用都会改变这个可变对象,而默认参数如果是不可变对象,不存在该问题,因此正确答案为A选项。
6、python变量内存地址
-
对于整数、短字符串等值,在内存中只会有一份,也就是地址一致。
-
对于元组、字典、列表、集合以及range、map等容器类对象,这些的类型的数据值即使看起来一样,内存地址也是不一样的。
a与b定义如下,下列哪个选项是正确的?
a = '123'
b = '123'
a is b # 判断内存地址是否相同
>>> True
list.remove(obj)表示移除列表中某个值的第一个匹配项
dict的pop是删除指定key的键和值,如果没有指定,则返回default,就会报错;
而list的pop是删除最后一个值并返回
,dict.update(dict2)表示把字典dict2的键/值对更新到dict里
1、dict.get()的键不存在,返回默认值None;
2、dict.get()的键不存在,返回默认修改值18; age=info.get('age',18)
upper() 表示将字符小写转换为大写,title方法将字符串内每个连续字母的首字母大写,其余小写
insert方法是指定位置前面加元素
tmp = [1, 2, 3, 4, 5, 6]
tmp.insert(-3, 'a')
print(tmp[4])
>>>4
dicts = {'a': 1, 'b': 2, 'c': 3}
print(dicts.pop(‘a'))
>>>{'b': 2, 'c': 3}
In [1]: a = [1, 2]
In [2]: b = [3, 4]
In [3]: a.append(b)
In [4]: a
Out[4]: [1, 2, [3, 4]]
使用extend()函数的效果:
In [1]: a = [1, 2]
In [2]: b = [3, 4]
In [3]: a.extend(b)
In [4]: a
Out[4]: [1, 2, 3, 4]
在python3中,元组的“+”运算表示连接,
one = (1, 2, 3)
two = ('a', 'b')
print(one+two)
(1, 2, 3, 'a', 'b')
for i in range(4,6):
print i
# 前闭后开
7、函数中循环内定义闭包函数
闭包或工厂函数,如果在函数中定义的lambda或者def嵌套在一个循环之中,而这个内嵌函数又引用了一个外层作用域的变量,该变量被循环所改变,那么所有在这个循环中产生的函数会有相同的值------也就是在最后一次循环中完成时被引用变量的值。
def fn():
t = [
i = 0
while i < 2:
t.append(lambda x: print(i*x,end=","))
i += 1
return t
for f in fn():
f(2)
>>>4,4
8、浅复制与深复制
在python3中,dict.copy()表示返回一个字典的浅复制,并且复制后的新的字典元素变化不会影响原来的字典
import copy
a = [1, 2, 3, 4, ['a', 'b']]
b = a # 引用,除非直接给a重新赋值,否则a变则b变,b变则a变
c = copy.copy(a) # 浅复制,只会拷贝父对象, 不会拷贝父对象中的子对象,所以若a的子对象变则c 变,但是父对象变c不会变
d = copy.deepcopy(a) #深拷贝,完全拷贝,完全独立于原对象,a变也不变
a.append(5) # 改变父对象
a[4].append('c') #改变父对象中的 ['a', 'b']子对象
>>>
>
a == [1,2, 3, 4, ['a', 'b', 'c'], 5]
b == [1,2, 3, 4, ['a', 'b', 'c'], 5]
c == [1,2, 3, 4, ['a', 'b', 'c']]
x = np.arange(0,10,1)
x = np.linspace(0,10,10,endpoint=False)
9、 函数参数列表
9.0 对象的引用调用
对象引用调用 这种说法更好,因为,传递的是可变对象时,调用者能发现被调者做出的任何更改(插入列表的元素)。
i = 5
def f(arg=i):
print(arg)
i = 6
f()
9.1 默认参数(注意和后续调用之间共享参数)
默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。例如,下面的函数会累积后续调用时传递的参数:
def f(a, L=[]): # 会默认和后续调用之间共享参数!
L.append(a)
return L
print(f(1))
print(f(2))
print(f(3))
输出结果如下:
[1]
[1, 2]
[1, 2, 3]
不想在后续调用之间共享默认值时,应以如下方式编写函数:
def f(a, L=None):
if L is None:
L = []
L.append(a)
return L
9.2 函数参数的三种调用惯例:默认参数、位置参数、关键字参数
函数传参方式:位置传参、关键字传参(不要求位置)
函数定义:
def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
----------- ---------- ----------
| | |
| Positional or keyword |
| - Keyword only
-- Positional only
def combined_example(pos_only, /, standard, *, kwd_only):
print(pos_only, standard, kwd_only)
combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given
combined_example(1, 2, kwd_only=3)
1 2 3
combined_example(1, standard=2, kwd_only=3)
1 2 3
combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() got some positional-only arguments passed as keyword arguments: 'pos_only'
9.3 任意个数形参列表
*args 形参之前,可能有若干个普通参数。*args 形参后的任何形式参数只能是仅限关键字参数,即只能用作关键字参数,不能用作位置参数:
def concat(*args, sep="/"):
return sep.join(args)
concat("earth", "mars", "venus", sep=".")
>>>'earth.mars.venus'
9.4 传递实参时,解包实参列表
在调用函数时,用 * 操作符把实参从列表或元组解包出来:
args = [3, 6]
list(range(*args))
字典可以用 ** 操作符传递关键字参数 :
def parrot(voltage, state='a stiff', action='voom'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.", end=' ')
print("E's", state, "!")
d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
9.4 Lambda表达式
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])
pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
【代码解释】:按可迭代对象pair的第二个元素,进行默认方法(升序)排序。结果输出为按首字母升序排序。。
9.5 变量作用域
10 数据结构及不同数据结构支持的方法
10.0 列表推导式和字典推导式
- 列表推导式
[(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
vec = [[1,2,3], [4,5,6], [7,8,9]]
[num for elem in vec for num in elem]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
- 嵌套的列表 推导式
matrix = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
]
[[row[i] for row in matrix] for i in range(4)]
>>>[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
# 等价于
list(zip(*matrix)) # 实参前的星号,代表解包实参列表
>>>[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
- 字典推导式
{x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
只有一个元素的元组可以通过在这个元素后添加逗号来构建(圆括号里只有一个值的话不够明确)。丑陋,但是有效。例如:
singleton
('hello',) # 特别清晰,元组中只有一个元素
x, y, z = t # 元组解包,元组t中只包含三个元素
关键字是比较简单的字符串时,直接用关键字参数指定键值对更便捷:
dict(sape=4139, guido=4127, jack=4098)
{'sape': 4139, 'guido': 4127, 'jack': 4098}
10.1 比较的优先级
-
所有比较运算符的优先级都一样,且低于任何数值运算符
-
优先级:Not>and>or :
A and not B or C 等价于 (A and (not B)) or C
。 -
a < b == c 校验 a 是否小于 b,且 b 是否等于 c
-
and 和 or 是所谓的 短路 运算符,一旦确定结果,忽略后续变量值
string1, string2, string3 = '', 'Trondheim', 'Hammer Dance'
non_null = string1 or string2 or string3
non_null
'Trondheim'
10.2 循环语句的技巧
- 列表对象中元素循环:
for i, v in enumerate(list):
- 字典对象中元素循环:
for key, value in dict.items():
- 多个列表循环,用zip将列表中元素对应匹配:
for q, a in zip(questions, answers):
- 指定循环顺序:
for i in sorted(basket):
、反序:for i in reversed(list):
- 无重复元素的循环:
for f in sorted(set(basket)):
一般来说,在循环中修改列表的内容时,创建新列表比较简单,且安全:
import math
raw_data = [56.2, float('NaN'), 51.7, 55.3, 52.5, float('NaN'), 47.8]
filtered_data = []
for value in raw_data:
if not math.isnan(value):
filtered_data.append(value)
filtered_data
[56.2, 51.7, 55.3, 52.5, 47.8]
11、 模块
脚本模块:随着程序越来越长,为了方便维护,最好把脚本拆分成多个文件。编写脚本还一个好处,不同程序调用同一个函数时,不用把函数定义复制到各个程序。
使用模块可以让不同模块的作者不必担心彼此的全局变量名一样
11.0、模块导入与命名空间
在Python中,namespace(命名空间)是一个用于存储变量和函数的容器。它将变量名映射到相应的对象,以便在程序中进行访问和操作。
Python中有多个命名空间,每个命名空间都有不同的范围和生命周期。以下是几个常见的命名空间:
-
全局命名空间:全局命名空间包含在整个程序中都可访问的变量和函数。它从程序开始执行时创建,并在程序结束后销毁。
-
局部命名空间:局部命名空间是在函数内部创建的,用于存储函数中定义的变量和函数。它在函数调用时创建,并在函数返回或执行完毕后销毁。
-
内置命名空间:内置命名空间包含Python解释器提供的内置函数和变量,如print()、len()等。它在解释器启动时创建,并在解释器关闭时销毁。
Python解释器会自动管理这些命名空间,并根据变量的作用域和生命周期来决定在哪个命名空间中查找和存储变量。当我们使用一个变量时,解释器首先在局部命名空间中查找,如果找到则使用该变量,否则继续在全局命名空间中查找,最后在内置命名空间中查找。
示例:
x = 10 # 全局命名空间
def my_function():
y = 20 # 局部命名空间
print(x) # 在函数内部可以访问全局命名空间的变量
my_function()
print(y) # 在全局命名空间中无法访问局部命名空间的变量
在上述示例中,变量x
属于全局命名空间,可以被函数my_function()
访问。而变量y
属于my_function()
的局部命名空间,在函数外部无法直接访问。
11.1 作用域和命名空间区别
作用域(Scope)和命名空间(Namespace)在Python中是相关但不同的概念。
作用域(Scope)指的是在程序中访问变量的有效范围。它定义了变量在代码中的可见性和可访问性。Python中有三种常见的作用域:
局部作用域(Local Scope):局部作用域是在函数内部定义的变量的作用域。只能在其所在的函数内部访问。
全局作用域(Global Scope):全局作用域是在函数外部定义的变量的作用域。可以在整个程序中的任意位置访问。
内置作用域(Built-in Scope):内置作用域是Python解释器提供的预定义名称的作用域,如内置函数和异常名称。
命名空间(Namespace)是存储变量和函数的容器,用于管理和组织名称。每个命名空间都有一个唯一的标识符,用于区分不同的命名空间。Python中有多个命名空间,如全局命名空间、局部命名空间和内置命名空间。
作用域和命名空间之间的关系是,作用域决定了在哪个命名空间中查找和访问变量。在Python中,变量在当前作用域内查找,如果找不到则继续在更高一级的作用域中查找,直到在全局作用域和内置作用域中找到变量为止。每个作用域都有一个对应的命名空间,变量在该命名空间中查找和存储。
总结:
作用域定义了变量的可见性和可访问性范围。
命名空间是存储变量和函数的容器,用于管理和组织名称。
作用域决定了在哪个命名空间中查找和访问变量。
12、python 作用域和命名空间
对象之间相互独立,多个名称(甚至是多个作用域内的多个名称)可以绑定到同一对象。这在其他语言中通常被称为别名
在Python中,作用域是指在程序中访问变量的有效范围。Python中有三种作用域:全局作用域(global scope),嵌套作用域(nested scope)和局部作用域(local scope)。
全局作用域是整个程序中的最外层作用域,它包含了整个程序可访问的变量和函数。在全局作用域中定义的变量和函数可以在程序的任何地方被访问到。
嵌套作用域是指在函数内部定义的作用域,它包含了函数内部可访问的变量和函数。嵌套作用域可以访问全局作用域中的变量和函数,但不能访问其他函数的嵌套作用域。
局部作用域是指在函数内部或者语句块(如if语句或for循环)内部定义的作用域,它包含了局部变量和函数。局部作用域只能在定义它们的函数、语句块内部被访问到。
在Python中,如果在一个函数内部想要修改全局变量,需要使用global
关键字来声明变量为全局变量。这样声明后,函数内部对该变量的修改会影响到全局作用域中的变量。
示例:
x = 10 # 全局变量
def modify_global():
global x # 声明x为全局变量
x += 5
modify_global()
print(x) # 输出结果为15
在上面的例子中,函数modify_global
内部使用了global
关键字来声明变量x
为全局变量,然后对x
进行了修改。最后,打印全局变量x
的值,得到结果为15。
如果在一个函数内部想要修改嵌套作用域中的变量,需要使用nonlocal
关键字来声明变量为嵌套作用域中的变量。这样声明后,函数内部对该变量的修改会影响到嵌套作用域中的变量。
示例:
def outer():
x = 10 # 嵌套作用域中的变量
def inner():
nonlocal x # 声明x为嵌套作用域中的变量
x += 5
inner()
print(x) # 输出结果为15
outer()
在上面的例子中,函数inner
内部使用了nonlocal
关键字来声明变量x
为嵌套作用域中的变量,然后对x
进行了修改。最后,打印嵌套作用域中的变量x
的值,得到结果为15。
12、return和yeild区别
比较一下两端代码中return和yeild的区别
def reverse(data):
for index in range(len(data)-1, -1, -1):
return data[index]
和代码2
def reverse(data):
for index in range(len(data)-1, -1, -1):
yeild data[index]
for char in reverse('golf'):
print(char)
f
l
o
g
【结论】return和yield的作用是不同的。
在第一个代码示例中,使用return语句会立即结束函数的执行,并将指定的值返回给调用者。在每次循环迭代中,都会执行一次return语句,但由于return会终止函数执行,所以只会返回第一个迭代的结果。因此,整个函数将只返回一个值。
- 函数中for循环的嵌套空间内,需要输出时,常常采用yeild生成迭代器。
而在第二个代码示例中,使用yield语句会将值生成为一个迭代器。每次迭代,yield会暂停函数的执行,并将当前的值返回给调用者,保持函数的状态不变。在下一次迭代调用时,函数将从上次暂停的地方继续执行,直到再次遇到yield语句。yield语句可以在每次循环迭代中执行,因此可以生成多个值。调用者可以使用迭代器逐步获取这些值。
总结起来,return语句会立即返回一个值并终止函数执行,而yield语句将值生成为迭代器,在每次迭代中暂停函数执行并返回当前值,保持函数状态不变。
13、global标准库获取文件夹下匹配的所有文件
Python 的 glob 模块提供了一种用于匹配文件路径的方法。它使用类似于正则表达式的模式匹配规则,可以方便地筛选出符合条件的文件路径。下面是 glob 模块的主要功能:
-
glob(pathname):
- 返回一个包含匹配指定模式的文件路径的列表。
- 可以使用通配符 * 匹配任意字符(除了路径分隔符)。
- 可以使用通配符 ? 匹配任意单个字符(除了路径分隔符)。
-
glob.glob(pathname):
- 返回一个包含匹配指定模式的文件路径的列表。
- 支持使用通配符 * 和 ? 进行模式匹配。
-
glob.iglob(pathname):
- 返回一个生成器,逐个返回匹配指定模式的文件路径。
- 使用时需要进行迭代,逐个获取匹配的文件路径。
-
例子:
import glob # 获取当前目录下所有的 Python 文件 python_files = glob.glob("*.py") print(python_files) # 获取当前目录及其子目录下所有的文本文件 text_files = glob.glob("**/*.txt", recursive=True) print(text_files) # 使用 iglob 进行迭代获取当前目录下的所有文件 for file in glob.iglob("*"): print(file)
以上是 glob 模块的主要功能。它可以帮助你根据文件路径的模式进行筛选和获取文件,非常方便实用。
14、re标准库进行字符串模式匹配
15、dir()内置函数查找作用域内所有属性方法
dir() 是一个内置函数,用于返回当前作用域(scope)内定义的名称列表。它可以用于查看模块、类、对象等的属性和方法。
dir() 的功能包括:
-
返回当前作用域内的所有名称列表。
- 如果在交互式解释器中调用 dir(),它将返回全局作用域内的所有名称列表。
- 如果在一个函数内部调用 dir(),它将返回该函数内的局部作用域内的所有名称列表。
-
返回模块的属性和方法。
- 如果在模块中调用 dir(),它将返回该模块内定义的所有属性和方法的名称列表。
-
返回对象的属性和方法。
- 如果在一个对象上调用 dir(),它将返回该对象内定义的所有属性和方法的名称列表。
-
当不传递参数时,dir() 默认返回当前作用域的名称列表。
-
示例:
# 返回全局作用域的名称列表 print(dir()) # 返回模块的属性和方法 import math print(dir(math)) # 返回对象的属性和方法 class MyClass: def __init__(self): self.x = 10 self.y = 20 def my_method(self): pass obj = MyClass() print(dir(obj))
通过调用 dir(),你可以查看当前作用域内的所有名称,包括变量、函数、类、模块等的名称列表。这对于了解和调试代码非常有用。
16、python的打包分发和模块管理
要分发 Python 模块,可以使用 Python 的打包工具和模块管理工具。以下是一种常见的分发模块的方法:
-
创建项目目录结构:在项目根目录下创建一个与模块同名的文件夹。将模块的代码文件和其他必要的文件(如 README、LICENSE、setup.py 等)放入该文件夹中。
-
创建 setup.py 文件:在模块文件夹中创建一个名为 setup.py 的文件,用于描述模块的元数据和打包配置。setup.py 文件是使用 Python 的打包工具 setuptools 进行模块打包和安装的入口。
-
编写 setup.py 文件:在 setup.py 文件中,使用 setuptools 的 setup() 函数来定义模块的元数据和打包配置。例如,指定模块的名称、版本号、作者、描述、依赖关系等信息。
-
执行打包命令:在命令行中切换到模块文件夹所在的目录,并执行以下命令来对模块进行打包:
python setup.py sdist
这将生成一个名为 dist 的文件夹,其中包含一个压缩文件,该文件是模块的源代码和其他文件的打包版本。
-
发布模块:将生成的压缩文件上传到 PyPI 或其他模块仓库,以便其他人可以使用 pip 或其他工具来安装你的模块。
-
安装模块:其他人可以通过运行以下命令来安装你的模块:
pip install your_module
以上是一种常见的分发 Python 模块的方法。但请注意,实际的步骤可能会因项目的特殊需求或具体的打包工具而有所不同。建议参考相关文档和教程来了解更多详细信息。
16.0 基于github的模块打包方法
要判断包中的子模块,可以使用 Python 的内置模块 os
和 importlib
。
16.1 判断主模块还是子模块
下面是一种常见的判断包中子模块的方法:
import os
import importlib
def get_submodules(package):
package_path = os.path.dirname(package.__file__)
submodules = []
for file_name in os.listdir(package_path):
if file_name.endswith(".py") and file_name != "__init__.py":
module_name = file_name[:-3]
submodule = importlib.import_module(f"{package.__name__}.{module_name}")
submodules.append(submodule)
return submodules
上述代码中,package
是一个已导入的包对象。首先,通过 os.path.dirname(package.__file__)
获取包所在的文件夹路径。然后,遍历文件夹下的所有文件,判断是否为以 .py
结尾的文件且不是 __init__.py
文件。如果是,则将其文件名去掉后缀作为模块名,然后使用 importlib.import_module()
动态导入该模块。最后,将所有导入的子模块存储在 submodules
列表中并返回。
使用示例:
import mypackage
submodules = get_submodules(mypackage)
for submodule in submodules:
print(submodule)
上述示例代码将打印出 mypackage
包中的所有子模块。
注意:这种方法只会导入包中的子模块,但不会执行子模块中的代码。如果需要执行子模块中的代码,可以在 get_submodules()
函数中适当位置添加执行代码的逻辑。
17、 python中报的错误与异常
17.1 语法错误
SyntaxError: invalid syntax
17.2 异常及异常处理
即使没有语法错误,执行时仍可能触发错误。其他类型异常有:Nameerror,Typeerror等。内置异常列出了内置异常及其含义。
Traceback (most recent call last):
17.3 try\except\else\finally
try:可能出现异常部分的代码
exception: 可以被视为捕获异常。异常处理是一种程序控制流的机制。except ExceptionType:捕获到特定异常类型后,进行异常处理。 # 异常处理代码。直接用except,可用于捕获所有类型异常。
在 Python 中,raise
是用于抛出异常的关键字。通过使用 raise
关键字,可以在程序中显式地引发异常,从而中断程序的正常执行并提供错误信息。
else,当没有错误发生时,会自动执行else语句.
finaly,当try中发生错误时,try中错误以后的代码不执行。except捕获错误对应的代码执行。再执行finally之后的代码。
try:
print('try...')
r = 10 / int('2')
print('result:', r)
except ValueError as e:
print('ValueError:', e)
except ZeroDivisionError as e:
print('ZeroDivisionError:', e)
else:
print('no error!')
finally:
print('finally...')
print('END')
raise
的一般用法是将错误类型作为参数传递给它,并在需要时提供错误消息。以下是 raise
的基本语法:
raise ErrorType("Error Message")
其中,ErrorType
是 Python 内置的或自定义的异常类,而 "Error Message"
是一个描述性的错误消息。
以下是 raise
的几个常见用法示例:
- 使用内置异常类:
raise ValueError("Invalid value")
上述代码将抛出一个 ValueError
异常,并提供错误消息 “Invalid value”。
- 自定义异常类:
class CustomError(Exception):
pass
raise CustomError("Custom error message")
上述代码将抛出一个自定义异常类 CustomError
的实例,并提供错误消息 “Custom error message”。
- 重新引发异常:
try:
# Some code that may raise an exception
except Exception as e:
# Handle the exception
raise # Reraise the same exception
*上述代码先捕获一个异常,然后在处理异常的代码块中使用 raise
关键字重新引发相同的异常。这样可以将异常传递给上一级的异常处理机制。
总结起来,raise
关键字用于显式地抛出异常,可以用于内置的异常类或自定义的异常类,并提供相应的错误消息。使用 raise
可以使代码更加具有可读性和健壮性,通过合理地抛出异常可以提供更好的错误处理和调试能力。
内容主要包含数据结构、c/c++编程以及公司总结的在开发过程中容易出错的知识点,具体包含:拷贝/构造函数、运算符/函数重载、虚函数/多态、继承、类成员访问控制、对象模型、模板、内存操作,考察点多,考试题要比面试时的笔试题难。考试形式为:选择题(含单选、多选)/判断题/填空。新员工入职一个月内,部门组织技术骨干进行c++基础培训,平时复习主要通过自学,课余时间为主,考试前部门答疑一次;考试试题主要从公司题库中抽取*
17.4 raise\logging
logging 程序打印完错误信息后会继续执行,并正常退出
raise抛出我们定义的错误类型
import logging
def foo(s):
return 10 / int(s)
def bar(s):
return foo(s) * 2
def main():
try:
bar('0')
except Exception as e:
logging.exception(e)
main()
print('END')
18、 @property 方法
@property 装饰器将 diameter 方法转化为类的属性。通过 @property,diameter 方法可以像访问属性一样被调用,而不需要使用函数调用的形式。此外,@property 装饰器还可以与 setter 方法一起使用,以实现属性的设置功能。这样,,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。并通过setter方法限制属性的规范修改。
要特别注意:属性的方法名不要和实例变量重名。例如,以下的代码是错误的:
class Student(object):
# 方法名称和实例变量均为birth:
@property
def birth(self):
return self.birth
以下为正确,其中,birth为读改属性,age为只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth