【问题标题】:How to generate __init__ for class with custom descriptors in Python?如何在 Python 中为具有自定义描述符的类生成 __init__?
【发布时间】:2015-05-09 12:37:41
【问题描述】:

我为配置选项创建了一个自定义描述符,可用于创建这样的类:

class Configuration(SomeSpecificBackend):
    basedir = ConfigurationProperty('basedir', int)
    logfile = ConfigurationProperty('logfile', Path)

真实的实例包含更多的属性。问题是我想要一个__init__,它允许我在构造时初始化我想要的任何属性,如下所示:

    def __init__(self, basdir=None, logfile=None):
        if basedir is not None:
            self.basedir = basedir
        if logfile is not None:
            self.logfile = logfile

由于实际上有更多的属性,这变得难以维护,并且由于这里的模式非常规则,我想知道是否有一种方法可以自动提供此功能。

我的初稿是这门课:

class ConfigurationBase():
    def __init__(self, **kwargs):
        super().__init__()
        for key, value in kwargs.items():
            if hasattr(self, key): # don't create new attributes
                setattr(self, key, value)

这是我想要的,但在某些情况下甚至更多,因为它还会初始化不是配置属性的属性,这可能会导致其他基类出现问题。我不知道如何解决这个问题。 type(getattr(self, key)) 不会产生 ConfigurationProperty,而是当前值的类型。

此外,它将所有kwargs 视为要初始化的配置属性。其中一些可能是其他基类构造函数的参数,所以我需要能够区分这一点。

那么,有没有办法以通用的方式和安全的方式提供这个功能呢?

【问题讨论】:

  • ConfigurationProperty 是如何实现的?因为显然发生了一些神奇的事情,将返回值从getattr() 转换了。您还可以查看__getattr__()__getattribute__() 之间的区别,也可以直接致电__getattr__()
  • ConfigurationProperty 是使用descriptor protocol 实现的。所以是的,有魔法,但那是 Python 的内置魔法。
  • 在这种情况下,原始的ConfigurationProperty 对象仍应位于__class__.__dict__ 中(没有魔法),并且可以检查该类型。

标签: python descriptor


【解决方案1】:

只需使用locals:

def __init__(self, basdir=None, logfile=None):
    for name, value in locals().items():
        if values is not None and hasattr(self, name):
            setattr(self, name, value)

另一方面,为了进一步自动化这个过程,可以引入映射配置参数 -> 类型并动态创建和填充属性:

class Configuration(SomeSpecificBackend):
    CONFIGURATION_PROPERTIES = {
        'basedir': int,
        'logfile': Path,
    }
    for name, type_ in CONFIGURATION_PROPERTIES.items():
        locals()[name] = ConfigurationProperty(name, type_)

    def __init__(self, **properties):
        for name in self.CONFIGURATION_PROPERTIES:
            if name in properties:
                setattr(self, name, properties[name])

【讨论】:

  • 谢谢,这大大减少了手动工作,但它仍然需要我列出每个属性两次(一次在类中,一次在初始化程序的参数列表中)。也应该有办法解决这个问题。
  • 通常情况下,最好不要在界面中添加太多魔法。使用**kwargs 更难看出允许使用哪些参数。
  • 我同意,但在这种情况下,允许的参数列表实际上就在 __init__ 函数的正上方。
  • Modifying locals is undefined. 此外,不能保证 Python 不会将东西注入到 locals 中,或者这完全可以正常工作。
  • @BjörnPollex 如果你这样做help(Configuration) 会怎样?当然,您仍然希望显示调试信息。
猜你喜欢
  • 1970-01-01
  • 2022-01-08
  • 1970-01-01
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多