尝试执行完整操作,尽管有错误
try executes full operation, despite error
a = []
b = [1,2,'x']
try:
for i in b:
a.append(i%4)
except:
print('Not possible')
finally:
print("It's over")
print(a)
结果:
Not possible
It's over
[1, 2]
我一直认为python中的try
类似于交易; commit()
和 rollback()
在 SQL 中。所以在某种程度上,操作不会像我的情况那样 return 部分结果。例如,这是一个虚拟案例,但是 python 是否提供了一种解决方案,如果在过程中强加了错误,它不会将更改提交到列表中?所以在这个例子中它会 return 一个空白列表。
请注意,我知道如何解决这个问题,我很好奇如何用 try
& except
解决这个问题。
Try
是一个捕捉器,耐心地等待抛出异常,以便它可以捕获它并将代码发送到 Except
块。 只有 抛出异常的方式是如果它执行代码,所以不,它不会自动回滚。请注意:
Try
中的代码不知道它存在于 Try
-Except
块中。
- 因为 1.,如果有回滚,Python 将真正获取
Try
中的所有内容并存储其更改或副本。您肯定会嵌套 Try
s。如果你导入一个包,你在里面使用的一些函数里面会有Try
s。这意味着堆栈将跟踪您在块中所做的一切的多个副本。请注意,在大多数(许多?)DBMS 中,您不能在不结束第一个事务的情况下开始第二个事务。 python. 不是这种情况
如果您想回滚更改,您应该在 Except
语句的前几行中执行此操作。
在 Python 中,在 try
中发生的任何事情都将一直执行(就好像它根本不在 try/except 块中一样),直到遇到异常。在那一点上,它然后进行到 except
块。 finally
无论是否输入 except
都会被执行(也就是说,它总是会触发)。 try/except/finally
并不像 SQL 那样是原子的。
将您的操作包装在列表理解中
a = []
b = [1, 2, 'x']
try:
a += [i % 4 for i in b]
except Exception:
print("failed")
这样就不会向 a
添加任何内容,因为列表推导无法实例化。
您可以定义一个新的元数据class,这样每个 class 使用这个元数据class 就可以按照您的意思实现 try
/except
。
例如,您可以定义:
from copy import deepcopy
import types
class TryExceptRollbackMeta(type):
def __new__(cls, name, bases, attrs):
new_attrs = {}
for name, value in attrs.items():
if name == "__init__" or not isinstance(value, types.FunctionType):
new_attrs[name] = value
continue
# We know from now on that we're dealing with a non-static function
# If for some reason, a non-static method is defined without being passed self as an argument
if value.__code__.co_argcount == 0:
new_attrs[name] = value
continue
new_attrs[f"updated_{name}"] = TryExceptRollbackMeta.generate_updated_method(value)
return super().__new__(cls, name, bases, new_attrs)
@staticmethod
def generate_updated_method(func):
def updated_method(*args, **kwargs):
original = deepcopy(args[0])
try:
result = func(*args, **kwargs)
except Exception as e:
print(f"Exception {type(e)} has occured: {e}. Reverting state...")
args[0].__dict__.update(original.__dict__)
return None
return result
return updated_method
class Test(metaclass=TryExceptRollbackMeta):
def __init__(self):
self.a = []
def correct(self):
for i in [1, 2, 3]:
self.a.append(i % 4)
def incorrect(self):
for i in [1, 2, 'x']:
self.a.append(i % 4)
然后,这将像这样工作:
>>> test = Test()
>>> test.updated_correct()
>>> print(test.a)
[1, 2, 3]
>>> test.updated_incorrect()
Exception <class 'TypeError'> has occured: not all arguments converted during string formatting. Reverting state...
>>> print(test.a)
[1, 2, 3]
通过这样做,您可以完全控制您想要处理异常的方式,您可以根据异常类型采取行动,打印失败的行等...
问题是 deepcopy
可能会很长,具体取决于您的对象属性。尽管如此,仍然可以针对您想要具体恢复的属性,这只是您不知道哪个属性会受到方法影响的一般情况。
a = []
b = [1,2,'x']
try:
for i in b:
a.append(i%4)
except:
print('Not possible')
finally:
print("It's over")
print(a)
结果:
Not possible
It's over
[1, 2]
我一直认为python中的try
类似于交易; commit()
和 rollback()
在 SQL 中。所以在某种程度上,操作不会像我的情况那样 return 部分结果。例如,这是一个虚拟案例,但是 python 是否提供了一种解决方案,如果在过程中强加了错误,它不会将更改提交到列表中?所以在这个例子中它会 return 一个空白列表。
请注意,我知道如何解决这个问题,我很好奇如何用 try
& except
解决这个问题。
Try
是一个捕捉器,耐心地等待抛出异常,以便它可以捕获它并将代码发送到 Except
块。 只有 抛出异常的方式是如果它执行代码,所以不,它不会自动回滚。请注意:
Try
中的代码不知道它存在于Try
-Except
块中。- 因为 1.,如果有回滚,Python 将真正获取
Try
中的所有内容并存储其更改或副本。您肯定会嵌套Try
s。如果你导入一个包,你在里面使用的一些函数里面会有Try
s。这意味着堆栈将跟踪您在块中所做的一切的多个副本。请注意,在大多数(许多?)DBMS 中,您不能在不结束第一个事务的情况下开始第二个事务。 python. 不是这种情况
如果您想回滚更改,您应该在 Except
语句的前几行中执行此操作。
在 Python 中,在 try
中发生的任何事情都将一直执行(就好像它根本不在 try/except 块中一样),直到遇到异常。在那一点上,它然后进行到 except
块。 finally
无论是否输入 except
都会被执行(也就是说,它总是会触发)。 try/except/finally
并不像 SQL 那样是原子的。
将您的操作包装在列表理解中
a = []
b = [1, 2, 'x']
try:
a += [i % 4 for i in b]
except Exception:
print("failed")
这样就不会向 a
添加任何内容,因为列表推导无法实例化。
您可以定义一个新的元数据class,这样每个 class 使用这个元数据class 就可以按照您的意思实现 try
/except
。
例如,您可以定义:
from copy import deepcopy
import types
class TryExceptRollbackMeta(type):
def __new__(cls, name, bases, attrs):
new_attrs = {}
for name, value in attrs.items():
if name == "__init__" or not isinstance(value, types.FunctionType):
new_attrs[name] = value
continue
# We know from now on that we're dealing with a non-static function
# If for some reason, a non-static method is defined without being passed self as an argument
if value.__code__.co_argcount == 0:
new_attrs[name] = value
continue
new_attrs[f"updated_{name}"] = TryExceptRollbackMeta.generate_updated_method(value)
return super().__new__(cls, name, bases, new_attrs)
@staticmethod
def generate_updated_method(func):
def updated_method(*args, **kwargs):
original = deepcopy(args[0])
try:
result = func(*args, **kwargs)
except Exception as e:
print(f"Exception {type(e)} has occured: {e}. Reverting state...")
args[0].__dict__.update(original.__dict__)
return None
return result
return updated_method
class Test(metaclass=TryExceptRollbackMeta):
def __init__(self):
self.a = []
def correct(self):
for i in [1, 2, 3]:
self.a.append(i % 4)
def incorrect(self):
for i in [1, 2, 'x']:
self.a.append(i % 4)
然后,这将像这样工作:
>>> test = Test()
>>> test.updated_correct()
>>> print(test.a)
[1, 2, 3]
>>> test.updated_incorrect()
Exception <class 'TypeError'> has occured: not all arguments converted during string formatting. Reverting state...
>>> print(test.a)
[1, 2, 3]
通过这样做,您可以完全控制您想要处理异常的方式,您可以根据异常类型采取行动,打印失败的行等...
问题是 deepcopy
可能会很长,具体取决于您的对象属性。尽管如此,仍然可以针对您想要具体恢复的属性,这只是您不知道哪个属性会受到方法影响的一般情况。