可以从调用函数的地方访问的状态代码有哪些替代方案?例外? (Python, 姜戈)
What are alternatives to status codes that can be accessed from where a function is called? Exceptions? (Python, Django)
我想在函数中引发异常,然后检查其他地方(在 Django 视图和我的单元测试中)是否引发异常。下面的代码使用了状态代码,并且它有效。但是我不知道如何用例外做同样的事情——每个人似乎都同意,这是做这种事情的正确方法。
使用自定义错误消息对我来说很重要。不是打印它们,而是在代码中检测和使用它们(主要是用 Django 消息将它们转发给最终用户)。
如果在 utils.add_foo
中出现异常,我不知道如何检查 add_foo_view
。
在单元测试中,我尝试了 <a href="https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertWarnsRegex" rel="nofollow noreferrer">assertWarnsRegex</a>(Warning, 'blah went wrong')
之类的操作,但没有费心检查消息是否正确其实是一样的
views.py:
from django.contrib import messages
from .utils import add_foo
def add_foo_view(request):
if request.method == 'POST':
status = add_foo(request.POST['bar'])
if not status == 'Bar was added.':
messages.error(request, status)
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')
utils.py:
def add_foo(bar):
if not spamifyable(bar):
return 'Bar can not be spamified.'
try:
eggs = Egg.objects.get(baz=bar)
except:
return 'Bar has no eggs.'
do_things(bar)
return 'Bar was added.'
tests.py:
def test_bar_without_eggs(self):
status = add_foo(eggless_bar)
assertEqual(status, 'Bar has no eggs.')
我使用 Python 3.5.2 和 Django 1.11.4。
编辑: 我实际上不确定异常是否是此处的正确选择。我经常读到,例外只适用于意想不到的事情。但是我在这里遇到的情况是用户的错误输入,这是意料之中的。 所以我的问题不是真正的如何使它有例外,而是如何使它成为正确的 pythonic 方式。 无论如何我希望验证在单独的 utils
地方(普通 Python,没有 Django),而不是在视图中。
您可以使用 'raise' 语句引发异常,例如:
raise Exception("Bar has no eggs.")
您还可以通过继承内置异常 class 来创建自定义异常,例如:
class MyException(Exception):
pass
那么你可以这样做:
raise MyException("Bar has no eggs.")
并且您可以使用 try-except 块捕获引发的异常:
try:
function_that_raises_exception(args)
except MyException:
function_to _handle_exception(args)
所以在你的views.py中你可以这样做:
from django.contrib import messages
from .utils import add_foo, MyException
def add_foo_view(request):
if request.method == 'POST':
try:
add_foo(request.POST['bar'])
except MyException as e:
messages.error(request, str(e))
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')
由 add_foo
编辑的 return 明确的成功消息可能看起来更清晰,但可能不是一个好主意。该函数不需要 return 任何东西。如果没有抛出异常,则可以认为是成功的。
我可以创建自定义例外并在 __init__
中添加 message
属性。这样它就可以作为 e.message
访问,在我的例子中,它将被转发到 views.py
.
中的索引页面
utils.py
class AddFooException(Exception):
def __init__(self, message):
self.message = message
def add_foo(bar):
if not spamifyable(bar):
raise AddFooException('Bar can not be spamified.')
try:
eggs = Egg.objects.get(baz=bar)
except:
raise AddFooException('Bar has no eggs.')
do_things(bar)
views.py
from django.contrib import messages
from .utils import add_foo, AddFooException
def add_foo_view(request):
if request.method == 'POST':
bar = request.POST['bar']
try:
add_foo(bar)
except AddFooException as e:
messages.error(request, e.message)
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')
我想在函数中引发异常,然后检查其他地方(在 Django 视图和我的单元测试中)是否引发异常。下面的代码使用了状态代码,并且它有效。但是我不知道如何用例外做同样的事情——每个人似乎都同意,这是做这种事情的正确方法。
使用自定义错误消息对我来说很重要。不是打印它们,而是在代码中检测和使用它们(主要是用 Django 消息将它们转发给最终用户)。
如果在 utils.add_foo
中出现异常,我不知道如何检查 add_foo_view
。
在单元测试中,我尝试了 <a href="https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertWarnsRegex" rel="nofollow noreferrer">assertWarnsRegex</a>(Warning, 'blah went wrong')
之类的操作,但没有费心检查消息是否正确其实是一样的
views.py:
from django.contrib import messages
from .utils import add_foo
def add_foo_view(request):
if request.method == 'POST':
status = add_foo(request.POST['bar'])
if not status == 'Bar was added.':
messages.error(request, status)
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')
utils.py:
def add_foo(bar):
if not spamifyable(bar):
return 'Bar can not be spamified.'
try:
eggs = Egg.objects.get(baz=bar)
except:
return 'Bar has no eggs.'
do_things(bar)
return 'Bar was added.'
tests.py:
def test_bar_without_eggs(self):
status = add_foo(eggless_bar)
assertEqual(status, 'Bar has no eggs.')
我使用 Python 3.5.2 和 Django 1.11.4。
编辑: 我实际上不确定异常是否是此处的正确选择。我经常读到,例外只适用于意想不到的事情。但是我在这里遇到的情况是用户的错误输入,这是意料之中的。 所以我的问题不是真正的如何使它有例外,而是如何使它成为正确的 pythonic 方式。 无论如何我希望验证在单独的 utils
地方(普通 Python,没有 Django),而不是在视图中。
您可以使用 'raise' 语句引发异常,例如:
raise Exception("Bar has no eggs.")
您还可以通过继承内置异常 class 来创建自定义异常,例如:
class MyException(Exception):
pass
那么你可以这样做:
raise MyException("Bar has no eggs.")
并且您可以使用 try-except 块捕获引发的异常:
try:
function_that_raises_exception(args)
except MyException:
function_to _handle_exception(args)
所以在你的views.py中你可以这样做:
from django.contrib import messages
from .utils import add_foo, MyException
def add_foo_view(request):
if request.method == 'POST':
try:
add_foo(request.POST['bar'])
except MyException as e:
messages.error(request, str(e))
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')
由 add_foo
编辑的 return 明确的成功消息可能看起来更清晰,但可能不是一个好主意。该函数不需要 return 任何东西。如果没有抛出异常,则可以认为是成功的。
我可以创建自定义例外并在 __init__
中添加 message
属性。这样它就可以作为 e.message
访问,在我的例子中,它将被转发到 views.py
.
utils.py
class AddFooException(Exception):
def __init__(self, message):
self.message = message
def add_foo(bar):
if not spamifyable(bar):
raise AddFooException('Bar can not be spamified.')
try:
eggs = Egg.objects.get(baz=bar)
except:
raise AddFooException('Bar has no eggs.')
do_things(bar)
views.py
from django.contrib import messages
from .utils import add_foo, AddFooException
def add_foo_view(request):
if request.method == 'POST':
bar = request.POST['bar']
try:
add_foo(bar)
except AddFooException as e:
messages.error(request, e.message)
return render(request, 'index.html')
else:
return render(request, 'add_foo.html')