본문 바로가기

Python

Python 함수 선언 방법, 변수 지역성

728x90

함수 선언

Python 함수 선언 방법은 다음과 같다.

def my_function():
  print("Hello from my_function()")

 

↑  인자를 받지 않는 함수

def my_function(arg1, arg2):
  print(arg1, arg2)

 

↑  Positional Argument. 2개의 인자를 받는 함수 

def my_function(*args):
    print(type(args))
    print("The first argument is", args[0])

my_function("A", "B", "C")

>> <class 'tuple'>
>> A

 

Positional Argument Packing. 여러 인자를 받는 함수. 여기서 args는 tuple 타입으로 들어온다.

 

def my_function(a, b, c, *d):
  print(a, b, c, d)

my_function(1, 2, 3, 4, 5, 6, 7, 8, 9)

>> 1 2 3 (4, 5, 6, 7, 8, 9)

 

↑ Positional argument 3개와 Positional argument packing을 혼용한 함수

* 주의 : 가변 인자(*d)는 반드시 positional argument 후에 위치해야 한다.

def my_function(**args):
  print(args["blogname"])

my_function(blogname = "bithub")

 

Keyword Argument Packing. Key 값의 형태로 여러 인자를 받는 함수

def my_function(arg, *args, **args2):
    ...

 

↑ Keyword Argument Packing과 다른 매개변수를 혼용한 함수

* 주의 : Keyword argument pack(**args2)는 마지막에 위치해야 한다.

 


인자 기본값 설정하기

인자 기본값(Default parameter) : 함수 사용자가 인자를 따로 전달하지 않을 시 인자로 설정될 값을 설정할 수 있다.

def my_function(blogname="myblog", url="tistory.com", category="IT"):
  print(blogname, url, category)

my_function()

>> myblog tistory.com IT

 

** 주의사항1 : 인자 기본값은 오른쪽에서부터 채워져야 한다.

def my_function(blogname, url, category="IT"): # good
def my_function(blogname="myblog", url, category): # error

 

** 주의사항2 : 기본 인자 설정 시 불변객체(immutable object)로 설정되어야 한다. 리스트는 가변객체(mutable object)이기 때문에 __defaults__가 참조하는 객체에 이전 히스토리가 계속 쌓이는 것을 볼 수 있다.

def foo(x, items=[]): # not recommended
    items.append(x)
    print(items)
    pass

foo(1) # [1]
foo(2) # [1 2]
foo(3) # [1 2 3]
print(foo.__defaults__) # ([1, 2, 3],)

 

** 올바른 예시

def foo(x, items=None):
    if items is None:
        items = []

    items.append(x)
    print(items)
    pass

foo(1) # [1]
foo(2) # [2]
foo(3) # [3]

 


함수 인자 전달 방법

함수를 호출하는 방법에는 크게 2가지가 있다.

1. Positional Argument

2. Keyword Argument

 

1. Positional Argument : 위치에 따라 인자를 전달하는 방식

def my_function(blogname, url, category):
  print(blogname, url, category)

my_function("bithub", "bithub.tistory.com", "IT")

 

2. Keyword Argument : 매개변수의 이름에 따라 인자를 전달하는 방식

def my_function(blogname, url, category):
  print(blogname, url, category)

my_function(blogname="bithub", url="bithub.tistory.com", category="IT")

 

* Positional Arugment와 Keyword Argument는 같이 사용될 수 있다.

def my_function(blogname, url, category):
  print(blogname, url, category)

my_function("bithub", "bithub.tistory.com", category="IT")

 

* 주의 : Positional Arugment는 반드시 Keyword Argument보다 선행되어야 한다.

def my_function(blogname, url, category):
  print(blogname, url, category)

my_function("bithub", "bithub.tistory.com", category="IT") # good
my_function(blogname="bithub", "bithub.tistory.com", "IT") # error

함수도 객체다!

def my_function():
    print("Hello from my_function()")
    
print(type(my_function))
func = my_function # shallow copy
print(id(func))
print(id(my_function))

>> <class 'function'>
>> 2452672101920     
>> 2452672101920

 

Python의 함수는 객체다.

함수를 선언하고 정의하면 function이라는 클래스의 객체가 만들어진다.

일반 객체처럼 shallow copy가 이루어진다.


전역변수, 지역변수

x = "global variable"

def my_function():
    x = "local variable"
    print("Hello from my_function()")
    
my_function()
print(x) # global variable

 

함수에서 사용되는 모든 변수는 기본적으로 지역 변수(local variable)다.

 

x = "global variable"

def my_function():
    global x
    x = "changed"
    print("Hello from my_function()")
    
my_function()
print(x) # changed

 

함수에서 전역 변수(global variable)에 접근하기 위해서는 global 키워드를 사용해야 한다.

def my_function():
    global y
    y = "generated"
    print("Hello from my_function()")
    
my_function()
print(y) # generated

 

만약 global 키워드가 적용된 변수가 존재하지 않는다면 해당 전역변수를 생성한다.

g = "global"

def my_function():
    print(g) # only read is OK.
    
my_function()

>> global

 

위에서 언급했듯 매개인자를 포함하여 함수 내부의 모든 변수는 기본적으로 지역(local) 변수다.

그리고 전역변수를 참조하고 싶다면 global 키워드를 사용하면 된다고 설명했다.

근데 전역 변수를 쓰기(write)를 하지 않고 읽기(참조, read)만 한다면 global 키워드도 사용하지 않아도 된다.

이는 Python 인터프리터가 해당 변수가 어디있는지 알아서 찾아주기 때문이다.

glo = 1
def outer(x):
    out = 100

    def inner(y):
        global glo
        nonlocal out
        out = out + 1
        print(glo, x, out, y)

    inner(33)
    pass

outer(3)

>> 1 3 101 33

 

위 예제 코드를 보자.

위 코드에는 함수 안에 함수(nested function)가 구현되어 있다.

inner 함수에서 x는 읽기(참조)만 하므로 global이나 nonlocal 같은 키워드를 쓸 필요없다.

glo와 out 변수는 쓰기까지 하므로 전역 변수와 외부함수의 지역변수임을 알려주는 global 키워드와 nonlocal 키워드를 사용해야 한다.


Argument Forwarding

함수의 인자를 그대로 다른 함수의 인자로 전달하는 것을 argument forwarding이라고 한다.

위에서 언급했듯, Positional Argument Packing 시 args는 tuple 타입이다.

그래서 다른 함수로 argument forwarding 시, unpacking 후에 forwarding 해야 한다.

def func1(*args)
    func2(*args) # good. func2(1, 2, 3, 4)
    func2(args) # bad. func2((1, 2, 3, 4))
    
def func2(*args)
    print(args)