是这种类型的属性值/函数检查,Python中的代码味道?

时间:2016-10-01 15:00:11

标签: python typechecking duck-typing

note :根据建议

,这是CodeReview上的crossposted

前提:我有一个类层次结构(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编码器(一般来说是一个更好的编码器)。因此,

我如何 Duck Type 以上?如果在对象构造之外从未触及属性/函数,那么检查属性值(igIgnoreType)/函数(isIgnored)是否会被视为 Duck Typing

我还有另一个实现,其中tidy忽略类型节点中重载。 不再进行类型检查,但父级仍然必须删除目标子级,并重新绑定孙级。这里,Ignore类型返回它们的子节点,对于叶节点,它们将是[]。但是,仍然会检查返回是否为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

1 个答案:

答案 0 :(得分: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()。< / p>