Rookies 4일차: Python 개념 학습 2
☀️공지 사항☀️ 해당 게시글은 SK 쉴더스 루키즈, 생성형AI 활용 사이버보안 전문인력 양성과정 을 수업을 듣고 정리한 글입니다. 자세한 교육 정보는 SK 쉴더스 홈페이지 를 확인해주세요.
학습 내용 요약 (25/10/28)
1. 변수 타입 응용 (문자열, 리스트, 딕셔너리)
1.1 문자열(String) 응용
파이썬의 문자열 메서드를 활용해 데이터를 처리하는 방법
- 슬라이싱을 통한 추출: URL에서 도메인 (
.com)과 같은 특정 부분을 추출할 때 슬라이싱을 사용. 예:url[-3:] - 공백 제거:
strip(),rstrip(),lstrip()메서드를 사용하여 문자열 양쪽 또는 특정 방향의 공백을 제거할 수 있다. 이는 사용자 입력 처리 시 데이터 무결성 확보에 중요하다. - 대소문자 변경:
capitalize()메서드로 첫 글자를 대문자로 변경. - 접미사 확인:
endswith()메서드를 사용하여 파일 확장자('report.xls')처럼 특정 문자열로 끝나는지 여부 확인. 이는 파일 처리 시 파일 타입 검증에 유용하다. - 위치 찾기:
find()메서드는 특정 문자열의 시작 인덱스를 찾아내는 데 사용.
실습 코드 예시
url = 'http://www.naver.com'
print('주어진 문자열에서 도메인만 추출하고 싶다면? ')
print('com - ', url[-3:])
print('find - ', url.find('com'))
print('find - ', url[url.find('com'):])
출력 결과
주어진 문자열에서 도메인만 추출하고 싶다면?
com - com
find - 17
find - com
1.2 리스트(List) 응용
리스트의 기본 연산 및 유용한 내장 함수를 확인했다.
- 리스트 통계:
max(),min(),sum(),len()함수를 사용하여 리스트 내 숫자의 최대값, 최소값, 합계, 평균을 구할 수 있다. - 정렬:
sort()메서드를 사용하여 리스트 요소를 정렬할 수 있으며,reverse=True옵션으로 내림차순 정렬을 수행했다. 예시)lst.sort(reverse = True) - 참조 타입과 주소: 파이썬의 모든 데이터 타입은 참조 타입으로, 변수에 값이 아닌 주소값을 담는다는 개념을 강조했다.
id()함수로 객체의 주소값을 확인하고,is연산자를 사용하여 두 변수가 같은 주소를 참조하는지 비교했다. 예시)print('is - 주소번지를 비교하는 연산자 ', lstTmp01 is lstTmp03)
1.3 딕셔너리 (Dict)
key: value 쌍으로 데이터를 저장하는 구조이다.
- 특징: 키 중복 불가능, 순서 없음. 키 값으로 불변(immutable) 타입만 정의할 수 있다는 주의사항이 있다.
- 키 접근/추가:
user['id']또는user.get('id')로 데이터에 접근하고,user['address'] = 'seoul'와 같이 새로운 키-값을 추가한다. - 순회:
dictZip.keys(),dictZip.values(),dictZip.items()메서드를 사용하여 키, 값, 또는 키-값 쌍을 순회할 수 있다. - 생성 방법: 중괄호
{}를 사용하거나,dict()생성자에 키워드 인자 또는(key, value)쌍의 리스트/튜플을 전달하여 생성한다. zip()함수 활용:zip(keys, datas)와dict()를 결합하여 두 리스트(튜플)를 병합해 딕셔너리를 쉽게 생성할 수 있다. 이는 단어 빈도수 계산 퀴즈에서도 활용되었다 (고유한 단어(set)와 해당 단어의 개수(count)를zip으로 묶어 딕셔너리 생성).
zip( ) 활용
# 현업에서 주로 사용하는 dict 만들기(`zip()`)
keys = ('key01', 'key02', 'key03', 'key04',)
datas = ('sk', 'samsung', 'lg', 'lgcns')
# zip(keys, datas) # 바로 dict 가 되는 것은 아니다.
# dictZip 에 넣어주기
dictZip = dict(zip(keys, datas))
print(dictZip)
# 순환 반복 가능
# .items -> 튜블 형태로 반환됨 -> 패킹 언패킹 가능
for key, data in dictZip.items() :
print(key, ' - ', data)
------------------------------------------------------------------
# 출력 예시
{'key01': 'sk', 'key02': 'samsung', 'key03': 'lg', 'key04': 'lgcns'}
key01 - sk
key02 - samsung
key03 - lg
key04 - lgcns
2. 얕은 복사 vs 깊은 복사
2.1 얕은 복사(Shallow Copy) vs 깊은 복사(Deep Copy) 차이점
데이터 복사 시 보안 취약점을 예방하기 위해 copy 모듈의 복사 방식 이해가 필수적이다.
| 구분 | 얕은 복사 (Shallow Copy) | 깊은 복사 (Deep Copy) |
|---|---|---|
| 특징 | 최상위 객체의 값만 복사. 하위 객체는 원본과 공유 (참조 주소 복사). | 원본 객체와 완전히 독립적인 새로운 객체 생성. 모든 하위 객체까지 복사. |
| 결과 | 원본의 하위 객체 변경 시, 복사본의 하위 객체도 함께 변경됨. | 원본과 복사본이 완전히 독립적이므로, 원본 변경이 복사본에 영향 없음. |
| 보안 관점 | 위험. 민감한 정보(예: token, 사용자 roles 리스트)를 얕은 복사한 후 원본이 변경되면, 캐시된 복사본의 하위 객체도 영향을 받거나, 복사본을 변경하면 원본에도 영향을 주어 데이터 무결성을 해칠 수 있다. |
안전. 원본 데이터에 대한 의도치 않은 변경을 방지하여 보안성이 높다. |
보안 조언: 사용자 정보 등 민감한 데이터를 다루거나, 원본 데이터의 불변성을 유지해야 할 때는 반드시
deepcopy를 사용해야 한다.
2.2 함수와 데이터 무결성: Side Effect 방지 원칙
함수 updateRole(data, newRole)의 코드를 개선한 것은 단순한 복사 문법 학습을 넘어선 함수형 프로그래밍 및 데이터 무결성 원칙을 적용한 것이다.
개선 전 (Side Effect 위험)
Python
# 기존 코드: data는 'user' 딕셔너리의 주소값을 참조
def updateRole(data, newRole):
data["role"] = newRole # 원본 딕셔너리(user)의 값이 직접 변경됨 (Side Effect)
이 방식은 함수 외부의 원본 데이터(user)를 직접 수정하는 Side Effect를 유발한다. 이로 인해 원본 데이터가 의도치 않게 변경되거나, 디버깅을 어렵게 만들 수 있다.
개선 후 (불변성 및 입력 검증)
Python
from copy import deepcopy
# ... allowedRoles 정의 ...
def updateRole(data, newRole):
copyUser = deepcopy(data) # 1. 깊은 복사: 원본 불변성 확보
if newRole not in allowedRoles: # 2. 입력값 검증 (인가되지 않은 값 차단)
print(f"허용되지 않는 변경: {newRole}")
else:
copyUser['role'] = newRole # 3. 복사본만 수정
return copyUser # 4. 변경된 복사본 반환
-
데이터 불변성(Immutability):
deepcopy를 사용하여 함수가 원본 데이터를 변경하지 않는 안전한 구조를 만들었다. -
입력값 검증 (Validation):
allowedRoles와if ~ in구문을 활용해 화이트 리스트 기반으로 인가(Authorization) 되지 않은 권한 변경 요청을 사전에 차단했다. 이는 최소 권한 원칙(Principle of Least Privilege)을 적용하는 기본 단계이다.
보안 관점: 모든 함수는 가능한 한 Side Effect가 없어야 하며, 외부 입력(
newRole)은 신뢰할 수 없는 데이터로 간주하고 반드시 검증해야 한다.
3. 열거형(Range) 및 반복 구문/분기문
3.1 열거형 (Range)
range()는 숫자형 값을 생성하는 객체 타입이며, 주로 반복문(for)에서 사용된다.
- 문법:
range(start, end-1, step). for반복문은range객체뿐만 아니라 리스트(lst)와 같은 순회 가능한 객체(Iterable)의 요소를 순서대로 반복할 수 있다.
3.2 List Comprehension
List Comprehension의 효율성
리스트 컴프리헨션은 단순한 문법적 간결함을 넘어 파이썬 인터프리터 수준에서 최적화되어, 일반 for 루프보다 더 빠르다는 장점이 있다. 많은 데이터를 처리할 때 성능 향상에 기여한다.
- 기본 구조:
[실행문 for 변수 in 열거형객체].- 예시: 리스트의 각 값을 제곱한 결과를 새 리스트에 담는 경우.
result = [] result = [lst[idx]**2 for idx in range(len(lst))] print(result)
- 예시: 리스트의 각 값을 제곱한 결과를 새 리스트에 담는 경우.
- 조건 추가:
[실행문 for 변수 in 열거형객체 if 조건식].- 예시: 제곱한 결과 중 2의 배수인 값만 추출하거나, 1~100 사이의 3의 배수만 추출하는 경우.
result = [] result = [lst[idx]**2 for idx in range(len(lst)) if (lst[idx]**2 % 2) == 0] print(result)
- 예시: 제곱한 결과 중 2의 배수인 값만 추출하거나, 1~100 사이의 3의 배수만 추출하는 경우.
3.3 분기문 (If Statement)
if ~ else 구문으로 프로그램의 흐름을 제어하고 True/False 조건을 처리한다.
- 멤버십 연산자 (
in): 리스트 내 특정 값의 존재 여부를 쉽게 확인할 수 있다. 예:if 4 in lst:. - 입력값 검증: 딕셔너리에서 키의 존재 여부 확인 (
"birth" in user) 및 함수 내에서 화이트 리스트(allowedRoles)를 활용한 권한 검증 (if newRole not in allowedRoles)에 사용되었다. 이는 인가되지 않은 접근을 막는 중요한 보안 기법이다.
4. 응용 문제
리스트에 들어있는 단어(요소)의 빈도수를 구하는 문제
wordLst = ['dog', 'dog', 'cat', 'cat', 'word', 'dog', 'cat', 'cs', 'cat', 'cs', 'sk', 'sk']
# 1번째 방법
result = {}
for i in wordLst :
if i in result :
result[i] +=1
else :
result[i]=1
print(result)
# 2번째 방법(순서 보장 X)
set(wordLst) # 1. 중복 제거(유니크화)
[ wordLst.count(data) for data in set(wordLst) ] # 2. 각 요소마다 카운드 세기
result = dict( zip(set(wordLst), [ wordLst.count(data) for data in set(wordLst) ] ) )
print(result)
댓글 남기기