2011-08-18 1 views
5

클라이언트 코드에 의해 구현되는 "인터페이스"가 있습니다.이 경우 "Pythonic"과 "convenient"의 균형을 어떻게 잡을 수 있습니까?

class Runner: 
    def run(self): 
     pass 

run는 일반적으로 docutilsnode를 반환해야하지만 일반 텍스트는 일반 텍스트이므로 호출자는 run에서 run를 반환 할 수 있습니다. 문자열은 type()을 사용하여 로 확인되고 node로 바뀝니다.

그러나 가 type()과 같은 "연기"에 의한 형식이 될 수 없기 때문에 "Pythonic"을 이해하는 방식으로 "Python"이 아닙니다. 코드는 오리 입력을 사용해야합니다.

나는

def run_str(self): 
    pass 

def run_node(self): 
    return make_node(self.run_str()) 

을 고려해 보았습니다.하지만 그다지 흥미롭지 않은 리턴 타입 인 를 이름에 넣었 기 때문에 걱정하지 않아도됩니다. 산만 해.

내가 놓친 아이디어가 있습니까? 또한, "나쁜"시스템으로 도로 아래에서 을 만날 수있는 문제가 있습니까? (더 안전하거나 덜 안전합니다)?

+0

저는 조금 혼란 스럽습니다. 'run' (arg를 통해)에 전달 된 값에 대해 이야기하고 있습니까? 아니면'Runner' 인터페이스를 구현 한 객체의'run' 메소드가 반환 한 가상의 값을 처리하는 방법에 대해 이야기하고 있습니까? – senderle

+0

나는 반환을 의미합니다. 나는 'arg'을 편집하여주의를 산만하게하지 않을 것입니다 (이것을 지적 해 주셔서 감사합니다). – Owen

답변

5

저는 이것이 다소기만적인 예라고 생각합니다. 당신이 진술하지 않은 것이 있습니다. 나는 당신이 "인터페이스를 가지고있다"고 말할 때, 객체를 받아들이는 코드를 가지고 있으며 그 메소드를 run 메서드라고 부르는 것을 의미하는 것이라고 생각합니다.

run 메서드를 호출하기 전에 해당 객체의 유형을 테스트하지 않으면 일반적이고 간단하게 오리 유형을 사용하고 있습니다! 이 경우 run 방법이있는 경우 Runner입니다.) run 메서드를 가진 객체에서 type 또는 isinstance을 사용하지 않는다면 Pythonic이됩니다.

일반 문자열이나 노드 객체 만 받아 들여야하는지에 대한 질문은 조금 다른 질문입니다. 문자열과 node 객체는 아마도 동일한 인터페이스를 구현하지 않을 것입니다! 문자열은 근본적으로 node과 같은 돌팔이가 아니므로 하나처럼 취급 할 필요가 없습니다. 이것은 따라 오는 코끼리와 같습니다. 오리처럼 무릎을 꿇고 싶으면 코끼리에게 테이프 플레이어를주고 코끼리를 먼저 사용하도록 훈련시켜야합니다.

그래서 "오리 타잉"의 문제가 아니라 인터페이스 디자인입니다. 인터페이스가 얼마나 엄격한지를 결정하려고합니다.

답을 얻으려면이 레벨에서 runnode 개체를 반환한다고 가정하는 것이 가장 Pythonic이라고 생각합니다. 이를 테스트하기 위해 isinstance 또는 type을 사용할 필요가 없습니다. 그냥 node 객체 인 척하고 인터페이스를 사용하는 프로그래머가 잘못되어 예외가 발생하면 runnode 객체를 전달해야한다고 알리는 문서 문자열을 읽어야합니다.

그런 다음 으로 문자열이나 끈 같은 돌기를 허용하려는 경우 그렇게 할 수 있습니다. 문자열은 오히려 기본 유형이기 때문에 isinstance(obj, basestring) (그러나 이 아닌type(obj) == str이 아닌 것은 유니 코드 문자열 등을 거부하기 때문에 사용하는 것은 부적절하지 않다고 말합니다.) 본질적으로, 이것은 당신이 당신의 프로그램을 게으른 사용자들에게 매우 자유롭고 친절합니다. 당신은 이미 코끼리뿐만 아니라 오리처럼 돌팔매질하는 것들을 받아들임으로써 위와 그 이상으로 나아가고 있습니다.

(보다 구체적으로,이 조금 당신이 발전기 및 시퀀스를 모두 수용 할 함수의 시작 부분에서 인수에 iter를 호출처럼 말하고 싶지만.)

+0

실용적인 API 디자인과 비교하여 "Pythonic purity"의 좋은 교환 조건입니다. 또한 사용자가 전혀 반환하지 않음으로써 None을 "반환"할 것으로 예상하므로 코드도 작성해야합니다. – PaulMcG

1

체크 아웃 : 당신의 make_node 기능 내부

def run(self,arg): 
    try: 
     return make_node(arg) 
    except AlreadyNodeError: 
     pass 

는 인수가 이미 노드 인 경우는 AlreadyNodeError을 올릴 수 있습니다.

+0

+1 내 생각은 정확히 (거의 정확히). – zeekay

+0

unshosher 호출을'type()'으로'make_node()'함수로 옮기지 않습니까? – Owen

+0

make_node 함수가 Try : Raise : 블록을 노드에 만들려고 시도하고 이미 발견 된 노드를 발견하면 오류가 발생합니다. – Jonathanb

2

각 유형을 처리 할 수있는 방법이 반드시 필요한 것은 아니며, 특히 간단한 조작 만 수행하면됩니다.

def run(self): 
    try: 
     ...assume it's a str 
    except TypeError: 
     ...oops, not a str, we'll address that 

이것은 일반적으로 빠르고 간단 코딩의 Easier to ask for forgiveness than permission (EAFP) 스타일을 다음과 : 일반적인 파이썬 방법은 그런 짓을하는 것입니다.

+0

나는 우리가 다른 것들에 대해 이야기하고 있다고 생각한다. 나는 반환 유형을 의미했다. 하지만 당신의 대답도 거기에 적용될 것입니다. 그것은 제 경우에 잘 작동 할 것입니다. – Owen

+0

저는 일반적으로 메서드가 완전히 다른 유형의 객체를 반환하도록하는 것이 좋지 않다고 생각합니다. 나는이 경우에 두 가지 분리 된 방법을 다루는 것을 선호한다. – zeekay

+0

네 말이 맞아, 나쁘다. 그것은 단지 유혹적 일 정도로 편리합니다. – Owen

1

, 더 좋은 방법은 사용하는 것입니다 그것은 (귀하의 경우 str)는 원하는 형식에서 상속 객체를 허용하지 것처럼, 변수의 타입이 정말 나쁜 관행입니다 감지 type()를 사용 isinstance() :

if isinstance(my_var, str): 
    my_code_here() 

또한, 이것을 수행하는 파이썬 방법은 언급 한대로 덕 타이핑이 될 것입니다. try/except 블록에 코드를 넣는 것이 어떻습니까? 따라서 값이 이 아니라면이 예상대로 (예외적으로 오리처럼 걷고 걷는 경우) 예외가 발생합니다.

0
class Node(object): 
    def __new__(cls, contents): 
    return contents if isinstance(contents, cls) else object.__new__(cls) 
    def __init__(self, contents): 
    # construct from string... 

class Manager(object): 
    def do_something(self, runner, *args): 
    do_something_else(Node(runner(*args))) 

는 지금은 '아무튼 주자가 노드 또는 문자열을 반환하면 문제가 발생합니다.

관련 문제