03. 함수

송지윤·2025년 7월 30일

Python

목록 보기
10/20

함수로 코드 재사용

자주 사용하는 코드를 함수, 클래스, 모듈로 만들어두고 필요할 때마다 재사용하면 된다.

함수의 이해

함수를 한마디로 말하면 재사용할 수 이쓴 코드 블록이다. 여러 개의 구문을 하나로 묶어서 특정 기능을 수행하는 함수로 만들어두고 필요할 때마다 함수를 호출해서 사용하는 것이다.
함수의 밖에서 안으로 어떤 값을 넘기면 함수 내부에서는 받은 값을 이용해 다양한 연산을 수행하고, 그 결과를 함수를 호출한 곳으로 넘긴다.
return (함수를 호출한 곳으로 되돌아 간다)
return 값은 있을 수도 있고, 없을 수도 있음. return만 쓰거나 return 생략

매개변수도 하나 혹은 여러 개, 없을 수도 있다.

parameter(매개변수), argument(인자값)
함수에서 쓰이는 값은 input과 output으로 구분할 수 있다.

  • input
    함수의 외부에서 함수를 호출할 때 넘겨주는 값으로, 매개변수 또는 인자값이라고 한다.
    - 함수명 다음의 괄호() 안에 입력한다.
    - 매개변수는 없을 수도 있고, 여러 개일 수도 있다.
    - 매개변수가 없다고 해서 함수 다음의 괄호()를 생략할 수는 없다.
    - 매개변수로 선언된 변수 앞에는 변수의 타입을 명시하지 않는다.
    - 함수를 호출할 때는 함수를 선언할 때 명시한 대로 매개변수를 전달해야 한다.

매개변수와 인자값의 차이점

매개변수(파라미터, parameter)는 함수 선언부의 변수 목록을 의미하고, 인자값(아규먼트, argument)은 함수가 호출될 때 전달되는 실제 값을 의미한다. 즉, 다음 그림에서 함수의 선언부에 정의된 num1, num2를 매개변수라 하며, 함수를 호출할 때 전달하는 값인 10과 20을 인자값이라고 한다.

def sum(num1, num2) : # num1, num2 매개변수
	return num1 + num2

sum(10, 20) # 함수 호출하는 부분에서 넘기는 인자값

매개변수와 인자값은 쓰이는 곳에 따라 의미적인 차이가 있지만, 일반적으로는 둘 중 하나로 통일하여 부르기도 한다. (구분하지 않고 사용해도 됨)

  • output
    - 함수를 실행한 뒤 함수를 호출했던 곳으로 넘겨주는 결과값으로, 리턴값(반환값)이라고 한다.
    - 리턴값은 없을 수도 있으며 여러 개의 값을 튜플로 묶어서 전달할 수도 있다.
    - 함수의 구현부 마지막에 작성하는 return문은 생략할 수 있다.
    - return문에 값이 없거나 return문을 생략하면 return None으로 간주한다.
    - return문의 생략은 함수를 호출한 곳으로 리턴할 때 아무런 값도 가지고 가지 않는다는 의미이지 리턴이 안 된다는 의미가 아니다.
    - 리턴값이 없어도 함수를 호출했던 곳으로 돌아간다.

None

None은 아무런 값이 없음을 의미한다. 다른 언어에서 사용하는 null과 같은 값이라고 보면 된다. None은 NoneType 자료형의 유일한 값으로, 파이썬에서는 return문이 없거나 return문에 값이 없는 모든 함수의 마지막에 return None을 사용한다.

함수의 선언과 구현

함수를 사용하기 위해서는 먼저 함수 선언과 기능을 구현하고, 이후에 함수를 호출하는 과정을 거친다. 함수의 선언이란 함수의 이름과 매개변수 등을 명시하는것이고, 함수의 구현은 함수가 수행하는 작업을 정의하는 것이다. 함수의 선언과 구현은 동시에 이루어진다. 선언부와 구현부는 콜론(:)으로 구분한다.
한번 선언된 함수는 여러 번 호출할 수 있으며, 함수 실행을 종료하면 함수를 호출했던 코드로 되돌아간다. 함수 이름 다음에는 괄호를 붙여서 함수임을 나타내고, 함수를 호출할 때도 괄호를 꼭 붙여야 한다. 그럼 이제 이름 있는 함수와 이름 없는 함수, 두 가지 유형을 살펴보자.

이름 있는 함수 만들기

함수를 선언하는 형식은 다음과 같다.

def 함수명(매개벼수) :
	구문
    return 리턴값
  • 함수의 선언부는 def(define의 약자)로 시작하고 콜론으로 끝난다.
  • 함수 이름 다음의 괄호 안에는 매개변수를 선언하는데, 변수의 타입 없이 변수 이름만 입력한다. 매개변수는 경우에 따라 기본값을 가질 수 있다.
  • 함수 구현부의 시작과 끝은 코드의 들여쓰기로 구분하므로 따로 명시할 필요가 없다. 같은 함수의 구현부는 들여쓰기 수가 모두 같다.

자바에서는 매개변수의 타입을 작성해야하고 변수의 타입이 달라질 때마다 함수를 재정의 해야함 -> method overloading
파이썬은 method overloading 불필요

이름 없는 함수 만들기

함수는 이름 없이 만들 수도 있다. 이름이 없는 함수를 람다(lambda) 함수라고 하며, 다른 언어에서는 익명 함수(anonymous function)라고 부른다. 람다 함수는 다음과 같은 형식으로 선언한다.

lambda 매개변수 : 구문
  • 이름이 없이 lambda로 시작하며, 함수의 매개변수와 구현부만 존재한다.
  • 람다 함수에는 return문을 작성할 수 없다. return문이 있으면 에러가 발생한다.
  • 함수에 함수를 매개변수로 넘겨줄 때와 같이 한 줄 정도의 간단한 함수가 필요할 때 사용한다.

그렇다면 이름이 없는 람다 함수는 어떻게 호출해서 사용할까? 람다 함수는 주로 다음과 같은 네 가지 방식으로 사용할 수 있다.

첫째, 람다 함수를 선언함과 동시에 호출한다.

(lambda a : a+a)(10)
// 20

둘째, 람다 함수를 변수에 할당하여 사용한다. (가장 많이 쓰는 형태)

func = lambda a, b : a+b
func(10, 20)
// 30

함수를 변수에 할당하거나, 함수를 다른 함수의 리턴값으로 넘기거나, 함수를 다른 함수의 매개변수로 넘기는 것이 가능한 이유는 모두 함수형 언어의 특징과 관련이 있다.

셋째, 람다 함수를 다른 함수의 리턴값으로 넘겨서 사용한다. myFunc() 함수 호출 시 넘기는 매개변수 20은 n에 할당하고, 10은 lambda의 x에 할당한다.

def myFunc(n) :
	return lambda x : x+n

myFunc(20)(10)
// 30

앞에 있는 n 이 myFunc 의 매개변수고 뒤에 10이 lambda 의 매개변수
괄호 자체를 2개 써야함 ,로 구분하는 거 아님(이건 매개변수 2개)

넷째, 람다 함수를 다른 함수의 매개변수로 넘겨서 사용한다.

a = [1,2,3,4]
b = [5,6,7,8]
list(map(lambda x, y : x+y, a,b)
// [6, 8, 10, 12]

예시에서 사용한 함수는 map(function, ierable, ...) 함수이다. 이 함수는 첫 번째 매개변수로 함수(function)를, 두 번째 매개변수로는 반복 가능한 이터러블 객체(iterable)를 받아서 매개변수로 쓰인 함수를 이터러블 객체의 모든 요소에 적용하는 함수이다. 리턴값으로는 매개변수로 쓰인 함수에 의해 변경된 이터러블 객체를 리턴한다.

함수 매개변수

기본 매개변수

하나 이상의 매개변수가 '매개변수=값' 형식을 가질 때 함수는 기본 매개변수 값(default parameter values)을 갖는다고 한다. 기본값을 가지는 매개변수를 기본 매개변수(default parameter) 또는 기본 인자값(default argument)이라고 하며 함수의 옵션 또는 함수의 속성이라고도 부른다.
기본 매개변수를 지정하면 매개변수가 필요한 함수를 호출할 때 매개변수를 넘기지 않아도 미리 지정해놓은 기본값이 할당된다. 기본 매개변수는 함수의 괄호 안에 '이름=값' 형태로 지정한다.
my_func() 함수에 기본 매개변수 a,b를 지정하고 기본 매개변수가 적용되는 다양한 경우를 살펴보자.

def my_func(a=10, b=20)
	return a*b

우선 매개변수를 입력하지 않으면 기본 매개변수인 a=10, b=20이 할당된다.

my_func()
// 200

매개변수를 입력하면 앞에서부터 차례대로 할당된다. 예를 들어 매개변수를 100하나만 입력하면 a=100, b=20이 할당되고, 100과 200을 입력하면 차례대로 a=100, b=200이 할당된다.

my_func(100)
// 2000
my_func(100,200)
// 20000

이름과 값을 함께 지정하면 해당 매개변수에 값이 할당되고, 나머지는 기본 매개변수가 할당된다. 즉, b=100을 입력하면 a=10, b=100이 할당된다.

my_func(b=100)
// 1000

이름과 값을 함께 지정하면 매개변수의 순서에 상관없이 해당 변수에 값이 할당된다.

my_func(=300, b=400)
// 120000
my_func(b=100, a=200)
// 20000

기본 매개변수를 사용할 때는 반드시 지켜야 할 규칙이 있다. 기본값을 가지는 매개변수 뒤에는 기본값이 없는 매개변수를 사용할 수 없다. 이를 지키지 않으면 에러가 발생한다.

def my_func(a, b=10, c, d=20) :

참고로 파이썬의 에러 메시지에는 매개변수(parameter) 대신에 인자값(argument)이라는 용어가 사용된다.

SyntaxError

SyntaxError는 구문 에러로, 주로 파이썬 문법을 어겼거나 변수나 함수의 이름에 오타가 있을 때 발생한다. 여기서는 기본값이 없는 매개변수가 기본 매개변수 뒤에 나왔다는 에러가 발생했다. 에러가 발생하면 구체적인 에러 내용이 바로 이어서 나오므로 에러 메시지를 잘 확인하자.

앞의 코드에서 매개변수의 위치를 다음과 같이 바꾸면 에러가 발생하지 않는다.

def my_func(a, c, b=10, d=20) :
	return a+c+b+d

기본 매개변수의 순서가 중요한 이유

기본 매개변수가 아닌 매개변수를 반드시 먼저 써야 하는 규칙은 프로그램을 작성하는 데 매우 편리한 장점이다. 주로 파일의 입출력이나 그래프를 그리는 함수들이 매개변수가 많은데, 예를 들어 매개변수가 40개인 함수를 호출한다고 생각해보자.
기본값이 있는 매개변수와 그렇지 않은 매개변수의 순서가 뒤섞여 있다면 어떨까? 실수로 기본값이 없는 매개변수의 값을 넘겨주지 않으면 에러가 날 것이다. 따라서 함수를 호출할 때마다 매번 함수의 정의를 비교해 보느라 함수를 호출하는 대만 한참이 걸린다.
이런 불편함을 줄이기 위해 기본값이 없는 매개변수를 앞에 쓰는 것이다. 기본값이 있는 매개변수가 나오기 시작하면 그 뒤로는 쭉 기본 매개변수일 것이다. 그러니까 우리는 기본 매개변수가 어디서 시작되는지만 파악하면 된다.
read_csv() 함수에 기본값이 없는 매개변수는 filepath_or_buffer 하나밖에 없기 때문에 이 함수를 호출할 때 반드시 넘겨야 할 매개변수는 한개인 셈이다.

키워드 매개변수

키워드 매개변수(keyword parameter)란 함수를 호출할 때 함수의 선언부에 있는 매개변수의 이름을 그대로 변수명으로 사용하는 것을 의미한다. 키워드 매개벼수는 기본값의 유무에 상관이 없다.
앞에서 설명했듯이 매개변수는 함수를 선언할 때 사용되는 변수를 의미하고 인자값은 함수를 호출할 때 전달하는 값을 의미하는데, 파이썬 공식 문서에서는 함수를 호출할 때 변수명을 사용하는 키워드 매개변수를 키워드 인자값(keyword parameter)이라고 표현한다.

다음은 전달받은 매개변수를 연결하여 url이라는 값을 return하는 함수이다.

def connet(server, port) :
	url = 'https://' + server + ':' + port
    return url

변수 대신 값을 전달할 수도 있으며, 앞에서부터 차례대로 할당된다.

connect('pypi.org', '80')
// 'https://pypi.org:80'

가변 매개변수

매개변수의 개수가 정해지지 않은 것을 가변 매개변수라고 한다. *를 배개변수 이름 앞에 붙이고, 값을 튜플 형식으로 전달하면 된다. 값은 없거나 여러 개일 수 있다.
다음은 전달받은 값과 값의 타입을 출력하는 함수다. type() 내장 함수로 자료형을 확인할 수 있다.

def func(*args) :
	print(args)
    print(type(args))
    
func()
// ()
// <class 'tuple'>

func(10, 20)
// (10, 20)
// <class 'tuple'>

딕셔너리 형태의 가변 매개변수

*를 두개를 붙인 **를 사용하면 가변 매개변수를 튜플이 아닌 딕셔너리 형식으로 전달할 수 있다. 다음 get_url() 함수는 server, port와 함께 이름=값을 쌍으로 하는 매개변수를 여러 개 받을 수 있다.

def get_url(server, port, **query) :
	url = 'https:.//' + server + ':' + port + '/?'
    for key in query.keys() :
    	url += key + "=" + query[key] + "&"
    return url

get_url('localhost', '8080', id='admin', pass='1234')
// 'https://localhost:8080/?id=admin&pass=1234&'

함수의 호출

함수를 선언하고 나면 함수를 이름으로 호출할 수 있다. 이때 함수의 선언부에 있는 대로 매개변수를 전달해야 한다. 선언 시 매개변수가 없었다면 아무것도 넘기지 않는다. 함수에 전달할 매개변수가 없다고 해서 함수를 호출할 때 괄호를 생략해서는 안 된다.
함수는 앞서 실습해본 def나 lambda를 이용해 사용자가 직접 만들 수 있고, 파이썬 표준 라이브러리나 서드파티 라이브러리에서 제공하는 함수를 호출할 수도 있다. 서드파티 라이브러리는 6장에서 설명한다.
함수를 호출하는 다양한 방법을 알아보자.

내장 함수 호출

파이썬에서는 파이썬 표준 라이브러리에서 기본으로 제공하는 내장 함수(Built-in Functions)를 호출할 수 있다. 내장 함수의 종류와 사용법은 파이썬 공식 문서에서 확인할 수 있다.
함수의 종류는 공식 문서뿐만 아니라 내장 함수 help() 함수를 통해서도 도움말 즉 독스트링(docstring)을 볼 수 있다. help() 함수에 다른 함수를 매개변수로 전달하면 그 함수가 어떤 기능을 수행하는지와 함수의 매개변수, 리턴값 등을 확인할 수 있다.

내장 함수는 다음과 같이 improt 문 없이 함수의 이름으로 호출하면 된다.
내장 함수인 help() 함수를 사용한 예시

help(print)

출력 결과

Help on built-in function print in module builtins:

print(*args, sep=' ', end='\n', file=None, flush=False)
    Prints the values to a stream, or to sys.stdout by default.

    sep
      string inserted between values, default a space.
    end
      string appended after the last value, default a newline.
    file
      a file-like object (stream); defaults to the current sys.stdout.
    flush
      whether to forcibly flush the stream.

내장 객체 타입 함수 호출

파이썬 표준 라이브러리에는 내장 객체 타입이 가지고 있는 함수도 있다. 내장 객체 타입(Built-in-Types)이란 파이썬에서 이미 만들어 놓은 객체(클래스) 타입을 의미한다. 앞에서 살펴봤던 리스트, 딕셔너리, 튜플, 세트, 문자열이 대표적인 내장 객체 타입이며 이 객체들이 가지고 있는 함수를 내장 객체 타입 함수라고 한다.
내장 객체 타입이 가진 함수를 호출할 때는 import문을 사용하지 않고 객체명 다음에 .을 찍어서 함수 이름을 호출한다.

객체명.함수명(매개변수, ...)

다음은 내장 객체 타입인 리스트를 생성한 뒤 리스트가 가지고 있는 append() 함수를 호출하는 예시

my_list = [1,2,3]
my_list.append(4)
my_list
// [1,2,3,4]

같은 모듈에 선언된 함수 호출

같은 모듈 내에서 사용자가 def로 정의한 함수를 호출하는 것을 말한다. 모듈이란 함수와 클래스 등을 묶어서 하나의 프로그램을 구성하는 단위를 말한다. 같은 모듈에 선언된 함수는 파이썬 내장 함수와 마찬가지로 import문을 사용하지 않고 함수 이름과 정의된 매개변수를 전달하면서 호출한다. 일반적으로 같은 모듈은 동일한 소스 코드 내부를 의미한다.

def func_test() :
	print('사용자 정의 함수')
    
func_test()
// '사용자 정의 함수'

다른 모듈에 선언된 함수 호출

모듈은 크게 세가지 형태로 구분할 수 있다.

  • 파이썬 표준 라이브러리에서 제공하는 모듈
  • 서드파티 라이브러리에서 제공하는 모듈
  • 사용자 정의 모듈

모듈에 있는 함수를 사용하려면 먼저 모듈을 임포트하고, 임포트한 모듈명과 함수를 호출하면 된다. 다른 모듈에 있는 객체 타입의 함수를 호출할 때는 모듈명과 객체명, 함수명을 모두 점으로 연결해서 사용하면 된다.

import 모듈명
모듈명.함수명(매개변수, ...)
모듈명.객체명.함수명(매개변수, ...)

파이썬에서 자주 사용하는 내장 함수를 정리해보면 다음과 같다. 함수를 모두 외우지 않아도 되며, 필요할 때마다 사용법 등을 찾아보면서 사용하면 된다.

  • type() : 매개변수의 타입을 리턴한다.
  • help() : 매개변수로 주어진 함수의 도움말을 볼 수 있다.
  • dir() : 모듈이나 클래스를 구성하는 목록을 보여준다.
  • input() : 사용자에게 텍스트 입력을 받는다.
  • len() : 문자열, 리스트 등 객체의 크기를 정숫값으로 리턴한다.
  • str() : 주어진 갑을 문자열로 변환한다.
  • range() : 주어진 범위의 이터레이터 객체를 리턴한다.
  • int() : 문자열 자료형을 숫자 자료형으로 변환한다.
  • list() : 매개변수로 주어진 값을 리스트로 변환한다.
  • max() : 리스트, 튜플, 문자열에서 최댓값을 리턴한다.
  • min() : 리스트, 튜플, 문자열에서 최솟값을 리턴한다.

함수의 독스트링
앞서 살펴본 것처럼 파이썬에서는 help() 함수를 이용하면 함수나 속성 등에 관련한 도움말을 제공해준다. 이러한 도움말을 독스트링(docstring, document string의 줄임말)이라고 한다.
그렇다면 파이썬에서 제공하는 도움말이 없는 사용자 정의 함수는 어떻게 할까? 사용자 정의 함수의 독스트링은 이미 만들어진 함수에 __doc__ 속성을 이용해 입력하는 방법과 함수를 정의할 때부터 함수 내부에 입력하는 두 가지 방법이 있다. __doc__은 앞뒤로 언더바를 두 개씩 붙인다.
첫 번째로 함수 선언과 정의를 먼저 하고 난 뒤 독스트링을 추가하는 방법을 알아보자. 실습을 위해 calc_salary라는 함수를 다음과 같이 만든다. 파이썬 셀에서 코드를 입력할 때는 들여쓰기를 항상 신경 쓰자.

def calc_salary(emp, salary) :
	base = 2000000
    extra = 5000000
    if emp == '사원' :
    	salary = base + salary
    elif emp == '임원' :
    	salary = base + salary + extra
    print('salary :', salary)

help() 함수로 calc_salary 함수의 사용법을 확인한다. 실행 결과를 보면 함수 이름 외에는 아무런 정보도 나오지 않을 것이다.
함수에 독스트링을 만들려면 '함수명__doc__'의 형태로 변수를 만들고, 내용을 입력하면 된다.
내용을 한 줄만 입력할 때는 따옴표를 하나씩 (' ' 혹은 " ") 사용하고, 여러 줄 입력할 때는 따옴표를 세 개씩(''' ''' 혹은 """ """)사용한다.
우리가 만든 사용자 정의 함수의 독스트링을 여러 줄로 입력해본다.

calc_salary.__doc__ = '''사용자 정의 함수.
emp : 입력값은 사원 혹은 임원,
salary : 급여
사원과 임원의 급여를 계산하여 출력한다.'''

다음과 같이 help() 함수로 calc_salary 함수의 사용법을 확인해보면 방금 작성한 독스트링이 출력되는 것을 확인할 수 있다.

두 번째 방법은 함수를 선언할 때 구현부에 독스트링을 추가하는 것이다. 함수 구현부가 시작되는 첫 번째 줄에 마찬가지로 따옴표로 내용을 입력하면 된다. 구현부의 첫 번째 줄에 입력하지 않으면 독스트링으로 처리하지 않는다는 점에 유의한다.

def calc_salary(emp, salary) :
	'''사용자 정의 함수.
    	emp : 입력값은 사원 혹은 임원,
        salary : 급여
        사원과 임원의 급여를 계산하여 출력한다.'''
      base = 2000000
      extra = 5000000
      if emp == '사원' :
          salary = base + salary
      elif emp == '임원' :
          salary = base + salary + extra
      print('salary :', salary)

다시 help() 함수로 calc_salary 함수의 사용법을 확인하면 방금 입력한 독스트링이 출력되는 것을 볼 수 있다.
이처럼 앞으로 학습할 모듈이나 클래스, 크래스의 메소드 모두 __doc__ 속성을 이용하거나 구현부의 첫 번째 줄에 따옴표로 문자열을 입력하면 독스트링으로 처리된다. 사용자 정의 함수는 이렇게 간단한 방법으로 도움말을 만들 수 있다.

독스트링이 필요한 이유

하나의 프로그램을 개발할 때는 여러 명이 공동 작업을 하는 경우가 대다수다. 따라서 독스트링으로 다른 개발자가 작성한 코드를 어떻게 호출하고 사용해야 하는지 도움말을 얻을 수 있다.
물론 혼자서 개발할 때도 독스트링을 작성해두면 수많은 함수나 클래스 모듈을 사용할 때 사용법을 쉽게 파악할 수 있고, 배포 시에도 해당 코드를 사용하는 다른 사용자들에게 사용법에 대한 도움말을 제공할 수 있어 매우 편리하고 유용한 속성이다.

파이썬은 표준 라이브러리뿐만 아니라 기타 라이브러리들도 독스트링이 아주 잘 만들어져 있다. 따라서 공식 문서나 help() 함수를 통해 도움말을 자주 확인하고 독스트링 작성 요령을 키워두는 것이 좋다.

변수의 호출 범위

변수는 선언된 위치에 따라서 전역 변수와 지역 변수로 나눌 수 있다. 변수는 전역 변수와 지역 변수 둘 중 하나에 속하며, 전역 변수이면서 동시에 지역 변수일 수는 없다.

  • 전역 변수(global variable) : 함수 밖에서 선언된 변수로, 특정 함수의 영역이 아닌 전역적인 범위에서 사용할 수 있는 변수다.
  • 지역 변수(local variable) : 함수 안에서 선언된 변수로, 함수 내부에서만 지역적으로 사용할 수 있는 변수다.

변수는 값을 담는 상자다. 상자가 사라지면 그 안에 저장된 값도 함께 사라진다. 전역 변수는 파이썬 프로그램을 실행하고 변수를 선언했을 때 만들어졌다가 프로그램을 종료하면 전역 범위가 파괴되어 사라진다. 전역 변수는 프로그램이 실행되는 중에 모든 함수에서 사용할 수 있다. 따라서 여러 함수에서 하나의 값을 공통으로 사용해야 한다면 전역 변수로 선언한다.
지역 변수는 파이썬 프로그램을 실행하고 함수가 호출될 때마다 만들어진다. 함수를 호출하면 지역변수가 만들어졌다가 함수의 수행이 끝나면 사라진다. 서로 다른 함수들 사이에서 각자의 지역 변수는 공유되지 않는다. 오직 변수가 선언된 함수 안에서만 사용할 수 있다. 따라서 서로 다른 함수에서는 같은 이름으 ㅣ지역 변수를 선언해도 된다.

전역 변수 count를 선언하고, my_func() 함수에 지역 변수 name을 선언한다.

count = 0
def my_func() :
	name = '지역변수'
    print(name)
    print(count)

my_func() 함수를 호출하면 지역 변수 name과 전역 변수 count가 모두 출력된다. 전역 변수 count는 모든 함수 안에서 얼마든지 참조할 수 있다.

def my_func() :
	name = '지역변수'
    count = count + 1
    print(name)
    print(count)
    
my_func()

전역 변수 count의 값을 1 증가시키도록 my_func() 함수를 변경하고 다시 호출한다.
지역 변수 count에 값이 할당되기 전에 먼저 참조되었다는 에러가 발생한다. 앞에서 count 변수를 참조만 했을 때는 분명 전역 변수 count를 잘 읽어왔는데, 값을 변경하려고 하니 count를 전역 변수가 아니라 지역 변ㅅ수로 인식한 것이다.
함수 안에서 전역 변수의 값을 변경하려면 global이라는 키워드를 사용해야 한다. my_func() 함수가 정상적으로 실행되도록 코드를 수정하면 다음과 같다.

def my_func() :
	name = '지역변수'
    global count
    count = count + 1
    print(name)
    print(count)
    
my_func()

여기서 주의할 점은 global 키워드로 count가 전역 변수임을 먼저 선언한 다음에 전역 변수를 참조해야 한다는 것이다. 즉, global 키워드를 통해 count 변수는 지역 변수가 아닌 전역 변수이므로 count라는 지역 변수를 만들지 말고 전역 변수 count를 참조하라고 알린 이후에 값을 할당해야한다. 만약 global count = count + 1 과 같이 작성하면 SyntaxError 에러가 발생한다.

변수의 호출 범위를 정리하면 지역 변수는 함수 사이에서 공유되지 않는 각 함수 고유의 변수이고, 전역 변수는 프로그램 실행 시에 딱 하나만 만들어져서 함수 사이에서 공유되는 변수이다.

변수를 참조할 때는 다음 순서대로 변수를 찾는다.
1. 함수 내부 영역, 지역 영역(local scope)
2. 함수 외부 영역, 전역 영역(global scope)
3. 파이썬에서 정의한 내장 영역(built-in scope)

함수형 언어의 특징

파이썬은 함수형 언어의 특징과 객체지향 언어의 특징을 모두 가지고 있다. 함수형 언어는 어떤 특징이 있는지 기본적인 사항만 알아보자.
Function is object
함수형 언어에서 함수는 객체이다. 객체는 메모리의 특정 주소값에 생성되므로 함수도 주소값이 할당된다. 객체가 메몸링 ㅔ만들어지면서 할당된 주소값은 사용자에게 직접 알려주지 않고 참조 변수(reference variable)에 저장된다. 우리가 함수를 호출하면 함수의 이름으로 된 참조 변수를 통해 함수 객체에 찾아갈 수 있는 것이다.

def test() :
	print('test 함수')

t = test
t()
// test 함수

객체의 메모리 주소값은 직접 알아낼 수 없으므로 임의로 10번지라고 가정하겠다. 객체의 주소값은 참조 변수에 할당되며, 우리는 참조 변수를 통해서 메모리의 객체를 참조한다고 했다.
먼저 test() 함수를 선언하ㅗ 호출하면 메모리의 특정 주소값인 10번지에 test() 함수 객체가 만들어지고, 이 주소값을 test에 할당한다.
그리고 t라는 변수에 test를 할당한다. 이때는 test 뒤에 괄호를 붙이지 않는다. 괄호를 붙이면 함수를 호출하는 것이고, 지금은 test가 가지고 있는 값인 함수 객체의 주소값을 t에 할당하는 것이므로 괄호를 붙이지 않는다. 그러면 test와 t는 동일한 주소값을 가지게 되며, 같은 함수를 참조한다. type(t)로 t의 타입을 알아보면 class 'function'이라고 나온다. 즉, t 변수는 class로부터 생성된 function 객체 타입이다. 이후 t()를 통해 test() 함수를 호출할 수 있다.
결국 함수가 객체이기 때문에 가능한 점들은 다음과 같다.

  • 함수를 매개변수로 전달할 수 있다.
  • 함수의 리턴 타입으로 함수를 사용할 수 있다.
  • 변수에 함수를 할당할 수 있다.

앞서 lambda 함수를 만들고 호출한 방식도 모두 이에 해당한다.

0개의 댓글