33

我想创建一个行为类似于 collections.defaultdict 的类,而无需使用代码指定工厂。EG:代替

class Config(collections.defaultdict):
    pass

这个:

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

这几乎可以工作,但是

isinstance(Config(), Config)

失败。我敢打赌,这条线索意味着更深层次的狡猾问题。那么有没有办法真正实现这一点?

我也试过:

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

5 回答 5

30

我不认为有一个标准的方法可以做到这一点,但如果你经常需要它,你可以把你自己的小函数放在一起:

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)
于 2016-08-12T06:33:05.990 回答
9

我有一个类似的问题,但也需要我的部分应用类的实例是可腌制的。我想我会分享我最终得到的结果。

我通过查看 Python 自己的collections.namedtuple. 下面的函数创建一个可以腌制的命名子类。

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
于 2019-09-21T10:26:11.537 回答
9

如果您确实需要通过 进行显式类型检查isinstance,您可以简单地创建一个不太简单的子类:

class Config(collections.defaultdict):

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

您将使用列表工厂进行无参数构造,并且

isinstance(Config(), Config)

也会起作用。

于 2016-08-12T06:33:45.630 回答
5

至少在 Python 3.8.5 中,它只适用于functools.partial

import functools

class Test:
    def __init__(self, foo):
        self.foo = foo
    
PartialClass = functools.partial(Test, 1)

instance = PartialClass()
instance.foo
于 2021-04-16T14:47:09.800 回答
0

可以使用*argsand **kwargs

class Foo:
    def __init__(self, a, b):
        self.a = a
        self.b = b

    def printy(self):
        print("a:", self.a, ", b:", self.b)

class Bar(Foo):
    def __init__(self, *args, **kwargs):
        return super().__init__(*args, b=123, **kwargs)

if __name__=="__main__":
    bar = Bar(1)
    bar.printy()  # Prints: "a: 1 , b: 123"
于 2021-08-01T18:39:11.960 回答