반응형

줄리아 Julia의 변수 유효 범위( 전역, 로컬 범위 ) 에 대해 다룹니다. 

 

2023. 12. 22  최초 작성




다음 사이트를 참고하고 ChatGPT의 도움을 받았습니다. 

https://techytok.com/lesson-variable-scope/



Julia 개발 환경 구축은 다음 포스트를 참고하세요. 

 

Visual Studio Code 사용한 Julia 개발 환경만들기(Windows / Ubuntu / Macbook M1)

https://webnautes.tistory.com/2216 



Julia 강좌를 진행하고 있습니다.

 

Julia 강좌 1 - 변수와 데이터 타입

https://webnautes.tistory.com/2218 

 

Julia 강좌 2 - 함수, void function,  Optional positional arguments, Keyword arguments

https://webnautes.tistory.com/2220 

 

Julia 강좌 3 - 배열, 튜플, 딕셔너리

https://webnautes.tistory.com/2229 

 

Julia 강좌 4 - 제어문 if ... else, for, break, continue, while, enumerate

https://webnautes.tistory.com/2235 

 

Julia 강좌 5 - 브로드캐스팅(broadcasting)

https://webnautes.tistory.com/2240 


Julia 강좌 6 - 변수 유효 범위( Variable Scope ) : 전역(global), 로컬(local)

https://webnautes.tistory.com/2247

 

Julia 강좌 7 - 모듈(module)

https://webnautes.tistory.com/2253 

 

Julia 강좌 8 - 타입(type)

https://webnautes.tistory.com/2260

 

Julia 강좌 9 - 패키지(package)

https://webnautes.tistory.com/2268 

변수 유효 범위( Variable Scope )

 

변수의 유효 범위는 선언된 변수를 접근 할 수 있는 프로그램의 영역을 의미합니다. 전역(global) 범위와 로컬(local) 범위의 두 가지 주요 유형이 있습니다.

 

  • 전역 범위(Global Scope) : 전역 범위에 선언된 변수는 프로그램 전체에서 접근 가능합니다. 하지만, Julia에서는 모듈 또는 스크립트별로 전역 범위가 다를 수 있습니다.

 

  • 로컬 범위(Local Scope) : 로컬 범위에 선언된 변수는 그 변수가 선언된 함수, 루프, 블록 등 특정 영역 내에서만 접근 가능합니다. 이러한 변수는 선언된 영역 밖에서는 접근할 수 없습니다.

 

로컬 범위(Local Scope)

함수 내부에 선언된 각 변수는 함수 내부에서는 자유롭게 접근할 수 있지만 함수 외부에서는 접근할 수 없습니다. 따라서 함수 별로 똑같은 이름의 변수를 선언하여 사용할 수 있습니다. 

 

함수 내부에서 계산된 값을  함수 외부에서 필요로 할 수 있습니다. 이 경우 함수 외부의 전역 변수에 값을 저장하는 대신 함수 내부에서 계산된 값을 반환하는 것이 좋습니다.  일반적으로 함수 내부에서는 파라미터로 전달된 변수의 값을 사용하여 내부에서 계산 후, 결과를 반환하는 것이 좋습니다. 함수 내부에서 외부의 전역 변수를 직접 접근하는 것은 가급적 피하는 것이 좋습니다. 

 

함수 내부(로컬 범위)에는 존재하지만 전역 범위에는 존재하지 않는 변수의 예를 살펴보겠습니다:

 

function f()
    z = 42
end

f()  # 함수 f를 호출하여 내부에 변수 z가 선언되었지만
println(z) # 함수 외부에선 변수 z에 접근할 수 없습니다.

 

다음과 같은 에러가 발생합니다.  함수 외부에서는 함수 내부에 있는 변수 z에 접근할 수 없기 때문에 변수 z가 선언되어 있지 않다는 에러가 발생합니다.  

 

ERROR: LoadError: UndefVarError: `z` not defined

Stacktrace:

 [1] top-level scope

   @ ~/julia/hello.jl:6

in expression starting at /Users/webnautes/julia/hello.jl:6



권장하는 방법은 아니지만 함수 외부에서 함수 내부에 있는 변수 z에 접근할 수 있도록 할 수는 있습니다. 

 

function f()
    global z = 42
end

f()  # 함수 f를 호출하여 내부에 변수 z가 전역 변수로 선언되면
println(z) # 함수 외부에서 변수 z에 접근할 수 있습니다.

 

함수 내부에 선언된 변수 z의 값이 출력됩니다.

 



하지만 이보다 더 나은 방법은 함수에서 값을 반환하고 함수 외부에서 이 값을 저장할 변수를 준비하도록 하는 것입니다. 

 

function f()
    z = 42

    return z # 변수 z의 값을 반환합니다.
end

ret = f()  # 함수 f가 반환한 값을 변수 ret에 저장합니다.
println(ret) # 변수 ret에는 함수 내부에 있던 변수 z의 값을 가지고 있습니다.  

 

함수 내부의 값을 반환받아서  화면에 출력합니다.

 



함수 내부에서 전역 변수의 값을 변경하기 위해서 global 키워드를 사용해야 합니다. 사용하지 않으면 함수 내부에서만 변경된 값이 유지됩니다.  전역 변수에 접근하여 값을 출력시에는 global 키워드를 사용할 필요가 없습니다. 

 

# 전역 변수 선언합니다.
global_var = 10

function testFunction()
    # 전역변수와 똑같은 이름의 로컬 변수 선언시 local 키워드를 사용합니다.
    local_var = 20
   
    println("Local variable: ", local_var)  # 로컬 변수를 출력합니다.
    # Local variable: 20

    global global_var = 25  # 전역 변수의 값을 변경합니다.
    println("Global variable: ", global_var)  # 전역 변수를 출력합니다.
    # Global variable: 25
end

testFunction()

# 함수 밖에서 전역 변수를 출력합니다.
println("Accessing global variable outside function: ", global_var)
# Accessing global variable outside function: 25



let 구문  

특정 변수가 let 블록내에서만 유효하도록 만들어 줍니다. 그래서 외부의 변수를 let 블록내에서 접근 가능하지만 외부에서 let 블록 내에서 사용된 변수에 접근할 수 없습니다 



기본적으로 let 블록은 다음과 같이 구성됩니다:

 

let [변수 정의]
    # 코드 블록
end

 

여기서 [변수 정의] 부분에는 하나 이상의 변수 선언이 포함될 수 있으며, 이 변수들은 let 블록 내에서만 유효합니다.



다음 코드에서 전역 변수 x와 let 블럭 내의 변수 x는 별개입니다. 따라서 let 블록 내부에서 변수 x의 값은 5이지만, 블록 밖에서 변수 x의 값은 1입니다.

 

x = 1
# 젼역 변수 x를 선언합니다.

let x = 5

    # let 블럭 내에서 변수 x를 선언합니다.
    println(x) 
    # let 블럭내 변수 x의 값이 출력됩니다.
    # 5
end

println(x)
# let 블럭의 x와 별개이기 때문에 전역 변수 x의 값이 그대로 출력됩니다.
# 1






let 블록 내에서 선언된 변수 x는 블록 내에서만 정의됩니다. 그래서 let 블록 내에서는 전역 변수 y에 접근 가능하지만 외부에서는 let 블록에서 선언된 변수 x를 사용할 수 없습니다.

 

y = 1
# 전역 변수 y를 선언합니다.

let x = 5
    println(x) 
    # let 블록내에 선언된 변수 x의 값이 출력됩니다.
    # 5
    println(y)
    # 전역 변수 y의 값이 출력됩니다.
    # 1
end

println(x)
# let 블록 밖에선 변수 x가 정의되어 있지 않다고 에러납니다. 

 

실행 결과 변수 x는 let 블럭 내에서만 사용가능하도록 정의되어 있어서(전역 범위에서 정의되지 않았기 때문에) 다음처럼 변수 x가 정의되지 않았다고 에러가 발생합니다.

 

5

1

ERROR: LoadError: UndefVarError: `x` not defined

Stacktrace:

 [1] top-level scope

   @ ~/julia/hello.jl:7

in expression starting at /Users/webnautes/julia/hello.jl:7



let 블록의 계산 결과를 블록 외부에 반환할 수 있습니다. 

 

c = let i=10
    # let 블록에 변수 i를 선언합니다. 변수 값은 10으로 초기화 합니다.
    # let 블록의 반환값이 변수 c에 저장되도록 합니다.

    i+=42
    # 변수 i의 값이 42를 더합니다.

    i 
    # 변수 i의 값을 반환하여 변수 c에 합니다.
end

println(c)
# 52

println(i)
# let 블록내의 변수 i에는 접근할 수 없기 때문에 에러가 납니다. 
# ERROR: LoadError: UndefVarError: `i` not defined



begin 블록도 let 블록과 유사하지만 블록 외부에서 begin 블록내의 변수에 접근할 수 있습니다. 

 

d = begin
    # begin 블록내의 반환값은 변수 d에 저장되도록 합니다.

    i=41
    # 변수 i를 선언하고 초기값을 41로 합니다.

    i+=1
    # 변수 i의 값에 1을 더합니다.

    i
    # 변수 i를 반환하여 변수 d에 저장합니다.
end

println(d)
# begin 블록에서 반환받아 변수 d에 저장된 변수i의 값이 출력됩니다.
# 42

println(i)
# begin 블록 내의 변수 i를 바로 접근하여 출력할 수 있습니다.
# 42



begin 블록은 여러 표현식을 하나의 그룹으로 묶어 실행하는데 사용됩니다. 이러한 표현식들은 순차적으로 실행되며, begin 블록의 결과값은 마지막 표현식의 결과값이 됩니다.

 

begin 블록의 기본 구조는 다음과 같습니다:

 

begin
    # 여러 표현식
end



`begin` 블록은 주로 조건문이나 함수 정의 내에서 여러 표현식을 순차적으로 실행해야 할 때 유용합니다. 또한, 한 줄에 여러 표현식을 쓰고 싶을 때도 사용됩니다.

 

예를 들어 변수 x와 변수 y를 선언 후 더한 결과를 계산하는 것을 begin 블럭 내에서 할 수 있습니다. 

 

z = begin
    x = 1
    y = 2
    x + y
end

println(z)
# 3




전역 범위(Global scope)

함수나 특정 블록 외부에서 선언된 변수는 전역 범위에 속합니다. 전역 변수는 프로그램의 어디서나 변수의 값을 읽을 수 있습니다. 하지만,  함수 내부 또는 블록 내에서 에서 전역 변수의 값을 변경하려면, global 키워드를 사용하여 해당 변수를 전역 변수임을 명시해야 합니다. 

 

x = 0
# 젼역변수 x를 선언하고 값을 0으로 초기화합니다.

let y = 5
    global x = 10
    # let 블록내에서 전역변수 x의 값을 변경하려면 global 키워드를 사용해야 합니다.
end

println(x)
# 변수 x의 값이 let 블록 내에서 변경되었습니다.
# 10




상수(Constants)

Julia에서 전역 변수를 사용하면 성능이 떨어지기 때문에 가급적 사용을 피해야 합니다. 전역변수를 사용해야 한다면 상수로 선언하는 것이 좋습니다.  이렇게하면 성능 문제가 완화됩니다. 왜나하면 상수는 데이터 타입을 변경할 수 없어서 컴파일러가 최적화하는데 유리하게 됩니다.  

 

Julia의 상수는 일단 정의되면 데이터 타입을 변경할 수 없는 변수라서 상수의 데이터 타입을 변경하려고하면 에러가 발생합니다. 반면 상수의 값을 수정하려고 하면 경고 메시지를 출력합니다.  

 

const C = 299792458
# 상수 C를 선언합니다. 여기에선 정수 데이터 타입이 됩니다. 

C = 300000000
# 기존 상수 C의  데이터타입과 동일한 정수 데이터타입의 값으로 변경하려고 하면 경고 메시지가 출력됩니다.
# WARNING: redefinition of constant C. This may fail, cause incorrect answers, or produce other errors.

C = 2.998 * 1e8
# 기존 상수 C의 데이터 타입인 정수가 아닌 값으로 값을 변경하면 에러가 발생합니다.
# ERROR: LoadError: invalid redefinition of constant C




모듈(Modules)

모듈 별로 독립적인 전역 범위를 가지기 때문에 모듈에서 선언된 전역 변수는 외부에서 접근하는것이 제한되어 있습니다. 해당 변수를 외부에서 접근가능하도록 export로 지정하거나  모듈이름.전역변수이름 방식으로 접근할 수 있습니다. 



export를 사용하는 예제 코드입니다. 

 

module ScopeTestModule
# 모듈의 시작을 선언합니다.

export a1
# 모듈내 전역 변수 a1은 외부에서 접근가능하도록 합니다.

# 전역변수를 선언합니다.
a1 = 25
b1 = 42

end
# 모듈 끝에 end를 적어줘야 합니다.



using .ScopeTestModule
# 이제 앞에서 정의한 모듈을 사용합니다.

println(a1)
# 변수 a1의 값은 가져올 수 있습니다. export로 지정했기 때문에 가능합니다.
# 25

println(b1)
# 변수 b1의 값은 가져올 수 없기 때문에 에러가 발생합니다.
# ERROR: LoadError: UndefVarError: `b1` not defined




모듈이름.전역변수이름 을 사용하는 예제 코드입니다. 

 

module ScopeTestModule
# 모듈의 시작을 선언합니다.

# 전역변수를 선언합니다.
a1 = 25
b1 = 42

end
# 모듈 끝에 end를 적어줘야 합니다.



using .ScopeTestModule
# 이제 앞에서 정의한 모듈을 사용합니다.


println(ScopeTestModule.b1)
# export 없이 모듈내 변수의 값을 읽을땐 이 방식을 사용해야 합니다.
# 42

ScopeTestModule.a1=100
println(ScopeTestModule.a1)
# 이 방식으로 모듈 내의 변수의 값을 변경하거나 읽어올 수 있습니다.
# 100

ScopeTestModule.b1=200
println(ScopeTestModule.b1)
# 200



반응형

문제 발생시 지나치지 마시고 댓글 남겨주시면 가능한 빨리 답장드립니다.

도움이 되셨다면 토스아이디로 후원해주세요.
https://toss.me/momo2024


제가 쓴 책도 한번 검토해보세요 ^^

+ Recent posts