Основной вариант использования, для которого я использую это, - предотвращение распространения небольших модулей и для предотвращения загрязнения пространства имен, когда отдельные модули не нужны. Если я расширяю существующий класс, но этот существующий класс должен ссылаться на другой подкласс, который всегда должен быть связан с ним. Например, у меня может быть модуль utils.py
, в котором есть много вспомогательных классов, которые не обязательно связаны друг с другом, но я хочу усилить связь для некоторых этих вспомогательных классов. Например, когда я реализую https://stackoverflow.com/a/8274307/2718295
utils.py
import json, decimal
class Helper1(object):
pass
class Helper2(object):
pass
# Here is the notorious JSONEncoder extension to serialize Decimals to JSON floats
class DecimalJSONEncoder(json.JSONEncoder):
class _repr_decimal(float): # Because float.__repr__ cannot be monkey patched
def __init__(self, obj):
self._obj = obj
def __repr__(self):
return '{:f}'.format(self._obj)
def default(self, obj): # override JSONEncoder.default
if isinstance(obj, decimal.Decimal):
return self._repr_decimal(obj)
# else
super(self.__class__, self).default(obj)
# could also have inherited from object and used return json.JSONEncoder.default(self, obj)
Тогда мы можем:
>>> from utils import DecimalJSONEncoder
>>> import json, decimal
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234'),
... 'key2':'strKey2Value'}, cls=DecimalJSONEncoder)
{"key2": "key2_value", "key_1": 1.12345678901234}
Конечно, мы могли бы вообще отказаться от наследования json.JSONEnocder
и просто переопределить default ():
import decimal, json
class Helper1(object):
pass
def json_encoder_decimal(obj):
class _repr_decimal(float):
...
if isinstance(obj, decimal.Decimal):
return _repr_decimal(obj)
return json.JSONEncoder(obj)
>>> json.dumps({'key1': decimal.Decimal('1.12345678901234')}, default=json_decimal_encoder)
'{"key1": 1.12345678901234}'
Но иногда просто для соглашения, вы хотите, чтобы utils
состоял из классов для расширяемости.
Вот еще один вариант использования: я хочу фабрику для изменяемых файлов в моем OuterClass без необходимости вызывать copy
:
class OuterClass(object):
class DTemplate(dict):
def __init__(self):
self.update({'key1': [1,2,3],
'key2': {'subkey': [4,5,6]})
def __init__(self):
self.outerclass_dict = {
'outerkey1': self.DTemplate(),
'outerkey2': self.DTemplate()}
obj = OuterClass()
obj.outerclass_dict['outerkey1']['key2']['subkey'].append(4)
assert obj.outerclass_dict['outerkey2']['key2']['subkey'] == [4,5,6]
Я предпочитаю этот шаблон над @staticmethod
декоратором, который вы иначе использовали бы для заводской функции.