python equivalent of functools 'partial' for a class / constructor

前端 未结 3 881
花落未央
花落未央 2020-12-09 15:57

I want to create a class that behaves like collections.defaultdict, without having the usage code specify the factory. EG: instead of

class Config(collectio         


        
相关标签:
3条回答
  • 2020-12-09 16:32

    I had a similar problem but also required instances of my partially applied class to be pickle-able. I thought I would share what I ended up with.

    I adapted fjarri's answer by peeking at Python's own collections.namedtuple. The below function creates a named subclass that can be pickled.

    from functools import partialmethod
    import sys
    
    def partialclass(name, cls, *args, **kwds):
        new_cls = type(name, (cls,), {
            '__init__': partialmethod(cls.__init__, *args, **kwds)
        })
    
        # The following is copied nearly ad verbatim from `namedtuple's` source.
        """
        # For pickling to work, the __module__ variable needs to be set to the frame
        # where the named tuple is created.  Bypass this step in enviroments where
        # sys._getframe is not defined (Jython for example) or sys._getframe is not
        # defined for arguments greater than 0 (IronPython).
        """
        try:
            new_cls.__module__ = sys._getframe(1).f_globals.get('__name__', '__main__')
        except (AttributeError, ValueError):
            pass
    
        return new_cls
    
    0 讨论(0)
  • 2020-12-09 16:34

    I don't think there's a standard method to do it, but if you need it often, you can just put together your own small function:

    import functools
    import collections
    
    
    def partialclass(cls, *args, **kwds):
    
        class NewCls(cls):
            __init__ = functools.partialmethod(cls.__init__, *args, **kwds)
    
        return NewCls
    
    
    if __name__ == '__main__':
        Config = partialclass(collections.defaultdict, list)
        assert isinstance(Config(), Config)
    
    0 讨论(0)
  • 2020-12-09 16:41

    If you actually need working explicit type checks via isinstance, you can simply create a not too trivial subclass:

    class Config(collections.defaultdict):
    
        def __init__(self): # no arguments here
            # call the defaultdict init with the list factory
            super(Config, self).__init__(list)
    

    You'll have no-argument construction with the list factory and

    isinstance(Config(), Config)
    

    will work as well.

    0 讨论(0)
提交回复
热议问题