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

妖精的绣舞 提交于 2019-11-30 01:53:12

问题


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

class Config(collections.defaultdict):
    pass

this:

Config = functools.partial(collections.defaultdict, list)

This almost works, but

isinstance(Config(), Config)

fails. I am betting this clue means there are more devious problems deeper in also. So is there a way to actually achieve this?

I also tried:

class Config(Object):
    __init__ = functools.partial(collections.defaultdict, list)

回答1:


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)



回答2:


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.




回答3:


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


来源:https://stackoverflow.com/questions/38911146/python-equivalent-of-functools-partial-for-a-class-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!