5 분 소요

☀️공지 사항☀️ 해당 게시글은 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)
      

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)

태그: ,

카테고리:

업데이트:

댓글 남기기