首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何根据传递给__init__的参数实例化特定的子类?

如何根据传递给__init__的参数实例化特定的子类?
EN

Stack Overflow用户
提问于 2012-09-25 22:27:01
回答 3查看 332关注 0票数 0

我从python2.7打包了一个基于XML的远程API。该应用编程接口通过发送一个<statusCode>元素和一个<statusDescription>元素抛出错误。现在,我捕获了这个条件,并引发了一个异常类型。类似于:

代码语言:javascript
运行
复制
class ApiError(Exception):
    pass

def process_response(response):
    if not response.success:
        raise ApiError(response.statusDescription)

这很好用,除了我现在想以一种更复杂的方式处理错误。因为我有statusCode元素,所以我想根据statusCode引发ApiError的一个特定子类。实际上,我希望我的包装器像这样扩展:

代码语言:javascript
运行
复制
class ApiError(Exception):
    def __init__(self, description, code):
        # How do I change self to be a different type?
        if code == 123:
            return NotFoundError(description, code)
        elif code == 456:
            return NotWorkingError(description, code)

class NotFoundError(ApiError):
    pass

class NotWorkingError(ApiError):
    pass

def process_response(response):
    if not response.success:
        raise ApiError(response.statusDescription, response.statusCode)

def uses_the_api():
    try:
        response = call_remote_api()
    except NotFoundError, e:
        handle_not_found(e)
    except NotWorkingError, e:
        handle_not_working(e)

将特定的statusCode绑定到特定的子类的机制很简单,但我想要的是将其隐藏在ApiError中的某个地方,具体地说,除了传入statusCode值之外,我不想更改process_response。

我研究过元类,但不确定它们是否对这种情况有帮助,因为__new__获取的是写时参数,而不是运行时参数。同样,绕过__init__也无济于事,因为它不打算返回实例。那么,如何根据传递给__init__的参数实例化特定的子类呢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-25 22:30:24

创建一个函数,该函数将根据描述生成请求的错误类。如下所示:

代码语言:javascript
运行
复制
def get_valid_exception(description, code):
    if code == 123:
        return NotFoundError(description, code)
    elif code == 456:
        return NotWorkingError(description, code)

根据您的要求和将来的更改,您可以使用不同的参数创建异常或执行任何其他操作,而不会影响使用此函数的代码。

然后在你的代码中,你可以这样使用它:

代码语言:javascript
运行
复制
def process_response(response):
    if not response.success:
        raise get_valid_exception(response.statusDescription, response.statusCode)
票数 1
EN

Stack Overflow用户

发布于 2012-09-25 22:32:44

工厂函数将更容易理解。使用字典将代码映射到异常类:

代码语言:javascript
运行
复制
exceptions = {
    123: NotFoundError,
    456: NotWorkingError,
    # ...
}

def exceptionFactory(description, code):
    return exceptions[code](description, code)
票数 3
EN

Stack Overflow用户

发布于 2012-09-25 22:29:46

您可以创建一系列子类,并使用基类的__new__作为子类的工厂。然而,这在这里可能有些夸张;您可以只创建一个简单的工厂方法或类。但是,如果您想从另一个角度了解情况,可以为基类创建一个元类,在创建子类时,它会自动将子类添加到工厂中。类似于:

代码语言:javascript
运行
复制
class ApiErrorRegistry(type):

    code_map = {}

    def __new__(cls, name, bases, attrs):

        try:
            mapped_code = attrs.pop('__code__')
        except KeyError:
            if name != 'ApiError':
                raise TypeError('ApiError subclasses must define a __code__.')
            mapped_code = None
        new_class = super(ApiErrorRegistry, cls).__new__(cls, name, bases, attrs)
        if mapped_code is not None:
            ApiErrorRegistry.code_map[mapped_code] = new_class
        return new_class

def build_api_error(description, code):

    try:
        return ApiErrorRegistry.code_map[code](description, code)
    except KeyError:
        raise ValueError('No error for code %s registered.' % code)


class ApiError(Exception):

    __metaclass__ = ApiErrorRegistry


class NotFoundError(ApiError):

    __code__ = 123


class NotWorkingError(ApiError):

    __code__ = 456


def process_response(response):

    if not response.success:
        raise build_api_error(response.statusDescription, response.statusCode)

def uses_the_api():
    try:
        response = call_remote_api()
    except ApiError as e:
        handle_error(e)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12585115

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档