Является ли этот тип проверки значения атрибута/функции запахом кода в Python?
Примечание : это crossposted на CodeReview, в соответствии с рекомендацией
Предпосылка : у меня есть иерархия классов (Python), где tidy
- один из методов. Он удаляет узлы типа ASTIgnore и повторно связывает дочерние узлы этого узла с его родительским.
Целевой узел не может удалить себя и не видит своего родителя (для повторной привязки). Таким образом, удаление цели (типа ASTIgnore) произойдет у ее родителя, где родитель проверяет тип своих потомков.
Вопрос : Как это должно быть реализовано, чтобы уменьшить запах кода?
Какой из этих подходов наименее плох, или есть другие (см. Внизу)?# A)
if child.nodetype == "ASTIgnore":
# B)
if child.isIgnored():
# C)
if child.isIgnoreType:
# D)
if isinstance(child, ASTIgnore):
Где классы и tidy
выглядят следующим образом. Я удалю избыточность, основываясь на самой чистой реализации.
class ASTNode(object):
def __init__(self):
self.nodetype = self.__class__.__name__
self.isIgnoreType = False
def isIgnored(self):
return False
def tidy(self):
# Removes "Ignore" type/attribute nodes while maintaining hierarchy
if self.children:
for child in self.children:
child.tidy()
for i, child in reversed(list(enumerate(self.children))):
#--------- Is this Bad? ----------
if child.nodetype == "ASTIgnore":
#------ --------------------------
if not child.children:
# leaf node deletion
self.children.pop(i)
else:
# target node deletion + hierarchy correction
grandkids = child.children
self.children[i:i+1] = grandkids
class ASTIgnore(ASTNode):
def __init__(self):
ASTNode.__init__()
self.isIgnoreType = True
def isIgnored(self):
return True
По вопросу о типировании утки с политикой "не спрашивай" :
Я есть новичок в Python, и хотел бы быть pythonic coder (и лучшим кодером в целом). Следовательно,
Как я утка типа выше? Будет ли проверка значения атрибута (igIgnoreType
) / функции (isIgnored
) считаться утиной типизацией , если атрибут / функция никогда не затрагивается за пределами построения объекта?
У меня есть другая реализация, где tidy
перегружается в узлах типа Ignore. больше нет проверки типов , но родитель все равно должен удалить целевое дитя, и перезимовать внуков. Здесь типы Ignore возвращают свои дочерние элементы, которые будут []
для конечных узлов. Но, есть еще проверка на то, был ли возврат None
. Я уверен, что это, конечно, утка набрав , но проверка на None
и код-репликация, плохой код?
class ASTNode(object):
def tidy(self):
for i, child in reversed(list(enumerate(self.children))):
grandkids = child.tidy()
if grandkids is not None:
self.children[i:i+1] = grandkids
return None
class ASTIgnore(ASTNode):
def tidy(self):
for i, child in reversed(list(enumerate(self.children))):
grandkids = child.tidy()
if grandkids is not None:
self.children[i:i+1] = grandkids
return self.children
_edit0
Основываясь наголосовании Эрика , реализация проверки функций isIgnored()
будет выглядеть как
def tidy(self):
"""
Clean up useless nodes (ASTIgnore), and rebalance the tree
Cleanup is done bottom-top
in reverse order, so that the deletion/insertion doesn't become a pain
"""
if self.children:
# Only work on parents (non-leaf nodes)
for i, child in reversed(list(enumerate(self.children))):
# recurse, so as to ensure the grandkids are clean
child.tidy()
if child.isIgnored():
grandkids = child.children
self.children[i: i + 1] = grandkids
1 ответ:
Я думаю, что использование возвращаемого значения из метода
tidy
является хорошим способом передачи информации между вашими узлами. Вы все равно будете вызыватьtidy
для каждого из своих детей, поэтому получение возвращаемого значения, которое говорит вам, что делать с этим ребенком, упрощает весь код.Вы можете избежать повторения, используя
super
для вызова реализации базового класса из производного класса и просто изменив возвращаемое значение:class ASTIgnore(ASTNode): def tidy(self): super().tidy() # called for the side-effects, return value is overridden return self.children
Если вы используете Python 2, где
super
немного немного менее волшебно, чем в Python 3, вам нужно будет использоватьsuper(ASTIgnore, self)
вместоsuper()
.