2009-10-19 4 views
114

파이썬에서 함수를 forward-declare 할 수 있습니까? 선언되기 전에 자신의 cmp 함수를 사용하여 목록을 정렬하고 싶습니다.파이썬에서 함수를 forward-declare 할 수 있습니까?

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)]) 

호출 후 cmp_configs 메서드를 정의하는 코드를 구성했습니다. 그것은이 오류와 함께 실패합니다

NameError: name 'cmp_configs' is not defined 

가 사용되기 전에 cmp_configs 방법을 "선언"어떤 방법이 있나요? 그것은 내 코드를 더 깨끗하게 보일 것입니까?

저는이 문제가 발생하지 않도록 코드를 재구성해야한다고 말하는 사람들이 있습니다. 그러나 어떤 경우에는 재귀를 구현할 때와 같이 피할 수없는 경우가 있습니다. 이 예제가 마음에 들지 않는다면 함수를 선언하기 위해 이 실제로 인 경우가 있다고 가정합니다. end_conditionend_result 이전

def spam(): 
    if end_condition(): 
     return end_result() 
    else: 
     return eggs() 

def eggs(): 
    if end_condition(): 
     return end_result() 
    else: 
     return spam() 

정의되었습니다

앞으로-선언 함수 것은 파이썬으로 필요하다이 경우를 생각해 보자.

코드를 재구성하고 호출 전에 항상 정의를 넣는 유일한 해결책입니까?

답변

54

당신이 사용되는 전에 함수 를 정의하지 않으려면, 그리고 불가능 나중에 그것을 정의, 어떤 다른 모듈에서 정의에 대한?

기술적으로 당신은 여전히 ​​그것을 먼저 정의하지만 깨끗합니다.

def foo(): 
    bar() 

def bar(): 
    foo() 

파이썬의 기능

값은 익명처럼 익명, 그러나 그들은 이름에 바인드 할 수 있습니다

다음과 같은 재귀를 만들 수 있습니다.

위의 코드에서 foo()은 foo라는 이름의 함수를 호출하지 않고 호출이 이루어질 때 foo이라는 이름으로 바인딩되는 함수를 호출합니다. foo을 다른 곳으로 다시 정의 할 수 있으며 bar은 새 함수를 호출합니다.

신고하지 않은 변수를 얻으려고하는 것과 같기 때문에 문제를 해결할 수 없습니다.

+27

입니다. _if \ _ \ _ name \ _ \ _ == '\ _ \ _ main \ _ \ _': 스크립트의 마지막 줄에 main() _이 있으면 모든 것이 잘됩니다! –

+1

@FilipePina 귀하의 의견을 이해하지 못했습니다. 왜 코드의 마지막 줄을 단순히'main()'으로 넣을 수 없습니까? –

+6

@SanjayManohar :'import your_module'에서 실행을 피하십시오. – jfs

0

"이 문제가 발생하지 않도록 코드를 재구성하면됩니다." 옳은. 쉽게 할 수 있습니다. 항상 작동합니다.

참조하기 전에 항상 기능을 제공 할 수 있습니다.

그 심지어 원격으로 가능 방법을 볼 수 없습니다

는 "재귀의 몇 가지 형태를 구현할 때이 예를 들어, 아마도 피할 그러나 경우가 있습니다." 기능을 사용하기 전에 정의 할 수없는 장소의 예를 제공해주십시오.

+0

이런 상황이 있습니다. 함수 데코레이터에서 유형을 전달하려고 시도하고 있으며 유형이 모듈에서 더 아래로 정의됩니다. 문제가되는 유형은 상속 체인을 깨뜨릴 수 있기 때문에 이동할 수 없습니다. – Joe

+0

나는 람다를 실제 타입 대신에 내 데코레이터에 전달하여 그것을 고쳤다. 하지만 그렇지 않으면 그것을 수정하는 방법을 모르겠다. (내 상속을 재정렬 할 필요가 없다.) – Joe

66

다음을 통해 스크립트를 걷어차 시작하는 경우 :

if __name__=="__main__": 
    main() 

이 그때는 아마 "앞으로 선언"같은 것들에 대해 걱정할 필요가 없습니다. 보시다시피, 인터프리터는 모든 함수를로드 한 다음 main() 함수를 시작합니다. 물론 모든 수입품이 올바른지 확인하십시오 :-)

파이썬에서 "forward declaration"와 같은 것을들은 적이 없지만 다시 생각해보십시오. 틀린 ;-)

+11

+1 가장 실용적인 답 :이 코드를 가장 바깥 쪽 소스 파일의 아래쪽 **에 넣으면 어떤 순서로든 자유롭게 정의 할 수 있습니다. –

+1

위대한 팁; 정말 나를 돕는다. 나는 "하향식"프로그래밍 대 바텀 업을 훨씬 더 선호하기 때문에. – GhostCat

64

당신이 할 수있는 일은 그 자체의 기능으로 호출을 싸는 것입니다.

그래서

foo() 

def foo(): 
    print "Hi!" 

휴식하지만

def bar(): 
    foo() 

def foo(): 
    print "Hi!" 

bar() 

가 제대로 작동 될 것입니다.Python에서

일반 규칙은 그 기능 (Pascal에서와 같이) 코드에 높은 정의되어야하지, 그러나 그것의 사용 전에 정의되어야한다.

희망이 있습니다.

+11

+1 가장 직접적인 대답은 키스톤 개념입니다. Pascal = higher, Python = 더 일찍 정의. –

+1

이것은 정답이며'if __name __ == "__ main __":'솔루션이 작동하는 이유를 설명합니다. 간단히 말해 – 00prometheus

7

아니요, 파이썬에서 함수를 전달 선언 할 수있는 방법이 없다고 생각합니다.

당신이 파이썬 인터프리터라고 상상해보십시오. 줄에 가면

print "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)]) 

당신은 cmp_configs가 무엇인지 알지 못합니다. 진행하려면 cmp_configs를 알고 있어야합니다. 재귀가 있으면 상관 없습니다.

+6

코드를 한 번만 통과하면됩니다. 일부 컴파일러는 (그리고 나는 파이썬이 해석되어 있음을 깨닫는다.) 두 가지 패스를 사용하기 때문에 이러한 것들을 이해할 수있다. forward-declaration, 또는 적어도 어떤 종류의 스코프 된 발견은 정말로 좋을 것입니다. –

9

cmp_configs를 호출 할 때 자체 함수 정의 안에 있으면 괜찮을 것입니다. 예를 들어 보겠습니다.

def a(): 
    b() # b() hasn't been defined yet, but that's fine because at this point, we're not 
     # actually calling it. We're just defining what should happen when a() is called. 

a() # This call fails, because b() hasn't been defined yet, 
    # and thus trying to run a() fails. 

def b(): 
    print "hi" 

a() # This call succeeds because everything has been defined. 

일반적으로 코드를 기능 (예 : main())에 넣으면 문제가 해결됩니다. 파일의 끝에서 main()을 호출하면됩니다.

5

파이썬에는 순방향 선언과 같은 것은 없습니다. 함수가 필요하기 전에 함수가 선언되었는지 확인해야합니다. 함수 본문은 함수가 실행될 때까지 해석되지 않습니다.

def a(): 
    b() # won't be resolved until a is invoked. 

def b(): 
    print "hello" 

a() # here b is already defined so this line won't fail. 

당신은 함수의 몸은 당신이 함수를 호출하면 해석됩니다 또 다른 스크립트이라고 생각 할 수 있습니다

는 다음과 같은 예를 생각해 보자.

0

이제 잠시 기다려주세요. 모듈이 예제에서 print 문에 도달하면 cmp_configs이 정의되기 전에 정확히 무엇을 기대합니까?

인쇄를 사용하여 질문 귀하의 게시물이 정말이 같은 것을 표현하려고하는 경우 :

fn = lambda mylist:"\n".join([str(bla) 
         for bla in sorted(mylist, cmp = cmp_configs)]) 

다음이 문을 실행하기 전에 cmp_configs를 정의 할 필요가 없기를, 단지 코드와 모두 나중에 정의 잘 될 것입니다.

fn = lambda mylist,cmp_configs=cmp_configs : \ 
    "\n".join([str(bla) for bla in sorted(mylist, cmp = cmp_configs)]) 

지금 당신은 당신이이 선에 도달하기 전에 cmp_configs 변수를 정의해야합니다

은 이제 람다에 대한 인수의 기본값으로 cmp_configs을 참조하려고하는 경우, 다음이 다른 이야기입니다.

[편집 -.이 다음 부분은 기본 인수의 값을 할당받을 것이기 때문에 함수가 컴파일 될 때, 정확하지 밝혀, 그리고 나중에 cmp_configs의 값을 변경하는 경우 그 값도 사용됩니다]

다행스럽게도, 파이썬은 지금 그대로, 당신이 cmp_configs로 정의 무엇을 상관하지 않는다 - 수용 입력되고, 그래서 당신은이 문 서문 수 :

cmp_configs = None 

을 그리고 컴파일러는 행복 할 것이다. fn을 호출하기 전에 실제 cmp_configs을 선언해야합니다.

2

파이썬에서 함수를 전달 선언 할 수 없습니다. 함수를 정의하기 전에 논리를 실행하면 어쨌든 문제가 발생할 수 있습니다. 스크립트가 끝날 때 if __name__ == '__main__'에 조치를 취하십시오. (중요하지 않은 경우 "main"이라고 이름 붙인 함수를 실행하여) 코드가 모듈화되고 모듈로 사용할 수 있습니다. 필요하다.

또한

(즉, 인쇄 "\ n".join (STR (BLA)에 대한 즐 정렬 (myList에, CMP = cmp_configs)))

또한, 돈 '발전기 익스프레스와 그 목록의 이해를 교체 사용되지 않는 cmp를 사용합니다. "key"를 사용하고 less-than 함수를 제공하십시오.

+0

덜 작을 기능을 어떻게 제공합니까? –

+0

cmp_configs 대신 두 개의 인수를 사용하고 첫 번째가 두 번째 인수보다 작 으면 True를 반환하고 그렇지 않으면 False를 반환합니다. –

+0

C와 비슷한 배경에서 오는 사람들에게는 함수가 정의되기 전에 논리를 실행하는 것에 비합리적인 것이 없습니다. "다중 패스 컴파일러"라고 생각하십시오. 가끔은 새로운 언어에 적응하는 데 시간이 걸립니다 :) –

5

경우에 따라 알고리즘은 전반적인 구조부터 시작하여 세부 정보로 드릴 다운하는 것이 가장 쉬운 방법입니다.

당신은 앞으로 선언없이 수행 할 수 있습니다 :

def main(): 
    make_omelet() 
    eat() 

def make_omelet(): 
    break_eggs() 
    whisk() 
    fry() 

def break_eggs(): 
    for egg in carton: 
    break(egg) 

# ... 

main() 
-1

한 가지 방법은 핸들러 함수를 만드는 것입니다. 초기에 핸들러를 정의하고 핸들러를 호출해야하는 모든 메소드 아래에 놓습니다.

그런 다음 함수를 호출하는 처리기 메서드를 호출하면 해당 함수를 항상 사용할 수 있습니다.

핸들러는 nameOfMethodToCall 인수를 취할 수 있습니다. 그런 다음 올바른 문을 호출하기 위해 if 문을 사용합니다.

이렇게하면 문제가 해결됩니다.

def foo(): 
    print("foo") 
    #take input 
    nextAction=input('What would you like to do next?:') 
    return nextAction 

def bar(): 
    print("bar") 
    nextAction=input('What would you like to do next?:') 
    return nextAction 

def handler(action): 
    if(action=="foo"): 
     nextAction = foo() 
    elif(action=="bar"): 
     nextAction = bar() 
    else: 
     print("You entered invalid input, defaulting to bar") 
     nextAction = "bar" 
    return nextAction 

nextAction=input('What would you like to do next?:') 

while 1: 
    nextAction = handler(nextAction) 
+0

그것은 매우 unpythonic 것 같습니다. 파이썬은 이런 종류의 것들을 모두 처리해야합니다. –

+0

수락 된 답변을 다시 읽으십시오. 파이썬은 정의에서 함수를 사용하는 것뿐만 아니라, 함수가 정의 될 때까지 함수를 정의 할 필요가 없습니다. – tacaswell

5

나는이 스레드를 되살리기 위해 사과하지만 적용 할 수있는 여기에 언급되지 않은 전략이 있습니다.

리플렉션을 사용하여 선언문과 비슷한 작업을 수행 할 수 있습니다. 인스턴스가 있습니다 당신은 다음과 같습니다 코드 섹션이 있다고 :

# We want to call a function called 'foo', but it hasn't been defined yet. 
function_name = 'foo' 
# Calling at this point would produce an error 

# Here is the definition 
def foo(): 
    bar() 

# Note that at this point the function is defined 
    # Time for some reflection... 
globals()[function_name]() 

그래서 우리는 우리가 실제로 효과적으로 전달 선언을 정의하기 전에 호출 원하는 기능을 결정했다 이런 식이다. python에서 문을 globals()[function_name]()function_name = 'foo' 인 경우 foo()과 동일합니다. 왜냐하면 파이썬은 호출하기 전에 각 함수를 찾아야하기 때문입니다. 이 두 문장을 비교하는 방법을 보려면 timeit 모듈을 사용하면 정확히 동일한 계산 비용을 가지게됩니다.

물론이 예제는 매우 쓸모가 없다.하지만 함수를 실행해야하는 복잡한 구조를 가지기 전에 선언해야한다. (또는 구조적으로 나중에 선언해야한다.) 문자열을 저장하고 나중에 함수를 호출하십시오.

관련 문제