简体   繁体   中英

How to generate __init__ for class with custom descriptors in Python?

I have created a custom descriptor for configuration options that can be used to create classes like this:

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

The real instances contain a lot more properties. The problem is that I would like to have an __init__ that allows me to initialise any properties I want upon construction, like this:

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

Since in practice there are many more properties, this becomes hard to maintain, and since the pattern here is very regular, I am wondering if there is a way to automatically provide this functionality.

My first draft was this class:

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)

This does what I want, but in some cases even more, since it also initialises attributes that are not configuration properties, which might cause problems with other base classes. I don't know how to fix that. type(getattr(self, key)) does not yield ConfigurationProperty , but rather the type of the current value.

Also, it treats all kwargs as configuration properties to be initialised. Some of them might be arguments for other base class constructors though, so I'd need to be able to distinguish that.

So, is there a way to provide this functionality in a generic way and safe way?

Simply use 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)

On the other hand, to automate this process even further, one can introduce a mapping configuration parameter -> type and create and fill the properties dynamically:

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])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM