【问题标题】:Is this type of attribute value/function checking, a code smell in Python?这种类型的属性值/函数检查是 Python 中的代码异味吗?
【发布时间】:2016-10-01 15:00:10
【问题描述】:

注意:这是 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

关于 Duck Typing 和 Tell-Not-Ask 政策的问题

我是 Python 新手,想成为一名 Python 编码员(一般来说也是一名更好的编码员)。因此,

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

我确实有另一个实现,其中tidyIgnore 类型节点中被重载。 不再进行类型检查,但父级仍需移除目标子级,并重新绑定孙子级。在这里,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

【问题讨论】:

  • IMO isIgnored() 使您的代码最容易理解。对于读者来说,拥有额外的路标比使用重复代码的第二个密集函数更容易。
  • 将其发布到 Code Review:我将有机会获得答案。
  • Crossposted 这个在 CodeReview 上。添加了 Eric 的投票实现。
  • @LaurentLAPORTE 不,这个问题不太适合 Code View。

标签: python typechecking duck-typing


【解决方案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()

【讨论】:

  • 这对tidy 方法非常有效。我会记住这个技巧的。! 题外话:除此之外,我还有一些其他函数(stringifyprint_treeemitPredicatetransform_ControlFlow 等)——它们极大地受益于整个多态性方面(基类获取通用版本,并且某些子类可能会重载它,即方法操作实际上取决于调用它的类型)。但是,在阅读了单一职责原则之后,我很担心。这是否严重违反了 SRP?
  • 我认为单一职责原则在这种规模上并不重要。它主要是关于更大规模的设计(例如模块级别),不需要应用于每个类。我猜你所有的ASTNode 子类总是会非常紧密地相互耦合。这对 SRP 来说不是什么大问题,因为如果有任何设计更改,这些类通常会立即全部更改。
  • 没错!大多数ASTNode 子类只是pass,而有些则使用新的数据属性扩展了基础。尝试将核心方法与类分开肯定需要某种类型的类型检查(例如,isIgnored()isControl() 等)。 ___ 我需要阅读更多关于整个 SOLID 和 python 习语的信息。谢谢!我已经用super替换了对基类的显式调用(@​​987654338@,tidy)。
猜你喜欢
  • 1970-01-01
  • 2020-06-28
  • 1970-01-01
  • 1970-01-01
  • 2011-05-30
  • 2018-11-23
  • 2014-11-05
  • 1970-01-01
  • 2020-03-21
相关资源
最近更新 更多