эквивалент python частичной части functools для класса/конструктора
Я хочу создать класс, который ведет себя как collection.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)
Ответы
Ответ 1
Я не думаю, что существует стандартный метод для этого, но если вам это нужно часто, вы можете просто создать свою небольшую функцию:
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
Если вам действительно нужно работать с явным проверкой типов через 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)
также будет работать.
Ответ 3
У меня была похожая проблема, но я также требовал, чтобы экземпляры моего частично примененного класса были засолены. Я думал, что поделюсь тем, чем я закончил.
Я адаптировал ответ fjarri, посмотрев на собственный 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