파이썬에서 함수를 전달할 수 있습니까?


189

파이썬에서 함수를 전달할 수 있습니까? cmp선언하기 전에 내 함수를 사용하여 목록을 정렬하고 싶습니다 .

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

cmp_configs호출 후 메소드 정의를 넣도록 코드를 구성했습니다 . 이 오류로 실패합니다.

NameError: name 'cmp_configs' is not defined

cmp_configs메소드를 사용하기 전에 "선언"하는 방법이 있습니까? 내 코드가 더 깨끗해 보일까요?

일부 사람들은이 문제가 없도록 코드를 재구성해야한다고 말하고 싶어합니다. 그러나 불가피한 경우가있을 수 있습니다 (예 : 일부 재귀 형식을 구현할 때). 이 예제 마음에 들지 않으면, 나는 그것의하는 경우가 있다고 가정 정말 함수를 선언 전달하는 것이 필요합니다.

파이썬에서 함수를 앞으로 선언하는 것이 필요한 경우를 생각해보십시오.

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

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

경우 end_conditionend_result이전에 정의되어있다.

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

답변:


76

함수 사용 하기 전에 정의하지 않고 나중에 정의하는 것이 불가능 하다면 다른 모듈에서 정의하는 것은 어떻습니까?

기술적으로는 여전히 먼저 정의하지만 깨끗합니다.

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

def foo():
    bar()

def bar():
    foo()

파이썬의 함수는 값이 익명 인 것처럼 익명이지만 이름에 바인딩 될 수 있습니다.

위의 코드 foo()에서 이름이 foo 인 함수를 호출하지 않고 호출 foo시점에서 이름 에 바인딩되는 함수를 호출합니다 . foo다른 곳 에서 재정의 bar한 다음 새 함수를 호출 할 수 있습니다.

선언되지 않은 변수를 요청하는 것과 같기 때문에 문제를 해결할 수 없습니다.


47
간단히 말해 __name__ == '__main__': main ()이 스크립트의 마지막 줄이면 모든 것이 정상입니다!
Filipe Pina

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

11
@ SanjayManohar : 실행을 피하기 위해import your_module
jfs

2
추가하고 싶습니다. 나중에 평가되기 때문에 람다를 사용하여 이러한 문제를 피할 수 있습니다.
Joe

2
"익명"인 Wrt는 "일류 객체"를 의미합니다.
danielm

119

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

그래서

foo()

def foo():
    print "Hi!"

깨지 겠지만

def bar():
    foo()

def foo():
    print "Hi!"

bar()

제대로 작동합니다.

일반적인 규칙 Python은 함수가 코드에서 더 높게 정의되어야한다는 것이 아닙니다 (Pascal ), 그러나 그것의 사용 전에 정의되어야한다.

희망이 도움이됩니다.


20
키스톤 개념 : Pascal = define high, Python = define 일찍 가장 직접적인 답변 +1.
Bob Stein

1
이것이 정답이며 if __name__=="__main__":솔루션이 작동하는 이유도 설명 합니다.
00prometheus

2
올바르게 이해하면 OP의 spam () 및 eggs () 예제가 작성된 것입니다. 그 맞습니까?
krubo

1
@krubo 네, 작성된대로 괜찮습니다
lxop

92

다음을 통해 스크립트를 시작하면 :

if __name__=="__main__":
   main()

"포워드 선언"과 같은 것에 대해 걱정할 필요가 없습니다. 인터프리터는 모든 함수를로드 한 다음 main () 함수를 시작합니다. 물론 모든 수입품도 올바른지 확인하십시오 ;-)

그것을 생각해 보니, 파이썬에서 "앞으로 선언"과 같은 것을 들어 본 적이 없지만 다시는 틀릴 수도 있습니다. ;-)


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

2
좋은 팁; 정말 나를 도와줍니다; "top-down"프로그래밍보다 bottom-up보다 더 선호합니다.
GhostCat

10

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 ()을 호출하십시오.


10

이 글을 소생시킨 것에 대해 사과드립니다 만, 여기서 논의되지 않은 전략이 있습니다.

리플렉션을 사용하면 선언을 전달하는 것과 비슷한 작업을 수행 할 수 있습니다. 예를 들어 다음과 같은 코드 섹션이 있다고 가정 해보십시오.

# 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]()

따라서 이런 방식으로 실제로 정의하기 전에 어떤 함수를 호출 할 것인지, 실제로는 선언을 결정했습니다. 파이썬에서 문은 globals()[function_name]()동일 같은 foo()경우 function_name = 'foo'파이썬을 호출하기 전에 각각의 기능을 조회해야하기 때문에 이유를 들어, 위에서 언급. timeit모듈 을 사용 하여이 두 명령문을 비교하는 방법을 살펴보면 계산 비용이 정확히 같습니다.

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


9

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

다음 예제를 고려하십시오.

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.

함수 본문은 함수를 호출하면 해석되는 다른 스크립트 일 뿐이라고 생각할 수 있습니다.


7

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

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

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

cmp_configs가 무엇인지 알거나 알 수 없습니다. 계속하려면 cmp_configs를 알아야합니다. 재귀가 있는지는 중요하지 않습니다.


9
글쎄, 이것은 당신이 코드를 한 번만 수행하는 경우입니다. 일부 컴파일러 (그리고 파이썬은 해석 된 것으로 알고 있습니다)는 두 가지 단계를 수행하므로 이러한 것들을 알아낼 수 있습니다. 전진 선언 또는 적어도 일종의 범위가 지정된 발견은 실제로 좋을 것입니다.
마크 레이크 우드

7

때로는 전체 구조부터 시작하여 세부 사항까지 드릴 다운하는 알고리즘이 하향식을 이해하는 것이 가장 쉽습니다.

앞으로 선언하지 않고도 그렇게 할 수 있습니다.

def main():
  make_omelet()
  eat()

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

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

# ...

main()

4
# declare a fake function (prototype) with no body
def foo(): pass

def bar():
    # use the prototype however you see fit
    print(foo(), "world!")

# define the actual function (overwriting the prototype)
def foo():
    return "Hello,"

bar()

산출:

Hello, world!

3

파이썬에서는 함수를 전달할 수 없습니다. 함수를 정의하기 전에 로직을 실행한다면 어쨌든 문제가있을 수 있습니다. 당신의 행동을if __name__ == '__main__'스크립트 끝에 (사소하지 않은 경우 "main"이라는 이름의 기능을 실행하면) 코드가 더 모듈화되고 필요할 때 모듈로 사용할 수 있습니다 에.

또한, 발전기 명시 적으로 그 목록의 이해를 대체 (예 print "\n".join(str(bla) for bla in sorted(mylist, cmp=cmp_configs)))

또한 cmp더 이상 사용되지 않는를 사용하지 마십시오 . key보다 적은 기능을 사용 하고 제공 하십시오 .


보다 적은 기능을 어떻게 제공합니까?
Nathan Fellman

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

C와 같은 배경에서 온 사람들에게는 함수가 정의되기 전에 논리 실행에 대해 부당한 것이 없습니다. "멀티 패스 컴파일러"라고 생각하십시오. 새로운 언어에 적응하기까지 때때로 시간이 걸립니다 :)
Luke H

3

파일 자체를 가져옵니다. 파일을 test.py라고 가정합니다.

import test

if __name__=='__main__':
    test.func()
else:
    def func():
        print('Func worked')

1

"이 문제가 발생하지 않도록 코드를 재구성하십시오." 옳은. 하기 쉽다. 항상 작동합니다.

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

"그러나 어떤 형태의 재귀를 구현할 때와 같이 피할 수없는 경우가 있습니다"

그것이 어떻게 원격으로 가능한지 알 수 없습니다. 기능을 사용하기 전에 정의 할 수없는 장소의 예를 제공해주십시오.


나는 그런 상황이 있습니다. 함수 데코레이터에서 형식을 전달하려고하는데 형식이 모듈 아래에 더 정의되어 있습니다. 상속 체인을 손상시킬 수 있기 때문에 문제가되는 유형을 위로 이동할 수 없습니다.
Joe

실제 유형 대신 람다를 장식 자에게 전달하여 문제를 해결했습니다. 그러나 나는 그것을 다른 방법으로 고칠 방법을 모른다. (그러면 상속 재산을 재정렬 할 필요가 없다)
Joe

0

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

인쇄를 사용하여 질문을 게시하는 것이 실제로 다음과 같이 표현하려는 경우 :

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

그런 다음 정의 할 필요가 없습니다 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 = None

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


-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)

그것은 매우 비현실적인 것 같습니다. 파이썬은 이런 종류의 것들을 스스로 처리해야합니다.
Nathan Fellman

허용 된 답변을 다시 읽으십시오. 파이썬은 함수를 정의 할 때가 아니라 호출 할 때까지 함수를 정의 할 필요가 없습니다 .
tacaswell

-3

예, 우리는 이것을 확인할 수 있습니다.

입력

print_lyrics() 
def print_lyrics():

    print("I'm a lumberjack, and I'm okay.")
    print("I sleep all night and I work all day.")

def repeat_lyrics():
    print_lyrics()
    print_lyrics()
repeat_lyrics()

산출

I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.
I'm a lumberjack, and I'm okay.
I sleep all night and I work all day.

BJ 호머가 위에서 언급 한 것처럼 언급했듯이 파이썬의 일반적인 규칙은 함수가 코드에서 더 높게 정의되어야하지만 (파스칼에서와 같이) 사용 전에 정의되어야한다는 것입니다.

희망이 도움이됩니다.


2
print_lyrics()정의하기 전에 1 행에서 호출 되지 않습니까? 이 코드 조각을 복사하여 실행하려고했는데 NameError: name 'print_lyrics' is not defined1 행에 오류가 발생 했습니다. 설명해 주시겠습니까?
버그 버기
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.