[ 백엔드 면접준비 : Python ] Python 면접 질문 정리_01
Ⅰ. 리스트와 튜플의 차이는?
1. 가변성 측면(Mutability).
∇ 리스트 (List)
리스트는 가변 객체(mutable)이다.
그래서 선언 후 리스트의 안에 요소 값을 수정, 삭제 가능하다 ✅
- 리스트는 대괄호 [ ]
- 리스트가 더 많은 메모리를 소모한다. 더 느리다
- 리스트가 삽입과 삭제같은 프로그래밍 작업을 수행하는데 더 낫다.
∇ 튜플 (Tuple)
튜플은 불변 객체(immutable)이다.
그래서 선언 후 리스트 안에 값을 수정, 삭제 불가능하다 ❌
- 튜플은 소괄호 ( )
- 튜플은 리스트보다 더 적은 메모리를 소모한다. 더 빠르다
- 튜플 데이터타입이 요소들에 접근하기에 더 적절하다.
튜플의 주요 특징.
1. 불변성 : 한 번 생성된 튜플은 변경할 수 없습니다.
2. 인덱싱과 슬라이스 : 리스트와 마찬가지로 인덱싱과 슬라이싱이 가능합니다.
3. 패킹과 언패킹 : 여러 값을 하나의 튜플로 묶거나 튜플의 요소를 개별 변수로 분리 가능합니다.
2. 메모리 및 성능.
튜플과 메모리 최적화.
- 튜플은 리스트에 비해 메모리 사용량이 적고, 처리속도가 빠르다는 장점이 있습니다.
1. 불변성 : 아까 설명했듯이 튜플은 변경할 수 없는 불변(immutable)한 객체이기 떄문에,
파이썬은 튜플을 활용해서, 메모리를 더 효율적으로 관리할 수있습니다.
a. 고정된 크기
: 튜플은 생성 시 크기가 고정되므로, 파이썬은 정확히 필요한 만큼의 메모리만 할당합니다.
튜플은 변경될 수 없기에 내부 구조가 더 단순합니다.
이로 인해 메모리 사용량이 줄어들고 접근 속도가 빨라집니다.
<->
반면, 리스트는 '가변적'이므로 추가 공간을 미리 할당합니다.
2. 튜플 캐싱 : 파이썬은 작은 크기의 튜플을 메모리에 캐시(저장)하여 재사용합니다.
이는 성능 향상과 메모리 효율성을 위한 최적화 기법입니다.
a. 작은 튜플 생성
: 프로그램에서 작은 크기의 튜플(일반적으로 20개 이하 요소 가진 튜플) 을 생성할 때
파이썬은 이를 특별한 메모리 영역에 저장합니다.
b. 재사용
: 동일한 내용의 튜플이 다시 필요할 때,
파이썬은 새로운 메모리를 할당하지 않고 이미 저장된 튜플을 재사용합니다.
c. 메모리 효율성
: 동일한 튜플에 대해 반복적으로 메모리를 할당하고 해제하는 과정 간소화.
a = (1, 2)
b = (1, 2)
print(id(a), id(b)) #2070272464768 2070272464768 동일하게 출력
-> a,b는 동일한 메모리 주소를 가리킵니다. 파이썬이 두 번째 튜플을 생성할 때 이미 캐싱 된 튜플을 재사용했기 때문. !
3. 사용 케이스.
∇ 리스트 (List) 사용 적합한 케이스.
√ 데이터가 빈번한 수정이 필요한 경우.
√ 동적인 데이터 처리.
√ 삽입*삭제 작업 많은 경우.
√ ex) 장바구니 항목, 실시간 데이터 관리.
∇ 튜플(Tuple) 사용 적합한 케이스.
√ 변경되지 않아야 하는 데이터들을 사용하는 경우.
√ 성능 최적화가 필요한 경우
√ 삽입*삭제 작업 많은 경우.
√ ex) 장바구니 항목, 실시간 데이터 관리.
튜플을 사용해야 하는 경우.
1. 불변 데이터 표현
: 변경되지 않아야 하는 데이터를 저장할 때 튜플을 사용합니다.
ex) 좌표, 개인정보, 설정 값 등
2. 딕셔너리 키
: 튜플은 해시 가능하므로, 딕셔너리의 키로 사용할 수 있습니다.
3. 함수의 반환값
: 여러 값을 반환할 때 튜플을 사용하면 편리합니다.
4. 네임드 튜플
: collections 모듈의 namedtuple을 사용하여, 필드에 이름을 부여 가능합니다.
4. 주요 메서드 차이.
∇ 리스트 (List) 메서드.
√ append()
√ remove()
√ insert()
√ sort()
∇ 튜플(Tuple) 메서드.
√ count()
√ index()
5. 코드 예시.
# List 예시
fruits = ['apple', 'banana', 'cherry']
fruits.append('date') # 추가 가능
# Tuple 예시
coordinates = (10, 20)
# coordinates[0] = 15 # 불가능, TypeError 발생
Ⅱ. 파이썬의 주요 특징,
◆ 인터프리터 언어 [ Interpreter Language ]
: 파이썬은 인터프리터 언어이므로, 실행하기 전에 '컴파일'을 할 필요가 없습니다.
+ ∇ 인터프리터 (interpreter) vs 컴파일러(compiler)
:: "인터프리터"는 인간의 언어를 한줄*한줄 씩 통역해서 기계에게 알려주는 동시통역 방식.
-> 실행시간(runtime) 전에 기계 레벨 코드를 만드는 컴파일 언어와 다르게 소스코드를 바로 실행합니
:: "컴파일러"는 입력문 전체를 인지한 이후에 통역하는 방식.
+ ∇ 인터프리터 (interpreter) vs 컴파일러(compiler) 예시
"인터프리터" 예시
:: PHP, Ruby, Python, JavaScript
"컴파일러" 예시
:: C, C++, Rust, Go,
+ Java는 하이브리드 언어라는 괴상한 이름으로 불립니다. 컴파일 언어와 인터프리터 언어플 혼합한 형태입니다.
◆ 객체 지향 프로그래밍 [ OOP, Object Oriented Programming ]
- 파이썬은 클래스와 구성 및 상속을 함께 정의할 수 있다는 점에서 '객체지향프로그래밍'에 매우 적합합니다.
◆ 동적 타이핑 [ Dynamic Typing ]
: 파이썬은 변수 유형을 명시할 필요가 없습니다. 이것을 동적 타이핑(Dynamic Typing)이라고 합니다.
<-> 정적 타이핑(Static Typing)
: 데이터 타입을 정해주는 방식을 정적 타이핑(static Typing)이라고 합니다.
Ⅲ. PEP 8 이란 무엇인가?
★ PEP 8 은 파이썬 스타일 가이드입니다.
PEP 8은 문서로써, 파이썬 코드를 잘 작성하기 위한 가이드라인과 모범 사례들을 제공합니다.
-> 즉 읽기 쉽고 눈에 보기 좋은 코딩 스타일을 장려합니다.
Ⅳ. 파이썬에서 메모리 관리는 어떻게 이루어지는가??
◆ 파이썬의 메모리 관리.
▽ 메모리 구조.
○ 파이썬은 "힙(Heap) 메모리 구조"를 사용하여 객체와 자료구조를 저장합니다.
-> 모든 파이썬 객체는 이 힙 영역에 위치하며, 이는 파이썬 인터프리터에 의해 관리됩니다.
++ 스택(Stack) 메모리는 함수 호출 시 지역 변수를 저장하는 데 사용되며,
함수가 종료되면 자동으로 메모리가 해제됩니다.
▽ 가비지 컬렉션.
○ 파이썬은 가비지 컬렉터(Garbage Collector)를 통해 메모리를 관리합니다.
-> 사용되지 않는 객체를 자동으로 감지하고 메모리를 해제하여 메모리 누수를 방지합니다.
○ 가비지 컬렉터는 주기적으로 실행되며,
주로 "참조 카운팅(Reference Counting)" & " 주기적 수집(Generational Collection) " 방식을 사용합니다.
-> 참조 카운팅 : 각 객체는 자신을 참조하는 변수의 수를 기록합니다.
참조 카운트가 0이 되면 해당 객체는 메모리에서 해제됩니다.
-> 주기적 수집 : 서로 참조하는 객체들이 있을 경우 참조 카운트가 0이 되지 않더라도
주기적으로 이러한 객체들을 검사하여 메모리를 해제합니다.
▽메모리 할당.
○ 파이썬은 메모리를 동적으로 할당합니다.
== 프로그램 실행 중에 필요에 따라 메모리를 요청하고 해제합니다.
○ C언어의 메모리 관리 함수와는 달리, 파이썬은 이러한 과정을 자동으로 처리하여
코더의 부담을 줄여줍니다.
▽메모리 최적화.
○ 프로그래머는 메모리 사용을 최적화하기 위해 불필요한 객체를 삭제하거나
'del' 키워드를 사용하여 참조를 제거할 수 있습니다.
○ '메모리 프로파일링 도구'를 사용하여 메모리 사용량을 분석하고,
성능을 개선 할 수 있습니다.
◎ 메모리 관리의 중요성
:: 효율적인 메모리 관리는 프로그램의 성능과 안전성에 큰 영향을 미칩니다.
메모리 누수나 과도한 메모리 사용은 프로그램의 실행 속도를 저하시킬 수 있습니다.
Ⅴ. GIL은 무엇이고, 파이썬의 쓰레드의 안정성은?
▣ GIL은 무엇인가
: GIL은 전역 인터프리터 락(Global Interpreter Lock) 으로
파이썬의 멀티쓰레드 환경에서의 안정성을 보장하기 위해서 사용되는 '동기화 메커니즘' 입니다.
GIL은 한 번에 하나의 스레드만 파이선 바이트코드로 실행할 수 있도록 제한하는 락으로서,
데이터의 일관성을 유지하고 경쟁 상태를 방지합니다.
▣ GIL의 존재 이유.
1.메모리 관리의 안전성.
● 파이썬의 레퍼런스 카운팅{reference counting} 방식 보호.
* 레퍼런스 카운팅
- 객체에 대한 참조의 수를 세어서, 참조 수가 0이 될 때 해당 객체의 메모리를 해제하는 방식.
+ 메모리 누수를 방지하는데 도움을 주지만, '순환 참조' 같은 문제를 야기할 수 있습니다.
* 파이썬- 가비지 컬렉션.
-> 파이썬은 이러한 순환참조를 문제를 해결하기 위해, "가비지 컬렉션" 기법도 함께 사용합니다 !
->> 가비지 컬렉터는 주기적으로 객체의 참조 관계를 검사하여,
'순환참조'를 처리하고 더 이상 사용되지 않는 객체를 메모리에서 제거합니다.
● 메모리 누수 및 경쟁 상태(Race Condition) 방지.
2. 스레드 안전성 보장.
● 여러 스레드가 동시에 객체에 접근할 때 발생할 수 있는 문제 해결.
● 복잡한 락 메커니즘 대신 단일 인터프리터 락 사용.
▣ GIL의 작동 원리.
● 한 스레드가 GIL을 획득하면, 다른 스레드는 대기.
● I/O 작업이나 일정 시간 후 GIL을 다른 스레드에 양도.
● 멀티코어 환경에서도 실제로는 한 번에 하나의 스레드만 실행.
▣ 파이썬 쓰레드 안전성
:: "쓰레드 안전성"은 멀티스레드 환경에서
공유 자원에 대한 일관되고 예측 가능한 접근을 보장하는 프로그래밍 특성 입니다.
▶ 위에서 설명한 GIL 덕분에 파이썬에서는 쓰레드가 동시에 실행될 때 발생할 수 있는
데이터 경합(race condition)문제를 어느 정도 완화할 수 있습니다.
▶ 그러나, GIL이 있는 상태에서도, 쓰레드가 GIL을 잃게 되면 다른 쓰레드가 실행될 수 있으므로
코드의 안전성을 확보하기 위해서는 적절한 동기화 기법이 필요합니다.
◎ 동기화 기법.
● Lock : 쓰레드가 특정 자원에 접근할 때 Lock을 사용하여 다른 쓰레드가 동시에 접근하지 못하도록 합니다.
● RLock : 재진입 가능한 Lock으로, 같은 쓰레드가 여러 번 Lock을 획득할 수 있습니다.
● Semaphore : 특정 수의 쓰레드만 자원에 접근할 수 있도록 제한합니다.
● Event: 쓰레드간의 통신을 위해 사용되며, 특정 이벤트가 발생할 때까지 대기할 수 있습니다.
☆ 파이썬은 GIL을 통해 멀티쓰레딩 환경에서 안전성을 제공하지만,
개발자는 동기화 기법을 통해 코드의 안전성을 확보해야 합니다.
'면접준비[프론트,백,데이터,CS] > InterView 준비 [ 백엔드 ]' 카테고리의 다른 글
[ 백엔드 면접준비 : Java&Kotlin + SpringBoot ] Java 면접 질문 정리_03 (0) | 2024.12.22 |
---|---|
[ 백엔드 면접준비 : Java&Kotlin + SpringBoot ] Java 면접 질문 정리_02 (2) | 2024.12.20 |
[ 백엔드 면접준비 : Java&Kotlin + SpringBoot ] Java 면접 질문 정리_01 (0) | 2024.12.20 |
[ 백엔드 면접 준비 ] 백엔드 면접 준비 _ 02. (0) | 2024.12.16 |
[ 백엔드 면접 준비 ] 백엔드 면접 준비 _ 01. (2) | 2024.12.13 |