惰性加载/配置一个类以继承

2 投票
3 回答
666 浏览
提问于 2025-04-17 15:53

我创建了一个Python包,其中有一个可选的部分/类。当我使用这个可选部分(OptClass)时,我需要改变一个类(ExampleClass)的继承关系。现在我使用的代码是:

if use_option :
    _opt_class =  __import__('package.my_module', globals(), locals(), ['OptClass']).OptClass
else :
    _opt_class = object # do not use the optional class

....

class ExampleClass(base_module.BaseHandler, _opt_class):

    ....

有没有其他更“Pythonic”的方法来解决这个问题呢?比如说使用动态继承或者懒加载,或者其他什么方法……?

3 个回答

0

看起来你想根据 use_optionExampleClass 添加一些额外的功能。我建议你写两个类(一个是从另一个类派生出来的,增加了额外的功能),然后根据 use_option 使用一个通用的名字来指向其中一个类。

from package.my_module import OptClass

class SimpleExampleClass(base_module.BaseHandler):
    pass

class ExtendedExampleClass(SimpleExampleClass, OptClass):
    pass

ExampleClass = ExtendedExampleClass if use_option else SimpleExampleClass

这样一来,你就不需要在 ExtendedExampleClass 中添加额外的功能了,因为这些功能已经在 OptClass 里面了。

(也许这就是 millimoose 提到的策略模式;我也不太确定。)

0

我建议把这个模块化的设计明确地建模。你提到了OAuth2,所以为了这个例子,我假设你想添加的功能是使用这个协议进行身份验证。

那么你可能会有这样的文件:

authmodule.py

import oauth2client
# ...

class OAuth2Module(object):
    # ...

exampleclass.py

class ExampleClass(base_module.BaseHandler):
    def __init__(self, auth_module, ...):
        self.auth_module = auth_module
        # ...

    def foo(self):
        if self.auth_module:
            self.auth_module.bar()

main.py

# this is where ExampleClass is created
if use_option:
    # the optional dependency only really gets pulled in here
    from authmodule import AuthModule
    example_obj = ExampleClass(AuthModule())
else:
    example_obj = ExampleClass(None)

# ...
example_obj.foo()

显然,这个实现方式可以稍微不同,比如把ExampleClass中的一些基础代码移动到DummyAuthModule里。(具体怎么做还不太确定,因为不清楚这个可能继承的类是怎么使用的。)

2

我可能会使用一个类装饰器:

def optional_inherit(cls):
    if use_option:
        from package.my_module import OptClass
        class ExampleClassWithOptClass(cls, OptClass):
            pass
        return ExampleClassWithOptClass
    else:
        return cls

...

@optional_inherit
class ExampleClass(base_module.BaseHandler):
    ...

如果你经常这样做,可以写一个叫 optional_inherit 的函数来接收参数;在这种情况下,可以这样写 @optional_inherit(use_option, 'package.mymodule.OptClass')

撰写回答