2012-08-22 3 views
2

호기심이 없어지면 다른 함수에 함수를 명시 적으로 전달하거나 함수가 함수를 함수에서 호출하게하는 것이 더 바람직합니다. 이것은 Explicit의 경우가 내재적 인 것보다 낫습니까? 예를 들어명시 적으로 파이썬 함수 전달하기

def foo(x,y): 
    return 1 if x > y else 0 

partialfun = functools.partial(foo, 1) 

def bar(xs,ys): 
    return partialfun(sum(map(operator.mul,xs,ys))) 

>>> bar([1,2,3], [4,5,6]) 

또는 -

def foo(x,y): 
    return 1 if x > y else 0 

partialfun = functools.partial(foo, 1) 

def bar(fn,xs,ys): 
    return fn(sum(map(operator.mul,xs,ys))) 

>>> bar(partialfun, [1,2,3], [4,5,6]) 

답변

2

정말 기능이 상황에서 다른 것 사이에 어떤 차이가 아니다 (다음 내가 무엇을 의미하는지 설명하기 위해 아니라). 함수의 다른 호출에 따라 다를 수있는 매개 변수 인 경우 인수를 인수로 전달합니다. 호출중인 함수 (예 : bar)가 항상 다른 함수를 호출하는 경우이를 인수로 전달할 이유가 없습니다. 많은 다른 기능을 사용할 수 있도록 매개 변수화해야하는 경우 (예 : barpartialfun 이외의 많은 함수를 호출해야하며 어느 것을 호출해야하는지 알 필요가 있음) 인수로 전달해야합니다.

2

일반적으로 예,하지만 항상 그렇습니다. 여기서 설명하고있는 것은 dependency injection입니다. 일반적으로 주어진 기능의 논리에서 가변성을 분리 할 수 ​​있으므로 좋은 생각입니다. 예를 들어,이 코드를 테스트하는 것이 매우 쉽다는 것을 의미합니다.

# To test the process performed in bar(), we can "inject" a function 
# which simply returns its argument 
def dummy(x): 
    return x 

def bar(fn,xs,ys): 
    return fn(sum(map(operator.mul,xs,ys))) 

>>> assert bar(dummy, [1,2,3], [4,5,6]) == 32 
+0

의존성 주입에 대한 링크에 감사드립니다. 그것은 분명히 몇 가지를 명확히했습니다 (내가 묻고 있다는 것을 깨닫지 못했던 것) – beoliver

2

문맥에 따라 크게 달라집니다.

기본적으로 함수가 bar의 인수 인 경우 호출자는 해당 함수를 구현하는 방법을 알고 있어야합니다. bar은 신경 쓸 필요가 없습니다. 그러나 결과적으로 bar의 설명서에는 어떤 기능이 종류에 해당하는지 설명해야합니다.

종종 매우 적절합니다. 분명한 예로는 map 내장 기능입니다. map은 목록의 각 항목에 함수를 적용하고 결과 목록을 돌려주는 논리를 구현합니다. map 자체는 항목이 무엇인지, 또는 함수가 무엇을하는지에 대해 알지도 모릅니다. map의 설명서에는 하나의 인수 기능이 필요하다는 것을 설명해야하고 map의 각 호출자는 적절한 기능을 구현하거나 찾는 방법을 알아야합니다. 그러나이 협정은 훌륭합니다. 그것은 당신이 당신의 커스텀 오브젝트들과 그 오브젝트들에 대해 특별히 작동하는 함수의리스트를 전달할 수있게 해주고, map은 없어져서 일반적인 일을 할 수 있습니다.

그러나 종종이 배열은 부적절합니다. 함수는 상위 수준의 작업에 이름을 지정하고 내부 구현 세부 정보를 숨기므로 작업을 하나의 단위로 생각할 수 있습니다. 함수 매개 변수로 외부에서 조작의 일부를 전달할 수 있도록 허용하려면 해당 함수의 인터페이스를 사용하는 방식으로 작동해야합니다.

좀 더 구체적인 (다소 인위적이지만) 예제가 도움이 될 수 있습니다. 내가 PersonJob을 나타내는 데이터 유형을 구현했다고 가정하고 전자 메일 서명이나 레터 헤드 등에 삽입 할 클라이언트 코드 용으로 전체 이름과 직책을 문자열로 서식 지정하기위한 함수 name_and_title을 작성했습니다. 분명히 PersonJob을 가져갈 것입니다. 호출자가 사람의 이름을 형식화하는 방법을 결정할 수 있도록 함수 매개 변수를 취할 수 있습니다 (예 : lambda firstname, lastname: lastname + ', ' + firstname). 하지만 이렇게하려면 내가 다른 사람들의 이름과 성으로 사람들의 이름을 대표하고 있음을 드러내는 것입니다.중간 이름 지원으로 변경하려면 name_and_title 중 중간 이름을 포함 할 수 없거나 허용되는 함수의 유형을 변경해야합니다. 어떤 사람들이 4 개 이상의 이름을 가지고 있고 이름 목록을 저장하는 것으로 변경하기로 결정한 후에는 확실히 함수 유형을 변경해야합니다. name_and_title 수락합니다.

예를 들어 bar 예를 들어, 의미가없는 추상 예이기 때문에 어떤 것이 더 좋다고 말할 수는 없습니다. partialfun에 대한 호출이 bar이 수행해야하는 구현 세부 사항인지 또는 partialfun에 대한 호출이 호출자가 알고있는 것 (다른 작업을 수행하려고 할 수 있음)인지 여부에 따라 다릅니다. 'bar'의 일부인 경우 매개 변수가 아니어야합니다. 호출자의 "일부"인 경우 매개 변수 여야합니다.

bar거대한 개의 함수 매개 변수 수를 가질 수 있습니다. 당신은 bar보다 유연하게 모두 매개 변수화 할 수 sum, mapoperator.mul를 호출 :

def bar(fn, xs,ys, g, h, i): 
    return fn(g(h(i,xs,ys)) 

그리고 gh의 출력에 호출되는 방식을 너무 추상화 될 수있다 :

def bar(fn, xs, ys, g, h, i, j): 
    return fn(j(g, h(i, xs, ys))) 

우리는 계속해서 bar이 아무것도하지 않고 모든 것이 전달 된 함수에 의해 제어되며 호출자는 100 가지 재미를 쓰기보다는 원하는 것을 직접 할 수도 있습니다. 기능을 수행하기 위해 그것을 수행하고이를 bar에 전달하십시오.

그래서 항상 확실한 답을 얻지 못하는 경우가 있습니다. 그것은 당신이 쓰고있는 특정 코드에 달려 있습니다.

+0

이것은 훌륭한 대답입니다 - 아주 철저합니다. 비록 당신이 단위 테스트를 언급했다면, 나는 그것을 좋아했을 것이다. : o) – voithos

+0

+1 -이 시간을 가져 주셔서 감사합니다! 나는 함수를 전달하고 partial을 사용하여 새로운 함수를 구축하는 습관을 갖게되었지만 실제로 필요하지 않을 때이 작업을 해왔다고 생각한다. 당신의 문장 '바의 일부인 경우에는 매개 변수가되어서는 안됩니다. 호출자의 "일부"인 경우 매개 변수 여야합니다. ' 많은 의미가 있습니다. 브라보. – beoliver

관련 문제