함수에서 명시 적으로 return 호출
얼마 전 나는 R 핵심 팀의 Simon Urbanek에 의해 책망을 받았다. (사용자 return
는 함수가 끝날 때 명시 적으로 호출하도록 권장했다 .
foo = function() {
return(value)
}
대신 그는 추천했다 :
foo = function() {
value
}
아마도 이와 같은 상황에서는 다음이 필요합니다.
foo = function() {
if(a) {
return(a)
} else {
return(b)
}
}
그의 의견 return
은 꼭 필요한 경우가 아니라면 전화 하지 않는 이유에 대해 약간의 설명을 밝혔 지만 이것은 삭제되었다.
내 질문은 : 왜 return
더 빨리 또는 더 나은 전화를하지 않는 이유는 무엇 입니까?
질문 : 왜 (명시 적으로) 호출이 더 빠르거나 더 나은 호출을하지 않는가?
R 문서에는 그러한 가정을하는 진술이 없습니다.
그쪽 맨 페이지? '기능'말한다 :
function( arglist ) expr
return(value)
return을 호출하지 않고 더 빠릅니까?
모두 function()
와 return()
기본 기능이며 function()
자체도 포함하지 않고 마지막에 평가 값을 반환하는 return()
기능.
호출 return()
로 .Primitive('return')
인수로 마지막 값은 같은 일을하지만 더 하나의 호출을 필요로합니다. 따라서이 .Primitive('return')
호출 (불필요한 호출 )을 통해 추가 리소스를 얻을 수 있습니다. 그러나 간단한 측정은 결과 차이가 매우 작으므로 명시 적 반환을 사용하지 않는 이유가 될 수 없음을 보여줍니다. 이 방법으로 선택한 데이터에서 다음 플롯이 생성됩니다.
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x) vector(length=x,mode="numeric"))(x)
,repeats)) }
bench_ret2 <- function(x,repeats) { system.time(rep(
# with explicit return
(function(x) return(vector(length=x,mode="numeric")))(x)
,repeats)) }
maxlen <- 1000
reps <- 10000
along <- seq(from=1,to=maxlen,by=5)
ret <- sapply(along,FUN=bench_ret2,repeats=reps)
nor <- sapply(along,FUN=bench_nor2,repeats=reps)
res <- data.frame(N=along,ELAPSED_RET=ret["elapsed",],ELAPSED_NOR=nor["elapsed",])
# res object is then visualized
# R version 2.15
위의 그림은 플랫폼에서 약간 어둡게 보일 수 있습니다. 측정 된 데이터를 기반으로 반환 된 객체의 크기는 차이를 일으키지 않습니다. 반복 수 (확장 된 경우에도)는 매우 작은 차이를 만듭니다. 실제 단어와 실제 알고리즘이있는 실제 단어는 계산하거나 계산할 수 없습니다 스크립트가 더 빨리 실행됩니다.
return을 호출하지 않고 더 낫습니까?
Return
루틴을 끝내고 함수에서 벗어나 값을 반환하는 코드의 "잎"을 명확하게 디자인하는 데 유용한 도구입니다.
# here without calling .Primitive('return')
> (function() {10;20;30;40})()
[1] 40
# here with .Primitive('return')
> (function() {10;20;30;40;return(40)})()
[1] 40
# here return terminates flow
> (function() {10;20;return();30;40})()
NULL
> (function() {10;20;return(25);30;40})()
[1] 25
>
어떤 스타일을 사용하는지 프로그래머의 전략과 프로그래밍 스타일에 따라 다르며 필요하지 않은 return ()을 사용할 수 없습니다.
R 코어 프로그래머는 두 가지 접근법을 모두 사용합니다. 기본 함수의 소스에서 찾을 수 있으므로 명시 적 return ()을 사용하거나 사용하지 않습니다.
많은 경우 return () 만 사용되며 (인수 없음) 경우에 따라 함수를 중지하기 위해 NULL을 반환합니다.
R을 사용하는 표준 사용자 또는 분석가가 실제 차이를 볼 수 없기 때문에 더 나은지 확실하지 않습니다.
내 의견은 질문은 다음과 같아야한다는 것입니다 : R 구현에서 오는 명시 적 수익을 사용하는 데 위험이 있습니까?
또는 함수 코드를 작성하는 사용자는 항상 다음과 같이 질문해야합니다. 함수 코드 에서 명시 적 리턴을 사용 하지 않거나 코드 분기의 마지막 리프로 리턴 될 오브젝트를 배치 하면 어떤 영향이 있습니까?
모두가 동의하면
return
함수 본문 끝에 필요하지 않습니다- 사용하지 않는
return
것이 조금 더 빠릅니다 (@Alan의 테스트에 따르면 4.3 마이크로 초 대 5.1)
return
함수 끝에서 모두 사용 을 중지해야 합니까? 나는 확실히하지 않을 것이며 왜 그런지 설명하고 싶습니다. 다른 사람들이 내 의견을 나누면 듣고 싶습니다. OP에 대한 정답이 아니라 긴 주관적인 의견과 비슷한 경우 사과드립니다.
return
폴이 지적했듯이 함수를 사용하지 않을 때의 주요 문제 는 함수 본문에 필요할 수있는 다른 장소가 있다는 것입니다. 그리고 return
함수 중간에 어딘가에 사용해야한다면 모든 return
진술을 명시 적으로 작성 하지 않는 이유는 무엇입니까? 나는 일관성이없는 것을 싫어한다. 또한 코드가 더 잘 읽는다고 생각합니다. 함수를 스캔하고 모든 종료점과 값을 쉽게 볼 수 있습니다.
바울은이 예를 사용했습니다.
foo = function() {
if(a) {
return(a)
} else {
return(b)
}
}
불행히도, 다음과 같이 쉽게 다시 쓸 수 있다고 지적 할 수 있습니다.
foo = function() {
if(a) {
output <- a
} else {
output <- b
}
output
}
후자의 버전은 함수 당 하나의 리턴 문을 옹호하는 일부 프로그래밍 코딩 표준을 준수합니다. 더 좋은 예는 다음과 같습니다.
bar <- function() {
while (a) {
do_stuff
for (b) {
do_stuff
if (c) return(1)
for (d) {
do_stuff
if (e) return(2)
}
}
}
return(3)
}
단일 return 문을 사용하여 다시 작성하는 것이 훨씬 어려울 수 break
있습니다. 전파하기 위해서는 여러 개의 변수와 복잡한 부울 변수 시스템 이 필요 합니다. 이 모든 것이 단일 반환 규칙이 R과 잘 어울리지 않는다고 말하면 return
함수 본문의 일부 위치에서 사용해야 할 경우 일관성이 있고 어디에서나 사용해야합니까?
속도 인수가 유효한 것으로 생각하지 않습니다. 실제로 무언가를 수행하는 함수를 볼 때 0.8 마이크로 초의 차이는 아무 것도 아닙니다. 내가 볼 수있는 마지막 것은 타이핑이 적지 만 게으르지 않다는 것입니다.
return()
더 빠르지 않은 것 같습니다 ...
library(rbenchmark)
x <- 1
foo <- function(value) {
return(value)
}
fuu <- function(value) {
value
}
benchmark(foo(x),fuu(x),replications=1e7)
test replications elapsed relative user.self sys.self user.child sys.child
1 foo(x) 10000000 51.36 1.185322 51.11 0.11 0 0
2 fuu(x) 10000000 43.33 1.000000 42.97 0.05 0 0
____ 편집__ _ __ _ __ _ __ _ __ _ ___
나는 다른 벤치 마크 ( benchmark(fuu(x),foo(x),replications=1e7)
) 로 진행 하고 결과가 반전됩니다 ... 서버에서 시도 할 것입니다.
이것은 흥미로운 토론입니다. @flodel의 예가 훌륭하다고 생각합니다. 그러나 함수 코딩 스타일 대신 명령return
을 사용할 때 의미 가있는 요점을 설명한다고 생각합니다 (@koshke는 주석에서 이것을 언급합니다) .
요점을 칭찬하지는 않지만 foo
다음과 같이 다시 작성했을 것입니다 .
foo = function() ifelse(a,a,b)
기능적 스타일은 값 저장과 같은 상태 변경을 피 output
합니다. 이 스타일에서는 return
제자리에 있지 않습니다. foo
수학 함수처럼 보입니다.
@flodel에 동의합니다. 복잡한 부울 변수 시스템을 사용하면 bar
덜 명확하고 의미가 없습니다 return
. 진술에 bar
매우 적합 하게 만드는 return
것은 명령형으로 작성되었다는 것입니다. 실제로, 부울 변수는 기능적 스타일에서 피한 "상태"변경을 나타냅니다.
bar
단순한 의사 코드이기 때문에 기능적 스타일 로 다시 작성하는 것은 실제로 어렵지만 아이디어는 다음과 같습니다.
e_func <- function() do_stuff
d_func <- function() ifelse(any(sapply(seq(d),e_func)),2,3)
b_func <- function() {
do_stuff
ifelse(c,1,sapply(seq(b),d_func))
}
bar <- function () {
do_stuff
sapply(seq(a),b_func) # Not exactly correct, but illustrates the idea.
}
while
가에 상태 변화에 의해 제어되기 때문에 루프는 다시 작성하기가 가장 어려울 것이다 a
.
호출로 인한 속도 손실 return
은 무시할 만하지 만 return
기능적 스타일 을 피하고 다시 작성하여 얻는 효율성 은 종종 막대합니다. 새로운 사용자에게 사용을 중지하라고 return
해도 도움이되지 않지만 기능적인 스타일로 안내하는 것이 좋습니다.
@Paul return
은 루프의 다른 지점에서 함수를 종료하려는 경우가 많으므로 명령형 스타일이 필요합니다. 함수형 스타일은 루프를 사용하지 않으므로 필요하지 않습니다 return
. 순전히 기능적인 스타일에서 최종 호출은 거의 항상 원하는 반환 값입니다.
파이썬에서 함수에는 return
문장이 필요합니다 . 그러나 기능적 스타일로 기능을 프로그래밍 한 경우 기능 return
이 끝날 때 하나의 명령문 만있을 수 있습니다.
Using an example from another StackOverflow post, let us say we wanted a function that returned TRUE
if all the values in a given x
had an odd length. We could use two styles:
# Procedural / Imperative
allOdd = function(x) {
for (i in x) if (length(i) %% 2 == 0) return (FALSE)
return (TRUE)
}
# Functional
allOdd = function(x)
all(length(x) %% 2 == 1)
In a functional style, the value to be returned naturally falls at the ends of the function. Again, it looks more like a mathematical function.
@GSee The warnings outlined in ?ifelse
are definitely interesting, but I don't think they are trying to dissuade use of the function. In fact, ifelse
has the advantage of automatically vectorizing functions. For example, consider a slightly modified version of foo
:
foo = function(a) { # Note that it now has an argument
if(a) {
return(a)
} else {
return(b)
}
}
This function works fine when length(a)
is 1. But if you rewrote foo
with an ifelse
foo = function (a) ifelse(a,a,b)
Now foo
works on any length of a
. In fact, it would even work when a
is a matrix. Returning a value the same shape as test
is a feature that helps with vectorization, not a problem.
A problem with not putting 'return' explicitly at the end is that if one adds additional statements at the end of the method, suddenly the return value is wrong:
foo <- function() {
dosomething()
}
This returns the value of dosomething()
.
Now we come along the next day and add a new line:
foo <- function() {
dosomething()
dosomething2()
}
We wanted our code to return the value of dosomething()
, but instead it no longer does.
With an explicit return, this becomes really obvious:
foo <- function() {
return( dosomething() )
dosomething2()
}
We can see that there is something strange about this code, and fix it:
foo <- function() {
dosomething2()
return( dosomething() )
}
I think of return
as a trick. As a general rule, the value of the last expression evaluated in a function becomes the function's value -- and this general pattern is found in many places. All of the following evaluate to 3:
local({
1
2
3
})
eval(expression({
1
2
3
}))
(function() {
1
2
3
})()
What return
does is not really returning a value (this is done with or without it) but "breaking out" of the function in an irregular way. In that sense, it is the closest equivalent of GOTO statement in R (there are also break and next). I use return
very rarely and never at the end of a function.
if(a) {
return(a)
} else {
return(b)
}
... this can be rewritten as if(a) a else b
which is much better readable and less curly-bracketish. No need for return
at all here. My prototypical case of use of "return" would be something like ...
ugly <- function(species, x, y){
if(length(species)>1) stop("First argument is too long.")
if(species=="Mickey Mouse") return("You're kidding!")
### do some calculations
if(grepl("mouse", species)) {
## do some more calculations
if(species=="Dormouse") return(paste0("You're sleeping until", x+y))
## do some more calculations
return(paste0("You're a mouse and will be eating for ", x^y, " more minutes."))
}
## some more ugly conditions
# ...
### finally
return("The end")
}
일반적으로, 많은 수익이 필요하다는 것은 문제가 추악하거나 잘못 구조화되어 있음을 시사합니다 .g
<>
return
실제로 작동하는 함수가 필요하지 않습니다.이 함수를 사용하여 평가할 표현식 세트를 분리 할 수 있습니다.
getout <- TRUE
# if getout==TRUE then the value of EXP, LOC, and FUN will be "OUTTA HERE"
# .... if getout==FALSE then it will be `3` for all these variables
EXP <- eval(expression({
1
2
if(getout) return("OUTTA HERE")
3
}))
LOC <- local({
1
2
if(getout) return("OUTTA HERE")
3
})
FUN <- (function(){
1
2
if(getout) return("OUTTA HERE")
3
})()
identical(EXP,LOC)
identical(EXP,FUN)
return
코드 가독성을 높일 수 있습니다.
foo <- function() {
if (a) return(a)
b
}
참고 URL : https://stackoverflow.com/questions/11738823/explicitly-calling-return-in-a-function-or-not
'IT story' 카테고리의 다른 글
'any'대 'Object' (0) | 2020.05.17 |
---|---|
java.lang.VerifyError 발생 원인 (0) | 2020.05.16 |
git에서 태그 사이의 커밋 목록 가져 오기 (0) | 2020.05.16 |
HEAD, BODY 및 HTML 태그를 작성해야합니까? (0) | 2020.05.16 |
iOS에서 바코드를 스캔하려면 어떻게해야합니까? (0) | 2020.05.16 |