Is it a good pattern to raise exceptions in a python decorator?

Context : I have Flask routes defined for different API endpoints and each endpoint calls a controller class with certain parameters (uid, project_id, etc.).

@app.route('/sample/route', methods=['POST'])
@require_json_payload
@require_fields({
    'pid',
    'params'
})
def route_handler(arg1, arg2):
    #input filtering
    ...

    try:
        proj_cntr.sample_method(
            pid         = pid,
            ...         = ...
        )
    except ProjCntrException:
        #handle error

    #response generation
    ...

The controller (proj_cntr) is responsible for determining, say, if the given PID is valid, wether the given user is allowed to perform the action, and other business logic validation.

I noticed that I am c/pasting a lot of code like this in different controllers:

if not project_object:
    sys_logger.info('...')
    raise ProjCntrException('PID %d does not exist' % pid)

Putting these checks (validations) in decorators seems like the best thing to do. But I am not sure which error handling pattern is best practice should the validation not pass.

1) Should I create specific custom exceptions (InvalidProjException, PermissionsException, etc.) for each decorator to raise?

Concerns : The catch block of the caller method will look bloated. Also, is it good to make the assumption that the caller knows what exceptions the decorators of the callee raise?

2) The decorator passes an extra error argument to the method and the method decides what exception to raise. This way the caller method is aware what exception type to expect and handle.

Concerns : Approach seems a little over-engineered and messy.

Sorry for the verbose question. Any thoughts/ideas are greatly appreciated.


I ended up using decorators and throwing specific exceptions within them. For example:

The @validate_pid decorator raises InvalidPidException() which are caught in the except block of any consumer that calls the decorated method.

Advantages so far:

  • Controllers are much cleaner and there is a lot less code replication.
  • Fairly versatile solution, as I use these "business logic validation" decorators all over my code.
  • Disadvantages so far:

  • The decorator relies on certain keyname parameters to be passed when the decorated method is called, but some of these parameters are not used within the method itself. This can lead to some odd "dangling" parameters in the method signature.
  • I have some minor performance concerns. For example: the project validation decorator initializes a session and loads an object (Project) only to be loaded again in the decorated method itself. Just seems a little janky.

  • Option 1 : It seems logical to create a specific Exception for your decorator because this will help the user know which exception is raised, if any, and why. The type of exception should, of course, appear in the decorator docstring for the caller to be able to know what to expect. This way you're not making the assumption the user knows what exception is raised but that he has read the doc - which is more likely assumption. However if the method is called often the caller will have to handle it every time. That's part of the deal when using a library, an API or someone else's code.

    Option 2 : It does not belong to the user to determine which exception is going to be raised. The user should be aware of it via the documentation, for example. It is messy and counter intuitive in term of API design.

    Thinking about your question it made me think about the way Java works, especially if you use an IDE, when calling a method you will be warned - by the IDE and via the typing mechanism - that you should try/catch a given type of exception.

    But in your case wouldn't be possible to raise a proper HTTPException with a specific message ?

    链接地址: http://www.djcxy.com/p/24478.html

    上一篇: 返回统一的初始化参考是否有效?

    下一篇: 在Python装饰器中引发异常是否是一种很好的模式?