这种类型的属性 value/function 检查是 Python 中的代码味道吗?
Is this type of attribute value/function checking, a code smell in Python?
注意:根据建议
,这是 CodeReview 上的crossposted
前提:我有一个class层次结构(Python),其中tidy
是方法之一。它删除类型为 ASTIgnore 的节点,并将该节点的子节点重新绑定到其父节点。
目标节点无法删除自身,也不会查看其父节点(用于重新绑定)。因此,目标(ASTIgnore 类型)的删除将发生在其父级,其中父级 检查其子级的类型。
问题:这需要如何实现以减少代码异味?
这些方法中哪一个最不坏,或者还有其他方法(见底部)?
# A)
if child.nodetype == "ASTIgnore":
# B)
if child.isIgnored():
# C)
if child.isIgnoreType:
# D)
if isinstance(child, ASTIgnore):
其中,classes 和 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
关于使用 Tell-Not-Ask 策略的 Duck Typing 问题:
我是 Python 的新手,想成为一名 Pythonic 编码员(并且总体上是一名更好的编码员)。因此,
我如何Duck Type上面的?如果 attribute/function 在对象构造之外从未被触及,是否会检查属性值(igIgnoreType
)/函数(isIgnored
)被视为 Duck Typing?
我有另一个实现,其中 tidy
在 Ignore 类型节点中过载。 不再进行类型检查,但父对象仍然需要删除目标子对象,并重新绑定孙子对象。在这里,Ignore 类型 return 它们的子节点,对于叶节点来说是 []
。但是,仍然会检查 return 是否为 None
。我确定这肯定是 Duck Typing,但正在检查 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
根据 Eric's 投票,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
我认为使用 tidy
方法中的 return 值是在节点之间传递信息的好方法。无论如何,您将在每个 children 上调用 tidy
,因此获得一个 return 值告诉您如何处理 child 会使整个代码更简单.
您可以通过使用 super
从派生的 class 调用基础 class 的实现并仅更改 return 值来避免重复自己:
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()
.
注意:根据建议
,这是 CodeReview 上的crossposted前提:我有一个class层次结构(Python),其中tidy
是方法之一。它删除类型为 ASTIgnore 的节点,并将该节点的子节点重新绑定到其父节点。
目标节点无法删除自身,也不会查看其父节点(用于重新绑定)。因此,目标(ASTIgnore 类型)的删除将发生在其父级,其中父级 检查其子级的类型。
问题:这需要如何实现以减少代码异味?
这些方法中哪一个最不坏,或者还有其他方法(见底部)?
# A)
if child.nodetype == "ASTIgnore":
# B)
if child.isIgnored():
# C)
if child.isIgnoreType:
# D)
if isinstance(child, ASTIgnore):
其中,classes 和 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
关于使用 Tell-Not-Ask 策略的 Duck Typing 问题:
我是 Python 的新手,想成为一名 Pythonic 编码员(并且总体上是一名更好的编码员)。因此,
我如何Duck Type上面的?如果 attribute/function 在对象构造之外从未被触及,是否会检查属性值(igIgnoreType
)/函数(isIgnored
)被视为 Duck Typing?
我有另一个实现,其中 tidy
在 Ignore 类型节点中过载。 不再进行类型检查,但父对象仍然需要删除目标子对象,并重新绑定孙子对象。在这里,Ignore 类型 return 它们的子节点,对于叶节点来说是 []
。但是,仍然会检查 return 是否为 None
。我确定这肯定是 Duck Typing,但正在检查 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
根据 Eric's 投票,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
我认为使用 tidy
方法中的 return 值是在节点之间传递信息的好方法。无论如何,您将在每个 children 上调用 tidy
,因此获得一个 return 值告诉您如何处理 child 会使整个代码更简单.
您可以通过使用 super
从派生的 class 调用基础 class 的实现并仅更改 return 值来避免重复自己:
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()
.