2016-10-01 7 views
2

참고 :이 전제 이 유형의 속성 값/함수 검사는 파이썬에서 코드 냄새가 있습니까?

추천

에 따라, 코드 검토에 crossposted이다 : 나는 (파이썬) 클래스 계층 구조를 가지고 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 

에게-하지-요청 정책 : 나는 파이썬에 새로운 오전 및 파이썬 코더 (그리고 일반적으로 더 나은 코더 싶습니다

을). 따라서

어떻게해야합니까? 오리 유형? 특성 값 (igIgnoreType)/기능 (isIgnored)을 검사하는 것이 으로 간주 될 것입니다. 특성/기능이 개체 생성을 넘어 절대로 만지지 않는다면 Duck Typing으로 간주됩니까?

tidy이 오버로드 된 경우 노드를 무시합니다. 형식 검사가 더 이상 없지만 부모는 여전히 대상 자식을 제거하고 손자를 다시 바인딩해야합니다. 여기에서 Ignore 형식은 자식을 반환하며 리프 노드의 경우 []이됩니다. 그러나 반환이 None인지 여전히 확인합니다. 나는 이것이 확실히 오리가이라고 타이핑하지만, None과 코드 복제, 나쁜 코드를 체크하고있는 것입니까? Eric's 투표를 바탕으로 _edit0

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 

가하는 isIgnored() 기능 검사 구현 내가 tidy 메서드에서 반환 값을 사용하여 생각

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 
+0

IMO'isIgnored()'는 코드를 가장 이해하기 쉽게 만듭니다. 그 여분의 푯말을 갖는 것이 반복 된 코드를 가진 두 번째 밀집된 기능보다 독자에게 더 쉽습니다. –

+0

코드 검토에 게시 : 답변을 얻을 수있는 기회를 갖게됩니다. –

+0

[Crossposted] (http://codereview.stackexchange.com/questions/142983/is-this-type-of-attribute-value-function-checking-a-code-smell-in-python)이 코드 검토. Eric의 투표 구현을 추가했습니다. –

답변

1

과 같을 것이다 것은 좋은 방법입니다 노드간에 정보를 전달할 수 있습니다.어쨌든 각 자식에 tidy을 호출 할 것이므로 그 자식에 대한 처리를 알려주는 반환 값을 얻으면 전체 코드를 더 간단하게 만듭니다.

당신은 반환 값을 파생 클래스에서 기본 클래스의 구현을 호출하는 super를 사용하여, 그냥 변경하여 자신을 반복하지 않도록 할 수 있습니다

class ASTIgnore(ASTNode): 
    def tidy(self): 
     super().tidy() # called for the side-effects, return value is overridden 
     return self.children 

당신이 super이 조금 파이썬 2를 사용하는 경우 파이썬 3보다 조금 덜 마법적이고, super() 대신 super(ASTIgnore, self)을 사용해야합니다.

+0

이것은'tidy' 메쏘드에서 아주 잘 작동합니다. 이 기술을 염두에 두겠습니다. ** 대치 : ** 그 외에도, 나는 다형성 측면에서 큰 이득을 얻는 몇 가지 다른 함수 ('stringify','print_tree','emitPredicate','transform_ControlFlow' 등)를 가지고 있습니다. 버전과 일부 하위 클래스가 오버로드 될 수 있습니다. 즉, 메소드 조작은 실제로이를 호출하는 유형에 따라 다릅니다. 그러나 Single Responsibility Principle에 대해 읽은 후에는 걱정됩니다. 이것은 SRP의 심각한 위반입니까? –

+0

필자는 Single Responsibility Principle이이 규모에서 중요하지 않다고 생각합니다. 이는 대개 대규모 디자인 (예 : 모듈 수준)에 관한 것이므로 모든 클래스에 적용 할 필요가 없습니다. 나는 당신의 모든 'ASTNode' 서브 클래스가 항상 서로 밀접하게 결합 될 것이라고 추측 할 수 있습니다. 디자인 변경이있을 경우 일반적으로 수업이 모두 한꺼번에 변경되므로 SRP의 경우 큰 문제는 아닙니다. – Blckknght

+0

맞습니다! 대부분의 ASTNode 서브 클래스는 단순히'pass'이며 일부는 새로운 데이터 속성으로베이스를 확장합니다. 핵심 메소드와 클래스를 분리하려고 시도 할 때 가장 확실하게 _ 유형 선택 검사가 필요합니다 (예 :'isIgnored()','isControl()'등). ** ___ ** 전체 솔리드와 파이썬 관용구에 대해 더 자세히 읽을 필요가 있습니다. 감사! 나는 기본 클래스 ('__init__','tidy')에 대한 명시 적 호출을'super'로 대체했습니다. –