Я пишу функцию build_hierarchy_config
внутри класса 'P', которая вызывает рекурсивно recursive_build_hierarchy_config
.Эта функция, вызываемая в экземпляре P1, выполняет итерацию по сложной структуре dict (атрибут «config») и сравнивает все элементы с таким же атрибутом «config» из другого экземпляра «P» (называемого P2), который является родительским для P1.Логика сравнения разбита на несколько функций:
- рекурсивный вызов
recursive_build_hierarchy_config
- сравнение кодов (перебор сложной структуры) в
get_more_strict_config
- сравнение одного элемента в
cmp_config_item
Таким образом, код выглядит следующим образом:
import decimal
from typing import Optional
from attrdict import AttrDict
class Config(AttrDict):
"""Represent P config."""
def __init__(self, some_dict):
super(Config, self).__init__(some_dict)
class P(dict):
"""Represents P object."""
def build_hierarchy_config(self,
hierarchy_config_type: str):
"""Fill the hierarchy_config or parent_hierarchy_config attribute."""
def cmp_config_item(slave: Optional[decimal.Decimal],
master: Optional[decimal.Decimal],
cmp_func: str) -> Optional[decimal.Decimal]:
"""Compare two numbers with custom 'None' handling."""
if cmp_func not in ['min', 'max']:
raise Exception(
f'comparison function {cmp_func} not supported')
if slave is not None and master is not None:
return eval(cmp_func + '(' + str(slave) + ',' +
str(master) + ')')
elif slave is None and master is None:
return None
elif slave is None:
return master
elif master is None:
return slave
def get_more_strict_config(config, parent_config) -> Config:
"""Combine configs and return most strict combinaton of values."""
# some logic with few for and if/else
return config
def recursive_build_hierarchy_config(pieceId: Optional[str]):
if pieceId is None:
return None
else:
p = P()
parent_config = recursive_build_hierarchy_config(
p.parentPieceId)
return get_more_strict_config(p.config, parent_config)
if hierarchy_config_type == 'hierarchy_config':
self.hierarchyConfig = recursive_build_hierarchy_config(
self.id)
elif hierarchy_config_type == 'parent_hierarchy_config':
self.parenthierarchyConfig = recursive_build_hierarchy_config(
self.parentPieceId)
, но затем выполнение flake8
дает мне ошибку:
C901 'P.build_hierarchy_config' is too complex (12)
Это означает, что сложность для build_hierarchy_config
суммирует сложность для всех подфункций.
Опция 1 Я легко могу это исправить, перемещая функцию cmp_config_item
из build_hierarchy_config
пространства имен (не уверен, что это правильная формулировка) и расположение в основной области:
import decimal
from typing import Optional
from attrdict import AttrDict
class Config(AttrDict):
"""Represent P config."""
def __init__(self, some_dict):
super(Config, self).__init__(some_dict)
class P(dict):
"""Represents P object."""
def build_hierarchy_config(self,
hierarchy_config_type: str):
"""Fill the hierarchy_config or parent_hierarchy_config attribute."""
def get_more_strict_config(config, parent_config) -> Config:
"""Combine configs and return most strict combinaton of values."""
# some logic with few for and if/else
return config
def recursive_build_hierarchy_config(pieceId: Optional[str]):
if pieceId is None:
return None
else:
p = P()
parent_config = recursive_build_hierarchy_config(
p.parentPieceId)
return get_more_strict_config(p.config, parent_config)
if hierarchy_config_type == 'hierarchy_config':
self.hierarchyConfig = recursive_build_hierarchy_config(
self.id)
elif hierarchy_config_type == 'parent_hierarchy_config':
self.parenthierarchyConfig = recursive_build_hierarchy_config(
self.parentPieceId)
def cmp_config_item(slave: Optional[decimal.Decimal],
master: Optional[decimal.Decimal],
cmp_func: str) -> Optional[decimal.Decimal]:
"""Compare two numbers with custom 'None' handling."""
if cmp_func not in ['min', 'max']:
raise Exception(
f'comparison function {cmp_func} not supported')
if slave is not None and master is not None:
return eval(cmp_func + '(' + str(slave) + ',' +
str(master) + ')')
elif slave is None and master is None:
return None
elif slave is None:
return master
elif master is None:
return slave
Теперь flake8 больше не жалуется.Но это делает функцию cmp_config_item
доступной для всей области видимости модуля и делает код менее структурированным (нет никаких признаков того, что эта функция предназначена для использования в выбранной области видимости.
Опция 2 Я могу отключить это сообщение для функции, добавив # noqa: ignore=C901
после def build_hierarchy_config
, как описано в другом потоке . Но это подавляет проверку самой функции build_hierarchy_config
, поэтому не будет принято.
Оба решения - компромиссы. Я не специалист по ООП, поэтому возникает вопрос: существует ли какой-либо правильный / лучший способ организовать те подпрограммы, которые бы соответствовали правилам объектно-ориентированного программирования