*공부하며 정리한 내용입니다. 틀린 내용이 있을 수 있습니다.

정적 타입 언어 : 자료형을 컴파일 타임에 결정(바인딩)하는 언어 (컴파일 언어)
동적 타입 언어 : 자료형을 런타임(실행 시점)에 결정(바인딩)하는 언어 (인터프리터 언어)
약타입 언어 : 자료형이 맞지 않을 시에 암묵적으로 타입을 변환하는 언어
강타입 언어 : 자료형이 맞지 않을 시에 에러 발생, 암묵적 변환을 지원하지 않음

파이썬은 동적타입이면서, 강타입 언어입니다.

파이썬의 모든 구성 요소의 자료형은 객체(Object)입니다. 객체란 Data를 메모리에 할당시켜주는 ‘공간’입니다. id(object)는 Argument로 제공된 객체를 위한 ‘고유한 상수’를 반환하는 함수로서 두객체의 id함수 반환 값을 비교하여 ‘동일 여부’를 확인할 수 있습니다. 한편, ‘객체 유형’을 식별하기 위해 사용하는 이름을 ‘식별자’라고 하며, 식별자에는 변수, 함수 등이 있습니다.

변수란 담기는 data의 값이 변할 수 있는 어떤 객체를 지칭합니다.

함수는 Input(parameter)을 받아 어떠한 계산 혹은 기능을 실행하고 결과값(return)인 Output을 생성합니다. parameter 와 return 은 optional 입니다. Input parameter가 없는 함수도 있을 수 있으며 리턴값이 없는 함수도 있을 수 있습니다.

함수를 처음 ‘선언’할 시에, 함수를 작동시킬 재료(input)로서 사용될 미정의 data를 담게 될 공간 즉 객체의 식별자는 변수이며 선언 시 함수에 ‘종속’될 이것을 매개변수(인자, parameter)라고 합니다. 한편, 선언된 함수를 ‘호출’할 때, 매개변수에 data를 옮겨 담기 위해 사용하는 변수 또는 특정 data를 지칭하여 인수(argument)라고 합니다.

Data에는 mutable 타입과 immutable 타입이 있습니다. immutable이란 불변적인 성질을 나타냅니다. 예를 들어 a라는 변수에 30000이라는 정수 data를 대입한 후, id(object) 함수의 매개변수인 object에 변수명인 a를 대입한다면 id(object=a) 또는 id(a)로 나타낼 수 있습니다. 이 때, a에 부여된 고유한 상수값이 4321이라고 가정합니다. 변수 a에 50000라는 정수 data를 대입한 후 다시 이 과정을 반복한다면, a에 부여된 상수값은 4321이 아닌 다른 상수값으로 변경되어 있습니다. 즉 30000이라는 data가 저장된 ‘위치’와 50000라는 data가 저장된 ‘위치’가 다르며, 변수 a에는 원래 data 30000의 위치가 담겼지만 변경된 위치에 담긴 data 50000가 전달되어 뒤집어 씌워졌습니다(오버라이드). 한편, 변수 b에 [‘사과’, ‘배’, ‘오렌지’] 라는 리스트 data를 대입한 경우와 [‘사과’, ‘배’, ‘오렌지’, ‘포도’]라는 리스트 data를 대입한 경우에 대하여, id(object)를 이용해 동일 여부를 검증할 시, 같은 상수값이 나오게 됩니다. ‘리스트 내부’의 원소 ‘사과, ‘배’, ‘오렌지’, ‘포도’는 문자열 data이며 ‘각각’ 할당된 메모리의 ‘위치’가 다르지만, 이들을 담고 있는 ‘리스트’는 원소와는 별도의 위치(원소의 크기에 따라 사용할 메모리가 달라지기 때문에 별도의 공간 확보)를 가지고 있는 객체 형태입니다. 전자의 식에서 변수 a가 지칭하는 것이 고유하고 크기가 확정된 메모리 위치를 가진 정수 data였다면 후자의 식에서 변수 b가 지칭하는 것은 고유하지만 크기가 확정되지 않은 메모리 위치를 가진 리스트 객체이기 때문에 리스트 내부 원소 ‘data가 변경되더라도 동일한 위치’ 값을 반환합니다. 전자와 같은 정수형 data의 사례를 immutable data 타입, 후자와 같은 리스트 data의 사례를 mutable data 타입이라고 합니다.

한편, 앞서 파이썬은 data 타입(자료형)을 런타임(실행 시점)에 결정(바인딩)하는 언어(인터프리터 언어)라고 하였습니다. 실행이 되지 않고, 코드로 선언만 한 상태에서는 아직 메모리를 할당받지 못했다는 뜻입니다. 코드를 실행(런타임)하면서 변수(객체)에 자료형을 바인딩(결정)할 때 코드의 흐름에서 같은 변수명이 여러 번 등장한다면 어떤 기준으로 값을 참조(reference)할까요? 이를 유효범위(scope)라 합니다. 파이썬의 변수 scope 규칙은 LEGB 룰이라고 불리기도 합니다.

변수가 값을 찾을 때, Local -> Enclosed -> Global -> Built-in
local – 함수(코드블록 이상) 범위.
Enclosed - 파이썬은 함수 실행문 안에서 다른 함수가 정의될 수 있는데, 가장 가까운 함수가 아닌 두번째 이상의 함수 가까운 함수 범위 입니다.
Global - 함수 바깥의 변수 또는 import된 module
Built-in – 파이썬 안에 내장되어 있는 함수 또는 속성들입니다.

def love_you(my_name, your_name):
print (f “{my_name} loves {your_name}”)

위와 같은 함수 선언문에서 input 부분은 마치 매개변수로 이루어진 리스트로 보여집니다. 앞서 살펴본 바에 따르면 리스트 data는 mutable data 타입이며, 형태는 객체이고, 리스트 내부의 원소는 종류에 따라 immutable 일수도 mutable일 수도 있습니다.

“정우성”, “아이유”라는 문자열 data는 immutable 타입이며, input 공간(객체, 리스트)에 인수로서 순서대로 love_you(“정우성”, “아이유”)와 같은 형태로 대입하여 호출하면, “정우성 loves 아이유” 가 출력됩니다. 함수 호출 시, 실행문의 순서대로 실행 코드 상의 변수 {my_name}, {your_name} 에 바인딩할 data를 탐색합니다. 호출된 함수 외부(전역)에서 선언문의 매개변수 my_name, your_name를 참조할 것이고, 이 매개변수들에는 각각 “정우성”, “아이유” 라는 문자열이 동일한 함수명을 가진 함수 호출문의 argument로 대입되어 있습니다. 즉 함수 실행을 위해 전역범위를 참조하였고 이 전역범위에서 다시 호출문의 argument를 참조하여 바인딩 된 자료형은 immutable한 문자열 data입니다.

loves_you(your_name=”아이유”, my_name=”정우성”)의 형태(keyword argument)로 매개변수 공간(객체, 리스트)에 들어갈 원소를 변수 정의문의 나열로 바꾸어 호출을 시도하였습니다. 함수의 실행과 함께 실행문 print (f “{my_name} loves {your_name}”) 내부의 변수들은 함수 선언문 자체에서 정의된 각각의 변수들을 참조합니다. 그렇기 때문에 실행문의 변수 나열 순서와 관계없이, argument가 Input 공간에 담기는 순서(positional argument)에 관계 없이 정상적으로 실행됩니다. 참조된 변수는 mutable 하지만 “아이유” 등 문자열은 immutable 하기 때문에 “바다” 등 다른 data로 오버라이드 할 수 있습니다.

한편, love_you(your_name = "아이유", "정우성")처럼 변수 정의문과 문자열로 이루어진 인수가 섞여서 호출될 때, 함수 선언문 매개변수의 순서와 다르다면, 어떻게 될까요? 호출 시 실행문 print (f “{my_name} loves {your_name}”) 의 순서대로 변수의 바인딩, 선언 및 메모리 할당이 이루어지는 과정에서, {my_name}은 전역 범위에서 동일한 함수명을 가진 함수 선언문의 매개변수 my_name을 참조하려 하지만, 여기에는 바인딩 된 자료형을 찾을 수 없습니다. 왜냐하면 함수 호출문의 argument에서 선언문 매개변수 순서를 따라 my_name을 찾으려 하면 그 자리에 your_name=”아이유” 변수 정의문이 있기 때문입니다.

Traceback (most recent call last):
File "python", line 1
SyntaxError: positional argument follows keyword argument

이제 함수 선언 시에 parameter에 default 값을 정의해봅시다.

def love_you(my_name, your_name=”아이유”) :
print (f “{my_name} loves {your_name}”)

love_you(“정우성”) 과 같이 두번째 매개변수 위치에 argument를 대입하지 않은 형태로 호출할 시에는 어떻게 될까요? 호출문 내부의 실행문 print (f “{my_name} loves {your_name}”)에서 {my_name}은 전역범위에서 동일한 함수명을 가진 함수 선언문 매개변수 my_name을 거쳐 호출문의 인수 “정우성”을 지칭하고, 문자열을 바인딩합니다. 한편, {your_name}은 전역범위에서 동일한 함수명을 가진 함수 선언문 내부에서 ”아이유”로 정의된 변수 your_name을 참조(“아이유” 문자열 data 위치가 아닌 매개변수 your_name의 위치를 참조)합니다. 출력 결과는 정우성 loves 아이유로 정상입니다.

def love_you(my_name = "정우성", your_name):
print(f"{my_name} loves {your_name}")

조심해야 할점은 default 값이 정의된 parameter가 default 값이 정의되지 않은 parameter 보다 먼저 위치해 있으면 안된다는 점입니다. 만일 default value parameter를 non-default value parameter 앞에 선언하면 syntax error가 납니다.

Traceback (most recent call last):
File "python", line 1
SyntaxError: non-default argument follows default argument

love_you(“정우성”)으로 호출 시 실행문의 {my_name}은 함수 선언문 내부에서 문자열 “정우성”으로 정의된 매개변수 my_name을 참조하여 가져오지만, {your name}은 선언문 내부에서도, 어디에서도 정의되지 않았기 때문에 바인딩할 자료형을 찾을 수 없기 때문입니다.