logo

파이썬 요약집(기초)

python version: 3.10

기본(Basic)

파이썬(Python)의 개요

  • 파이썬은 1991년 네덜란드의 귀도 반 로섬(Guido van Rossum)이 개발한 인터프리터 언어이다.
  • 인터프리터 언어란, 코드를 한 줄씩 읽고 컴파일해서 즉시 실행하는 프로그래밍 언어를 말한다.
  • 인터프리터가 한줄한줄 실행결과를 반환하기 때문에 빠른 개발이 가능하다.
  • 파이썬은 객체지향 프로그램밍(OOP) 언어이다.
  • 파이썬은 오픈소스이다.
  • 파이썬은 크게 버전2와 버전3로 나눌 수 있으며, 버전2와 버전3는 호환이 되지 않는 부분이 많다.
  • 들여쓰기(Indentation)

  • 코드블럭을 구분하기위해 사용한다.
  • 제어문, 함수, 클래스를 정의할 때 :의 다음 줄에 들여쓰기를 추가해야한다.
  • 특별한 규칙은 없으나, 일관성을 유지하지 않으면 에러가 발생한다.
  • 보통 들여쓰기로 띄어쓰기(space) 4칸을 한다.
  • 주석(Comments)

    #주석의 예
    a = 1    #변수 a에 대한 설명을 주석으로 달아주면 좋음
    
  • 기호 # 부터 그 줄의 끝까지를 주석으로 인식한다.
  • 문자열 내부의 #은 주석의 시작을 의미하지 않는다.
  • 주석은 사람의 이해를 돕기 위한 코드의 설명이지, 코드의 일부가 아니다.
  • 적절한 주석은 코드의 유지보수에 필수적이다.
  • 연산자(Operators)

    클래스에 연산자 오버라이딩(overriding) 메서드를 정의하였다면, 그 클래스의 객체에 한하여 전혀 다른 의미로 사용될 수도 있다.

    수리(Arithmetic) 연산

    연산자 설명 code 예제
    + 더하기 a + b
    - 빼기 a - b
    * 곱하기 a * b
    / 나누기 a / b
    % 나머지 a % b
    // a // b
    ** 제곱 a ** b

    *, ** 연산자는 문맥에 따라서 unpacking 연산자로 사용되는 경우도 있다.

    자료형에 따라 수리연산자는 다른 의미로 사용될 수도 있다.

    할당(Assignment) 연산

    연산자 설명 code 예제 동일표현
    = 변수에 저장 a = 3
    += 더해서 저장 a += 3 a = a + 3
    -= 빼서 저장 a -= 3 a = a - 3
    *= 곱해서 저장 a *= 3 a = a * 3
    /= 나눠서 저장 a /= 3 a = a / 3
    %= 나눠서 나머지 저장 a %= 3 a = a % 3
    //= 나눠서 몫 저장 a //= 3 a = a // 3
    **= 제곱해서 저장 a **= 3 a = a ** 3
    &= AND해서 저장 a &= 0b1010 a = a & 0b1010
    |= OR해서 저장 a |= 0b1010 a = a | 0b1010
    ^= XOR해서 저장 a ^= 0b1010 a = a ^ 0b1010
    >>= Bit 오른쪽 이동해서 저장 a >>= 3 a = a >> 3
    <<= Bit 왼쪽 이동해서 저장 a <<= 3 a = a << 3

    비교(Comparison) 연산

    연산자 설명 code 예제 해석
    == 같다 a == b a 와 b 가 같으면 참
    != 같지 않다 a != b a 와 b 가 같지 않으면 참
    > 크다 a > b a 가 b 보다 크면 참
    < 작다 a < b a 가 b 보다 작으면 참
    >= 크거나 같다 a >= b a 가 b 보다 크거나 같으면 참
    <= 작거나 같다 a <= b a 가 b 보다 작거나 같으면 참

    비교 연산의 결과는 불리언(Boolean)이다.

    논리(Logical) 연산

    논리연산자는 연산의 결과로 참이면 True, 거짓이면 Falsereturn하는 연산자이다.

    논리 연산자는 다른 말로 불리언(Boolean) 연산자라고도 한다.

    연산자 설명 code 예제 해석
    and 양쪽이 모두 참일 때 참 a and b a 가 참이고, b 가 참이면, 참
    or 한쪽만 참이어도 참 a or b a 가 참이거나, b 가 참이면, 참
    not 참과 거짓을 바꾸기 not a a 가 거짓이면 참, 참이면 거짓
    not(a > 1) a 가 1 보다 크지 않으면 참

    반드시 소문자로 사용하여야 한다

    동일성(Identity) 연산

    동일성 연산자는 변수의 id를 확인하여 같으면 True, 다르면 Falsereturn하는 연산자이다.

    연산자 설명 code 예제 동일표현 해석
    is 변수id가 같으면 참 a is b id(a) == id(b) a 와 b 가 동일 변수면 참
    is not 변수id가 다르면 참 a is not b id(a) != id(b) a 와 b 가 동일 변수가 아니면 참

    멤버쉽(Membership) 연산

    멤버쉽 연산자는 어떤 값이 리스트, 튜플, 딕션네리, 세트 타입의 변수에 포함되는지 아닌지를 확인하는 연산자이다.

    주의할 점은, dictionary 타입을 대상으로 하면 key에 포함되는지만을 확인한다.

    연산자 설명 code 예제 해석
    in 포함되면 참 a in [1,2,3] a 가 1,2,3 중에 하나이면 참
    not in 포함되지 않으면 참 a not in [1,2,3] a 가 1,2,3 중에 하나이지 않으면 참

    비트(Bitwise) 연산

    연산자 설명 code 예제 해석
    & AND 0b0101 & 0b1111 같은 자리의 bit이 둘 다 1 일때 1 이되므로, 결과는 0b0101
    | OR 0b0101 | 0b1111 같은 자리의 bit이 둘 중 하나라도 1 일때 1 이되므로, 결과는 0b1111
    ^ XOR 0b0101 ^ 0b1111 같은 자리의 bit이 같으면 1, 다르면 0 이되므로, 결과는 0b0101
    ~ NOT ~ 0b0101 모든 bit을 0 이면 1 로, 1 이면 0으로 변환하므로, 결과는 0b1010
    >> 오른쪽 쉬프트 0b0101 >> 1 모든 bit을 오른쪽으로 1 씩 이동시키고 양수는 0을 채우므로, 결과는 0b0010
    << 왼쪽 쉬프트 0b0101 << 1 모든 bit을 왼쪽으로 1 씩 이동시키고 0을 채우므로, 결과는 0b1010

    변수(Variable)

    변수란, 데이터 저장소를 말하며, 컴퓨터 메모리의 물리적인 공간을 사용한다.

  • 변수 만들기
  • #하나의 변수 생성
    변수명 = 데이터
    
    #복수의 변수를 한 줄에서 생성
    변수명1, 변수명2, 변수명3 = 데이터1, 데이터2, 데이터3  #실제로는 튜플을 만든 후 언팩킹하는 것이다
    

    할당 연산자(=)를 사용하여 변수를 만들고 데이터를 저장한다.


  • 변수의 규칙
    • 변수명에는 일반문자와 숫자, 언더스코어(_)만이 사용 가능하다. (특수문자 불가)
    • 숫자는 변수명의 첫문자가 될 수 없다.
    • 변수명에서 대문자와 소문자는 서로 다른 문자이다.
    • 변수명은 보통 snake_case 스타일로 작명한다.

  • 변수의 범위
    • 함수 내부의 변수들은 로컬 변수이다. 즉, 함수 외부에서 접근할 수 없는 변수이다.
    • 함수 내부와 외부에 동일 이름의 변수가 있다면, 함수 내부의 변수를 사용한다.
    • 단, 변수를 만들때, global 키워드를 사용하면 내부의 변수를 생성하지 않고 외부의 변수를 가져온다.
    • 함수 내부에서 외부 변수 읽기는 가능하다. 그러나 외부 변수를 업데이트할 수 없다.
      업데이트를 하려면 global 키워드를 사용해서 외부의 변수를 가져와야 한다.
    • 함수 내부에서 또 다른 함수를 정의하는 경우, nonlocal 키워드를 사용해 바깥 함수의 로컬 변수를 내부 함수로 가져올 수 있다.
    • a,b,c = 1,2,3         #글로벌 변수 생성
      print(a,b,c)          #'1 2 3'
      
      def func1():          #바깥 함수 정의
          global a          #글로벌 변수 a를 가져오기
          b,c = 4,5         #func1의 로컬 변수 생성
          print(a,b,c)      #'1 4 5'
      
          def func2():      #내부 함수 정의
              global a      #글로벌 변수 a를 가져오기
              nonlocal b    #func1의 로컬 변수 b를 가져오기
              c = 6         #func2의 로컬 변수 생성
              print(a,b,c)  #'1 4 6'
      
  • 자료형(Data Types)

    숫자(Numbers)

  • 타입
  • 이름 설명 예제 변수 만들기
    정수형(int) 영, 양수(자연수), 음수 0, 1, 2, -22 a = 12
    소수점형(float) 소수 부분이 있는 수 1.1, 2.087, 3.123 b = 1.2
    복소수형(complex) 허수 부분이 있는 수 3+2j, 2.1+4.3j c = 1+2j

  • 특별한 표현법
  • 이름 설명 예제 10진수 동일값
    지수형(Exponential)* e 또는 E를 사용하여 10진수의 지수형태로 나타내는 방법 4.21e5 4.21 * 10 ** 5, 421000
    2진수형(Binary) 0b를 수 앞에 붙여서, 2진수 수를 나타내는 방법 0b0111 7
    8진수형(Octal) 0o를 수 앞에 붙여서, 8진수 수를 나타내는 방법 0o177 127
    16진수형(Hexadecimal) 0x를 수 앞에 붙여서, 16진수 수를 나타내는 방법 0x01FF 511

    *지수형은 과학적 표기법과 유사함

    문자열(String)

    문자열이란 문자들의 집합을 말한다.

  • 문자열 변수 만들기
  • 방법 설명 예제 변수 만들기
    큰 따옴표로 감싸기 한줄 문자열 만들기 "ab123" a = "ab123"
    작은 따옴표로 감싸기 한줄 문자열 만들기 'ab123' b = 'ab123'
    큰 따옴표로 3연속 감싸기 여러줄 문자열 만들기
    """
    ab123
    mn567
    """
    c = """
    ab123
    mn567
    """
    작은 따옴표로 3연속 감싸기 여러줄 문자열 만들기
    '''
    ab123
    mn567
    '''
    d = '''
    ab123
    mn567
    '''

    3연속 따옴표로 만들어진 문자열을 "문자열 블락"이라고도 한다.


  • 큰 따옴표로 깜사인 문자열에서 작은 따옴표는 일반 문자로 취급한다.
  • a = "I'm a boy."    #작은 따옴표는 문자열의 일부

  • 작은 따옴표로 깜사인 문자열에서 큰 따옴표는 일반 문자로 취급한다.
  • a = '매우 "중요한" 문자열'    #큰 따옴표는 문자열의 일부

  • 따옴표 없이 문자를 사용하면 문자열을 만드는 것이 아니라, 해당 문자를 이름으로 하는 변수를 참조한다.
  • a = food  #food라는 변수가 없으므로 에러가 발생
    

  • 문자열 내부에서 감싸고 있는 따옴표와 동일한 따옴표를 문자로 사용하려면 \", \'로 써야한다.
  • a = "매우 \"중요한\" 문자열"
    b = 'I\'m a boy'
    

    특수문자 \는 문자열 내부에서는 escape라는 특별한 의미를 가지고 있다.

    포매팅(formatting)

  • 3가지 포매팅 방식
  • 방식 형식 예제 예제의 결과
    % 포맷코드 "(% 포맷코드)를 포함한 문자열" % 데이터
    "I have %d apples." % number
    "I have 3 apples."
    포맷 함수 "{0:포매팅 타입}를 포함한 문자열".format(데이터)
    "I have {0} apples.".format(number)
    "I have 3 apples."
    f-문자열 f"{데이터:포매팅 타입}를 포함한 문자열"
    f"I have {number} apples."
    "I have 3 apples."

    :포매팅 타입은 옵션


  • 문자열 % 포맷코드
  • 코드 설명
    %s 문자열(String)
    %c 문자 1개(character)
    %d 정수(Integer)
    %f 부동소수(floating-point)
    %o 8진수
    %x 16진수
    %% 문자 % 자체 (escape)

  • 포매팅 타입
  • 포맷 함수 또는 f-문자열의 {} 내부에서 데이터와 포매팅 타입을 :로 구분하여 포맷

    타입 설명 예제 예제의 결과
    s 데이터 자료형이 문자열인 경우
    f"나의 이름은 {name:s} 입니다."
    "나의 이름은 홍길동 입니다."
    d 데이터 자료형이 정수인 경우
    f"나의 나이는 {age:d} 입니다."
    "나의 나이는 10 입니다."
    f 데이터 자료형이 소수인 경우
    f"나의 키는 {height:f}cm 입니다."
    "나의 키는 123.1cm 입니다."
    .(숫자) 데이터 자료형이 소수일 때,
    소수점 아래 자리의 수의 길이
    f"10 나누기 3의 결과는 {result:.3f} 입니다."
    "10 나누기 3의 결과는 3.333 입니다."
    , 1000의 자리를 콤마로 구분
    f"나의 월급은 {salary:,d}원 입니다."
    "나의 월급은 10,000,000원 입니다."
    (숫자) 데이터의 최소길이
    f"++{greeting:6}++"
    "++hi    ++"
    < 공백이 있다면, 왼쪽 정렬
    f"++{greeting:<6}++"
    "++hi    ++"
    > 공백이 있다면, 오른쪽 정렬
    f"++{greeting:>6}++"
    "++    hi++"
    ^ 공백이 있다면, 가운데 정렬
    f"++{greeting:^6}++"
    "++  hi  ++"
    = 데이터가 숫자이고 공백이 있다면,
    부호를 가장 왼쪽에 배치하고 공백을 채우기
    f"현재 기온은 {-5:=3}도 입니다"
    "현재 기온은 - 5도 입니다"
    (문자) 주어진 문자로 공백을 채우기
    (반드시 정렬 타입과 함께 사용하여야 함)
    f"{number:=^5}"  #"="로 공백을 채우기
    "==3=="
    + 데이터가 숫자일 때, 반드시 부호를 붙이기
    f"{number:=+5}"
    "+   3"
    - 데이터가 숫자일 때, 음수일 때만 부호를 붙이기
    f"{number:=-5}"
    "    3"
    (공백) 데이터가 숫자일 때,
    양수일 때는 공백으로 음수일 때는 부호를 붙이기
    f"{number:= 5}"
    "    3"

  • 포매팅 타입의 순서
  • (공백문자* - 정렬) - 부호 - 길이 - 1000의 자리 구분 - 소수점 아래자리 - 데이터 자료형

    *공백문자는 정렬 타입이 있는 경우에만 사용 가능

    number=12345.67
    f"{number:@^+20,.3f}" # @^ : 가운데 정렬하고 공백은 @로 채우고 # + : 부호는 반드시 붙이고 # 20 : 총길이는 20으로 하고 # , : 1000의 자리는 콤마로 구분하고 # .3 : 소수점 아래 3자리까지 출력하고 # f : number의 자료형은 소수임 # 결과: "@@@@+12,345.670@@@@@"

    콜렉션(Collections)

    콜렉션 타입으로는 리스트, 튜플, 딕셔네리, 세트가 있다.


  • 변수 만들기
  • 자료형 특징 변수 만들기 형식 변수 만들기 예제
    리스트(list) []를 사용
    # 방법 1
    변수명 = [요소1, 요소2, 요소3, ...]
    
    # 방법 2
    변수명 = list(요소1, 요소2, 요소3, ...)
    
    a = []                 #비어있는 리스트
    b = [1, 2, 3]
    c = [1, 2, [1, 2, 3]]  #2차원 리스트
    d = list(1, 2, 3)
    
    튜플(tuple) ()를 사용
    # 방법 1
    변수명 = (요소1, 요소2, 요소3, ...)
    
    # 방법 2
    변수명 = tuple(요소1, 요소2, 요소3, ...)
    
    a = ()                 #비어있는 튜플
    b = (1,)               #요소가 하나인 경우 콤마로 끝나야 함
    c = (1, 2, 3)
    d = (1, 2, (1, 2, 3))  #2차원 튜플
    e = 1, 2, 3            #괄호를 생략할 수 있음
    f = tuple(1, 2, 3)
    
    딕셔네리(dict) {}키:밸류를 넣어준다.
    # 방법 1
    변수명 = {키1:밸류1, 키2:밸류2, ...}
    
    # 방법 2
    변수명 = dict(키1=밸류1, 키2=밸류2, ...)
    
    a = {}                        #비어있는 딕셔네리
    b = {"a": 1, "b": 2, "c": 3}  #키가 문자인 경우
    c = {1: "a", 2: "b", 3: "c"}  #키가 숫자인 경우
    d = dict(a=1, b=2, c=3)
    
    세트(set) {}를 사용
    # 방법 1
    변수명 = {요소1, 요소2, 요소3, ...}
    
    # 방법 2
    변수명 = set([요소1, 요소2, 요소3, ...])
    a = set()                          #비어있는 세트
    b = {1, 2, 3}
    c = set([1, 2, 3])                 #리스트로 세트를 만들기
    d = set((1, 2, 3))                 #튜플로 세트를 만들기
    e = set({"a": 1, "b": 2, "c": 3})  #딕셔네리로 세트를 만들기
    

    set() 함수는 리스트, 튜플, 딕셔네리 타입을 입력으로 받으나, 딕셔네리 타입은 키값만이 남고 밸류값은 사라진다.

    a = {} 코드는 비어있는 세트가 아니라 비어있는 딕셔네리를 만든다.


  • 특성
  • 자료형 데이터 변경여부 데이터 중복여부 데이터간 순서여부
    리스트 가변 가능 순서가 있음
    튜플 불변 가능 순서가 있음
    딕셔네리 키 - 불변
    밸류 - 가변
    키 - 불가능
    밸류 - 가능
    버전 3.6 이하 - 순서가 없음
    버전 3.7 이상 - 순서가 있음
    세트 불변
    (추가/삭제는 가능)
    불가능 순서가 없음

    세트는 불변타입이지만 요소의 추가, 삭제는 가능하다.

    세트에 중복된 데이터가 입력 또는 추가되면 자동으로 하나만 남는다.

    세트는 순서가 없으므로, 인덱싱을 할 수 없다.


  • 데이터 CRUD(생성-읽기-업데이트-삭제) 작업
  • 자료형 생성(Create) 읽기(Read) 업데이트(Update) 삭제(Delete)
    리스트
    a = ["가", "나", "다"]
    b = [1, 2, 3]
    
    #인덱싱으로 접근
    c = a[0]
    c = a[1]
    c = a[-1]
    
    #추가(Add)
    a.append("라")     #마지막에 추가
    a.insert(1, "라")  #인텍스 1 위치에 추가
    a.extend(b)        #a에 b 요소를 추가
    #추가하여 새 리스트 생성
    d = a + b          #a,b를 합하기
    d = a * 2          #a를 두번 반복
    
    #변경(Change)
    a[0] = "차"            #인덱싱으로 변경
    a[1:2] = ["차", "타"]  #슬라이싱으로 변경
    
    #pop()
    d = a.pop()   #마지막 요소 삭제
    d = a.pop(1)  #인덱스 1 삭제
    
    #remove()
    a.remove("다")  #요소("다") 삭제
    
    #del 키워드
    del a[1]   #인덱스 1 삭제
    del a[-1]  #인덱스 -1 삭제
    
    #슬라이싱으로 여러개 삭제
    del a[1:]
    
    튜플
    a = ("가", "나", "다")
    b = (1, 2, 3)
    
    #인덱싱으로 접근
    c = a[0]
    c = a[1]
    c = a[-1]
    
    불가
    (업데이트를 하려면 새로 생성해야 함)
    불가
    (변수 삭제만 가능)
    딕셔네리
    a = {"가":1, "나":2, "다":3}
    b = {1:"가", 2:"나", 3:"다"}
    
    #키로 접근
    c = a["가"]
    c = a["나"]
    c = b[1]
    c = b[2]
    
    #키가 이미 있으면 변경, 키가 없으면 추가
    
    #키로 접근하여
    a["라"] = 4         #변경
    b[4] = "라"         #추가
    
    #update()로
    b.update({1:"라"})  #변경
    b.update({4:"라"})  #추가
    
    #반복가능한 객체로 (키-밸류)값을 전달
    b.update({5:"마",6:"바"})     #딕셔네리
    b.update([(5,"마"),(6,"바")]) #튜플 리스트
    b.update([[5,"마"],[6,"바"]]) #2차원 리스트
    
    #pop()
    d = a.pop("가")  #a["가"] 삭제
    
    #popitem()
    #마지막에 추가된 키가 삭제됨
    d = a.popitem()
    
    #del 키워드
    del a["가"]  #a["가"] 삭제
    
    #clear()
    a.clear()  #모든 키 삭제
    
    세트
    a = {"가", "나", "다"}
    b = {1, 2, 3}
    
    개별 데이터 읽기 불가
    (세트에 포함 여부만
    확인할 수 있음)
    #추가는 가능하나, 변경은 불가
    
    #add()
    #하나의 요소 추가
    a.add("라")
    a.add(10)
    
    #update()
    a.update(b)          #세트 b를 a에 더하기
    a.update({1, 2, 3})  #세트
    
    
    #세트, 리스트, 튜플의 요소들을 추가
    a.update([1, 2, 3])  #리스트
    a.update((1, 2, 3))  #튜플
    
    #딕셔네리의 키들을 추가
    a.update({1:"가", 2:"나", 3:"다"})
    
    #remove()
    a.remove("나")  #요소 삭제
    a.remove("카")  #에러 발생
    
    #discard()
    a.discard("나")  #요소 삭제
    a.discard("카")  #에러 없음
    
    #pop()
    d = a.pop()  #랜덤 요소 삭제
    
    #clear()
    a.clear()  #모든 요소 삭제
    
    #del 키워드
    del a  #변수 삭제
    

    딕셔네리와 세트의 업데이트 메서드인 update()는 리스트, 튜플, 딕셔네리, 셋트 등의 반복가능(iterable) 객체를 전달인자로 받는다. 특히, 딕셔네리의 경우 키-밸류 값을 담고 있는 객체를 전달해야 한다.

    딕셔네리의 삭제 메서드인 popitem()는 추가된 순서를 기준으로 마지막 키:밸류를 삭제하므로, 버전 3.6 이하에선 랜덤하게 삭제되므로 주의할 것

    세트의 삭제 메서드인 remove()은 해당 요소가 없는 경우에 에러를 발생시킨다.

    세트의 삭제 메서드인 discard()은 해당 요소가 없는 경우에도 에러를 발생시키지 않는다.

    세트의 삭제 메서드인 pop()은 순서가 없는 세트의 특성상 랜덤하게 삭제되므로 주의할 것

    인덱싱(Indexing)

    변수명[인덱스]
  • 인덱스(index)란, 요소들의 순서를 말한다.
  • 인덱스는 0부터 시작하여 1씩 증가한다.

  • 인덱싱(indexing)이란, 인덱스로 요소에 접근하는 것을 말한다.
  • 인덱싱은 []를 사용한다. 리스트와 헷갈리지 않도록 주의할 것

  • 마이너스 인덱싱
      마지막_요소 = 변수명[-1]
    • 인덱스는 마지막 요소를 -1로 하여 마지막에서 첫 요소 방향으로 1씩 감소하게 매길 수도 있다.
    • 마이너스 인덱스와 일반 인덱스를 함께 사용할 수 있다.
  • 2차원 인덱싱
      변수명[1차원 인덱스][2차원 인덱스]
      #예제
      a = [1, 2, 3, ["a", "b", "c"]]
      
      #a[3] => ["a", "b", "c"]
      b = a[3][0]    #b = "a"
      c = a[3][1]    #c = "b"
      d = a[3][2]    #d = "c"
      

      2차원 이상의 고차원 인덱싱도 동일한 원리

  • 슬라이싱(Slicing)

    새로운_변수명 = 변수명[시작_인덱스(포함):끝_인덱스(불포함):스텝]

  • 특성
  • 시작_인덱스 끝_인덱스 스텝
    포함 여부 -
    생략 가능
    마이너스 값 가능
    디폴트 값 0 len(변수명) 1

    슬라이싱의 결과로 새로운 객채가 생성되며, 변수에 저장하지 않으면 버려진다.

    시작_인덱스끝_인덱스보다 크면 빈 객체가 생성된다.

    스텝을 생략할 때, 변수명[시작_인덱스:끝_인덱스]의 형태로 사용할 수 있다.

    스텝에 마이너스 값을 사용하면, 거꾸로 슬라이싱을 할 수 있다.


    #예제
    a = [0, 1, 2, 3, 4]
    
    b1 = a[:]      #b1 = [0, 1, 2, 3, 4] => 전체 복사
    b2 = a[2:]     #b2 = [2, 3, 4]       => a[2] 포함
    b3 = a[:2]     #b3 = [0, 1]          => a[2] 불포함
    
    #마이너스
    c1 = a[-4:]    #c1 = [0, 1, 2, 3, 4] => 전체 복사
    c2 = a[:-1]    #c2 = [0, 1, 2, 3]    => a[-1] 불포함
    c3 = a[-3:-1]  #c3 = [2, 3]
    c4 = a[-2:-3]  #c4 = []              => 빈 리스트
    
    #스텝
    d1 = a[::-1]   #d1 = [4, 3, 2, 1, 0] => 뒤집기
    d2 = a[::2]    #d2 = [0, 2, 4]       => 짝수만
    d3 = a[1::2]   #d3 = [1, 3]          => 홀수만
    

    불리언(Boolean)

    참(True)과 거짓(False)을 나타내는 자료형이다


  • 변수 만들기
  • #직접 입력
    a = True
    b = False
    
    #연산의 결과
    c = 1 > 2                #비교 연산
    d = a or b               #논리 연산
    d = name1 is name2       #동일성 연산
    e = number in [1,2,3,4]  #멤버쉽 연산
    
    #bool()
    f = bool(10)  #True
    g = bool("")  #False
    

  • 자료형의 참과 거짓
  • 자료형의 대부분의 값은 참(True)으로 간주되지만, 아래의 값은 거짓(False)으로 간주된다.

    자료형 거짓(False)인 값
    문자열 ""
    숫자 0
    리스트 []
    튜플 ()
    딕셔네리 {}
    세트 set()
    객체 None

    각 콜렉션 자료형의 비어있는 값은 거짓(False)이다.

    객체의 경우,

      1. 클래스에 __bool__() 메서드를 정의하였다면, 우선적으로 __bool__()의 실행결과에 따른다

      2. 클래스에 __len__() 메서드를 정의하였다면, __len__() 실행결과가 0이면 False, 그 외에는 True이다

      3. 둘다 정의하지 않았다면, 항상 True로 간주된다

    제어문(Controls)

    조건문(Conditionals)

    조건문이란, 참과 거짓을 판단하는 문장을 말한다.

    불리언(Boolean)을 결과로 내는 연산 또는 함수가 조건문의 조건이 될 수 있다.

    불리언(Boolean)이 아닌 자료형을 조건으로 사용하는 경우, 각 자료형에 정의된 참과 거짓을 판단하는 방법을 따른다.

    조건문의 조건으로 할당표현이 올 수도 있다.

    조건문은 if문 하나이었으나, 버전 3.10부터 match문이 추가되었다.


  • if문(if Statement)
  • if 조건1:      #if문의 필수문장
        실행문1-1  #들어쓰기!!!
        실행문1-2
        ...
    elif 조건2:    #다른 조건을 테스트
        실행문2-1
        실행문2-2
        ...
    elif 조건3:    #또다른 조건을 테스트
        실행문3-1
        실행문3-2
        ...
    else:          #위의 모든 조건이 False인 경우
        실행문4-1
        실행문4-2
        ...
    

    if문의 조건은 실행조건을 의미한다.

    위에서부터 순서대로 조건을 테스트하고, 먼저 True가 되는 조건의 코드블락을 실행하며 뒤의 다른 조건들은 테스트 없이 무시된다.

    elifelse는 필요없는 경우 생략할 수 있다.

    else가 생략된 경우, 모든 조건이 False이면 아무것도 실행되지 않는다.

    ifelse는 한번만 사용할 수 있지만, elif의 수에는 제한이 없다.


  • 축약형 if
  • if 조건1: 실행문1
    elif 조건2: 실행문2
    elif 조건3: 실행문3
    else: 실행문4
    

    실행문이 한 줄인 경우, 조건과 :에 이어서 줄바꿈 없이 바로 실행문을 쓸 수 있다.


  • 조건표현(Conditional Expression)
    실행문(참) if 조건 else 실행문(거짓)

    조건이 참이면 실행문(참)을, 거짓이면 실행문(거짓)을 실행한다.

    조건표현의 조건은 선택조건을 의미한다.

    • if문과 조건표현의 차이
    • 1. 조건표현에는 :이 없다.

      2. 조건표현은 반드시 한줄이어야 한다.

      3. 조건표현은 연산자로 사용할 수 있다.

    #예제
    print(a) if a > b else print(b)
    #a가 b보다 크면 a를 출력하고 아니면 b를 출력
    
    #연산자로 사용
    ok = "같다" if a == b else "다르다"
    #a와 b가 같으면 "같다"를 아니면 "다르다"를 변수 ok에 저장
    

  • match문(match Statement) [버전 3.10 부터 사용가능]
  • match 매칭대상:
        case 패턴1 if 조건1:  #들어쓰기!!!
            실행문1-1         #들어쓰기 추가
            실행문1-2
        ...
        case 패턴2 if 조건2:  #다른 패턴과 매칭 테스트
            실행문2-1
            실행문2-2
        ...
        case 패턴3 if 조건3:  #또다른 패턴과 매칭 테스트
            실행문3-1
            실행문3-2
        ...
        case _:              #위의 모든 패턴과 매칭에 실패한 경우, 무조건 매칭
            실행문4-1
            실행문4-2
        ...
    

    match문은 매칭대상패턴을 비교하여 매칭이 일어나는 case의 코드블락을 실행시키는 조건문이다.

    case의 수에는 제한이 없다.


  • match문의 가드
    • match문의 if 조건을 "가드"라고 말한다.
    • 가드는 패턴이 매칭에 성공하라도 코드블락의 실행을 막아야 하는 경우에 사용한다.
    • 필요 없으면 생략할 수 있다.
    • match문의 조건은 실행조건을 의미한다.
    • 어느 패턴매칭대상과 매칭에 성공하면, 조건을 테스트하여 True인 경우에만 case의 코드블락을 실행한다.

  • 패턴 내의 변수명
    • 패턴 안에는 변수가 포함될 수 있다. 이때, 변수가 있는 부분은 매칭이 되는 것으로 본다.
    • 최종적으로 매칭에 성공하면, 실행문이 실행되기 전에 패턴의 내의 변수에 매칭대상의 해당 부분 값이 변수에 저장된다.
  • #예제
    flag = False                                #flag는 가드
    target = (100, 200)                         #target은 매칭대상
    match target:                               #(100,200)과 매칭돠는 패턴을 찾기
        case (100, 300):                        #매칭 실패: 200 != 300 
            print("Case 1")
        case (100, 200) if flag:                #매칭 성공, 하지만 가드가 실행을 막음
            print("Case 2")
        case (100, y):                          #매칭 성공, y에 200이 저장됨
            print(f"Case 3, y: {y}")            #이 라인이 실행됨
        case _:                                 #매칭 성공 이후의 모든 case는 무시됨
            print("Case 4, 디폴트 케이스!")
    #결과: 'Case 3, y: 200'
    

    할당표현(Assignment Expression)

    변수명 := 연산(또는 함수 등)

  • 할당표현은 :=을 사용하여 할당연산을 다른 문장 내에서 사용할 수 있게 한다.
    • if문의 조건으로 할당표현을 사용할 수 있다.
    • match문의 매칭대상, 조건으로 할당표현을 사용할 수 있다.
    • while문의 조건으로 할당표현을 사용할 수 있다.
  • #예제(if문)
    a=[1,2,3]
    if b := len(a):           #변수 a의 길이를 변수 b에 저장
        print(f"길이: {b}")   #변수 b가 0이 아닌 경우 실행
    else:
        print("비어있음")     #변수 b가 0인 경우 실행
    print(f"변수 b 값: {b}")  #if문 이후에도 변수 b를 계속 사용할 수 있다
    

    반복문(Loops)

  • while
  • while 조건:    #조건이 True인 동안 반복
        실행문1-1  #들여쓰기!!!
        실행문1-2
        ...
    else:          #조건이 False이면 실행
        실행문2-1
        실행문2-2
        ...
    

    while문의 조건은 반복조건을 의미한다.

    조건True인 동안 while의 코드블락이 반복 실행된다.

    반복 종료 논리에 오류가 있다면, 무한반복 될 수 있다.

    else의 코드블락은 조건False인 경우, 딱 한번 실행된다.

    else의 코드블락은 반복이 break키워드로 종료된 경우, 실행되지 않는다.


  • for
  • for 변수명 in 반복대상:  #반복대상에서 하나씩 꺼내와 변수에 저장
        실행문1-1           #들여쓰기!!!
        실행문1-2
        ...
    else:                   #반복이 완료되면 실행
        실행문2-1
        실행문2-2
        ...
    

    for문은 반복가능(iterable) 자료형의 모든 요소를 하나씩 꺼내어 변수에 저장한 후, 동일한 작업을 반복적으로 수행하는 반복문이다.

    반복대상이란, 반복가능 자료형으로 리스트, 튜플, 딕셔네리, 세트, 문자열, 반복가능 객체를 말한다.

    반복대상의 모든 요소를 전부 꺼내어 마지막에 이르면, 반복이 완료되어 종료된다.

    else의 코드블락은 반복이 완료된 경우, 딱 한번 실행된다.

    else의 코드블락은 반복이 break키워드로 종료된 경우, 실행되지 않는다.

    딕셔네리를 반복대상으로 한 경우, 변수에는 키 값만 하나씩 돌아가며 저장된다.


    객체는 클래스에 반복자 프로토콜(iterator protocol)에 따라 아래의 메서드를 정의하여 반복대상으로 사용할 수 있다.

      1. __iter__()를 정의하여 return self를 실행한다.

      2. __next__()를 정의하여 반복논리를 만들고 그에 따라

          1) 다음 요소를 return하거나

          2) 마지막에 도달하면 raise StopIteration을 실행한다.

    #예제
    class iterableObj:
        def __init__(self, attr1, attr2, attr3):
            self.attr1 = attr1
            self.attr2 = attr2
            self.attr3 = attr3
            self._attr_num = 0             #반복을 위한 비공개 속성
    
        def __iter__(self):
            return self
    
        def __next__(self):
            self._attr_num += 1            #반복 순서 결정하기
            match self._attr_num:          #match문 사용
                case 1: return self.attr1  #속성을 돌아가며 반복
                case 2: return self.attr2
                case 3: return self.attr3
                case _:                    #반복완료
                    self._attr_num = 0     #다음 반복을 위한 초기화
                    raise StopIteration
    
    obj = iterableObj(1, 2, 3)
    a = [attr for attr in obj]
    print(a)                               #[1, 2, 3]
    

    for문 안에 for문을 넣으면, 다중 반복이 가능하다.

    #예제
    a = []
    for i in range(1, 5):      #4회 반복, i는 1부터 4까지
        for j in range(1, 3):  #2회 반복, j는 1부터 2까지
            a.append(i*j)
    print(a)                   #[1, 2, 2, 4, 3, 6, 4, 8]
    

  • continuebreak키워드
    • 이 두 키워드는 반복문의 실행문 내에서 반복을 제어하기 위한 키워드들이다.
    • while문과 for문의 실행문에서 사용된다.

    • continue키워드는 현재 진행중인 반복만을 중지하고, 다음 반복을 바로 시작하는 키워드이다.
    • 즉, 실행문에서 continue키워드를 만나면, 그 뒷줄의 모든 실행문은 실행하지 않고, 바로 반복 중인 코드블락의 첫번째 줄로 돌아가 반복을 계속한다.

    • break키워드는 현재 진행중인 코드블락의 반복 전부를 중단하는 키워드이다.
    • 실행문에서 break키워드를 만나면, 즉시 반복 중인 코드블락의 반복을 중단하고, 반복문 이후의 코드를 실행한다.
    • break키워드로 반복문이 종료되면, else코드블락을 실행하지 않는다.

  • 반복문과 특별히 자주 함께 사용되는 함수: range()
    range(끝숫자)
    range(시작숫자, 끝숫자)
    range(시작숫자, 끝숫자, 스텝)
    
    • range()는 정수형 숫자들을 시작숫자부터 끝숫자까지 차례로 출력하는 함수이다.
    • 슬라이싱과 동일하게 시작숫자는 포함되고, 끝숫자는 포함되지 않는다.
    • 끝숫자만을 인수로 입력하면 0부터 1씩 증가하며 끝숫자(불포함)까지 출력한다.
    • 시작숫자의 디폴트 값은 0, 스텝의 디폴트 값은 1이다.
  • 리스트 내포(List Comprehension)

    [실행문 for 변수명 in 반복대상 if 조건]
    #리스트 내포는 아래 코드의 축약형이다
    a = []                   #리스트를 저장할 변수
    for 변수명 in 반복대상:   #for문
        if 조건:              #if문
            a.append(실행문)  #실행 결과를 리스트에 추가
    
    #한줄로
    for 변수명 in 반복대상: if 조건: a.append(실행문)
    

    리스트 내포는, 리스트를 생성하는 표현 내부에 반복표현을 내포하고 있는 것이다.

  • 반복대상for문의 반복대상과 동일하다.
  • 변수명for문의 변수명과 동일하다.
  • 변수는 실행문조건 내에서 사용할 수 있다.

  • 조건if문의 조건과 동일하다. 즉, 반복조건이 아니라 실행조건이다.
  • 조건이 True인 경우에만 실행문이 실행된다.

  • 실행문을 통해 return된 값은 리스트에 차례대로 저장된다.
  • 실행문에 조건표현이 올 수도 있으며, 이 때 반복대상 뒤에 따라오는 조건과 착각하지 말 것
  • #예제
    a = [x*2 for x in range(5)]         #a=>[0, 2, 4, 6, 8]
    b = [x*x for x in range(5) if x%2]  #b=>[1, 9]
    
    #예제(조건표현과 함께)
    c = ["a" if x % 2 else "b" for x in range(10)]
    #c=>['b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a']
    

  • 다중 반복

    for문의 다중 반복을 리스트 내포에서도 구현할 수 있다.

    [실행문 for 변수명1 in 반복대상1 if 조건1
            for 변수명2 in 반복대상2 if 조건2
            ...                             ]
    
    #한줄로
    [실행문 for 변수명1 in 반복대상1 if 조건1 for 변수명2 in 반복대상2 if 조건2 ...]
    
    • 반복대상1이 1차 반복이고, 반복대상2은 2차 반복이며, 뒤로 갈 수록 내부로 들어가는 반복이 된다.
    • 모든 변수는 실행문에서 사용할 수 있다.
    • 변수명1조건2에서 사용할 수 있으나, 변수명2조건1에서 사용할 수 없다.
    • 즉, 앞의 변수는 뒤의 조건에서 사용할 수 있으나, 뒤의 변수는 앞의 조건에서 사용할 수 없다.
    #예제
    a = [x*y for x in range(1,4) for y in range(1,5)]
    #a=>[1, 2, 3, 4, 2, 4, 6, 8, 3, 6, 9, 12]
    
  • 함수(Functions)

    함수는 인자를 입력받아, 실행문을 실행하고, 그 결과를 출력하는 것을 말한다.

    함수는 먼저 정의를 하고, 나중에 호출하여 사용한다.

    함수의 실행은 호출로 시작하고, 함수 내부의 실행문을 모두 실행하거나 return문을 통하여 종료된다.

    함수의 정의(Definition)

    def 함수명(변수명1=디폴트값1, /, 변수명2=디폴트값2, *, 변수명3=디폴트값3, ...):
        """설명글"""
        실행문1
        실행문2
        ...
        return 결과
    

    함수명은 보통 변수명과 동일하게 snake_case 스타일로 작명한다.

    일반적으로 함수명 작명시, 동사형 단어로 시작하여 함수의 목적을 분명히 한다.

    매개변수(Parameters)

  • 매개변수란, 함수를 실행하기 필요한 입력값들을 정의한 것을 말한다.
  • 매개변수는 변수명을 통해 정의한다.
  • 매개변수의 수에는 제한이 없다.
  • 매개변수가 없는 함수도 있다. 이때, def 함수명():의 형식으로 정의한다.
  • #예제
    #매개변수: id, name, grade, class_no
    def add_student(id, name, grade, class_no):
        pass
    

  • 매개변수(Parameters)와 인자(Arguments)
    • 매개변수는 함수의 "정의"시 입력값들을 정의하기 위한 변수명을 지칭한다.
    • 인자는 함수의 "호출"시 매개변수의 정의에 따라 입력한 값을 지칭한다.
    • 즉, 매개변수는 정의할 때, 인자는 호출할 때, 사용되는 변수를 각각 가리키며, 동일한 대상을 지칭한다.
    • 종종 매개변수와 인자는 실무상 혼용하여 사용되며, 실제로 동일한 대상을 가리키므로 문제삼지 말고 넓은 마음으로 양해할 것
    • 인자는 "전달인자" 또는 "인수"라는 이름으로 불리기도 한다.
    • 인자는 위치 인자와 키워드 인자로 구분된다.
      • 위치 인자: 그 위치에 따라 어떤 변수명에 할당될지 결정하는 인자
      • 키워드 인자: 위치와 관계 없이, 변수명=데이터의 형태로 입력되는 인자
      • 위치 "전용" 또는 키워드 "전용"이 아니라면, 어떤 방식으로도 인자를 입력할 수 있다.
    #예제(정의)
    def add_student(id, name, grade, class_no):            #매개변수
        pass
    
    #예제(호출)
    add_student(123, "John", 4, 5)                         #위치 인자 사용
    add_student(id=123, name="John", grade=4, class_no=5)  #키워드 인자 사용
    

  • 위치 전용 매개변수
    • 특수문자 / 앞에 오는 매개변수들은 반드시 위치 인자로 입력해야 한다.
    #예제
    def add_student1(id, name, /, grade, class_no):  #위치 전용: id, name
        pass
    
    def add_student2(id, name, grade, class_no, /):  #위치 전용: id, name, grade, class_no
        pass
    
    add_student1(123, "John", 4, class_no=5)         #grade, class_no은 전용 설정 없음
    add_student2(123, "John", 4, 5)                  #위치 인자만 허용
    

  • 키워드 전용 매개변수
    • 특수문자 * 뒤에 오는 매개변수들은 반드시 키워드 인자로 입력해야 한다.
    #예제
    def add_student1(id, name, *, grade, class_no):         #키워드 전용: grade, class_no
        pass
    
    def add_student2(*, id, name, grade, class_no):         #키워드 전용: id, name, grade, class_no
        pass
    
    add_student1(123, name="John", grade=4, class_no=5)     #id, name은 전용 설정 없음
    add_student2(id=123, name="John", grade=4, class_no=5)  #키워드 인자만 허용
    
    
    #예제(복합)
    def add_student3(id, /, name, grade, *, class_no):
        pass
    
    #위치 전용: id | 전용 설정 없음: name, grade | 키워드 전용: class_no
    add_student3(123, "John", grade=4, class_no=5)
    
  • 임의의 인자를 위한 매개변수

    def 함수명(변수명, *args, 키워드전용변수명, **kwargs):
        pass
    

    함수를 정의하는 시점에서 특정할 수 없는 임의의 인자를 받기위한 특수한 매개변수를 정의할 수 있다.

    변수명이 반드시 args, kwargs일 필요는 없으나, 보통 이렇게 쓴다.

  • 종류
    • *args: 임의의 위치 인자를 위한 매개변수
    • **kwargs: 임의의 키워드 인자를 위한 매개변수

  • 변수명 바로 앞에 *, **을 붙여서 임의의 인자를 받는 매타변수임을 선언한다. (Packing의 의미임)
  • 임의의 인자를 위한 매개변수는 위치 인자를 위해 1개, 키워드 인자를 위해 1개를 선언할 수 있다.
  • *args이후에는 키워드 전용 매개변수(키워드전용변수명)만 올 수 있다.
  • args는 함수 내부에서 리스트 자료형으로 주어진다.
  • kwargs는 함수 내부에서 딕셔네리 자료형으로 주어진다.
  • #예제
    def add_student1(id, name, *args):                              #args: 임의의 위치 인자
        if args: print(args[0])                                     #args가 비어있지 않다면, 첫번째 요소를 프린트
    
    def add_student2(id, name, **kwargs):                           #kwargs: 임의의 키워드 인자
        for key in kwargs:                                          #kwargs key를 대상으로 반복
            print(kwargs[key])                                      #각 key의 해당 밸류를 프린트
    
    def add_student3(id, *args, grade, **kwargs):                   #grade는 키워드 전용
        if "class_no" in kwargs:                                    #kwargs에 "class_no"가 포함되어 있다면
            print(f"{id}: {args[0]} {grade}-{kwargs["class_no"]}")  #프린트
        else: print("Ooops")
    
    add_student1(123, "John", 4, 5)                                 #결과: 4
    add_student2(123, "John", grade=4, class_no=5)                  #결과: 5
    add_student3(123, "John", grade=4, class_no=5)                  #결과: '123: John 4-5'
    add_student3(123, "John", grade=4, class_no1=5)                 #결과: 'Ooops'
    

    return

    return 결과
  • 함수 내부에서 실행문을 실행한 결과는 return 키워드를 사용하여 반환한다.
  • 반환할 것이 없으면 return문은 생략가능하다.
  • return문의 위치와 상관없이 return 키워드를 만나면 함수의 실행은 종료된다.
  • 결과 없이 return 키워드를 단독으로 사용할 수 있다.
  • 함수의 호출(Calling)

    #위치 인자 사용
    함수명(데이터1, 데이터2, ...)                         #return 값이 없는 경우
    변수명 = 함수명(데이터1, 데이터2, ...)                 #return 값이 있는 경우
    
    #키워드 인자 사용
    함수명(변수명1=데이터1, 변수명2=데이터2, ...)          #return 값이 없는 경우
    변수명 = 함수명(변수명1=데이터1, 변수명2=데이터2, ...)  #return 값이 있는 경우
    
  • 함수는 정의된 바에 따라 함수명에 ()사용하여 호출한다.
  • 함수명에 이어 괄호 안에 정의된 바에 따라 인자들을 입력한다.

  • 위치 인자와 키워드 인자
    • 위치 인자: 변수명 없이 데이터만 입력하는 인자
    • 키워드 인자: 변수명=데이터으로 입력하는 인자

  • 필수 인자와 선택 인자
    • 필수 인자: 매개변수가 디폴트값 없이 변수명으로 정의된 인자
    • 선택 인자: 매개변수가 변수명=디폴트값으로 정의된 인자

    • 필수 인자는 함수 호출시, 반드시 주어져야 하는 인자이다.
    • 선택 인자는 함수 호출시, 생략가능한 인자이다.
    • 선택 인자의 생략시, 자동으로 디폴트값이 할당된다.
    #예제
    #필수 인자: id, name | 선택 인자: type, dps, hp
    def create_character(id, name, type="user", *, dps=1000, hp=10000)
        return {"id":id, "name":name, "type":type, "dps":dps, "hp":hp}
    
    user1 = create_character(1, "John")
    #user1 => {"id":1, "name":"John", "type":"user", "dps":1000, "hp":10000}
    user2 = create_character(2, "Alice", dps=2000)
    #user2 => {"id":2, "name":"Alice", "type":"user", "dps":2000, "hp":10000}
    user3 = create_character(3, "Bob", dps=2000, hp=20000)
    #user3 => {"id":3, "name":"Bob", "type":"user", "dps":2000, "hp":20000}
    monster1 = create_character(990, "Mon1", "npc")
    #monster1 => {"id":990, "name":"Mon1", "type":"npc", "dps":1000, "hp":10000}
    boss1 = create_character(9999, "Boss1", "boss", dps=100000, hp=10000000)
    #boss1 => {"id":9999, "name":"Boss1", "type":"boss", "dps":100000, "hp":10000000}
    
  • 함수 내의 함수

    함수의 정의 안에서 또다른 함수를 정의할 수 있다.

    def 외부함수명(외부매개변수):
        def 내부함수명(내부매개변수):
            내부실행문
            ...
    
        외부실행문
        내부함수명(데이터)
        ...
    
  • 내부함수는 외부함수의 실행문에서만 사용할 수 있다.
  • 고차함수(Higher Order Function)을 정의할 때 주로 사용한다.
  • 재귀 함수(Recursive Function)

  • 재귀 함수란, 함수의 정의 안에서 정의 중인 함수를 호출하는 함수를 말한다.
  • 재귀 함수는 복잡한 논리를 매우 간결하게 작성할 수 있다는 장점이 있다.
  • 그러나, 재귀 함수는 메모리를 더 많이 사용하는 경향이 있다.
  • 또한, 코드 실행속도를 저하시키는 등의 단점도 있으므로 사용시 주의가 필요하다.
  • def 함수명(매개변수):
        실행문
        함수명(데이터)  #이 부분이 재귀임
    

    현재 정의 중인 함수명을 호출하는 경우, 재귀함수가 된다.

    그 밖의 사항은 일반 함수의 규칙을 따른다.

    #예제
    def factorial(n):
        if n == 1:                     #재귀 종료 조건
            return 1
        else:
            return x * factorial(n-1)  #재귀
    
    a = factorial(4)
    #결과: a => 4*3*2*1=24
    

    람다표현(Lambda Expression)

  • 람다표현은 함수를 한줄에 정의하는 축약형 표현이다.
  • 람다표현은 함수형 프로그래밍(Functional Programming)을 구현하기 위한 도구이다.
  • 람다표현은 무명(anonymous) 함수라고도 불린다.

  • #정의
    lambda 변수명1, 변수명2, ... : 실행문
    lambda 변수명1=디폴트값1, 변수명2=디폴트값2, ... : 실행문  #디폴트값이 있는 경우
    
    #호출을 위해 람다표현을 변수에 저장
    함수명 = lambda 변수명1, 변수명2, ... : 실행문
    
    #호출
    함수명(데이터1, 데이터2, ...)                 #위치 인자
    함수명(변수명1=데이터1, 변수명2=데이터2, ...)  #키워드 인자
    
    #정의 즉시 호출(무명 호출)
    (lambda 변수명1, 변수명2, ... : 실행문)(데이터1, 데이터2, ...)
    
  • 변수명은 매개변수에 해당하며, 일반 함수와 동일한 규칙이 적용된다.
  • 따라서, 매개변수가 없는 경우, *args, **kwargs인 경우도 가능하다.
  • 실행문은 내부에서 인자를 사용할 수 있으며, 단 1개의 실행문만을 정의할 수 있다.

  • 람다표현을 변수에 저장하여 그 변수의 이름을 함수명으로 하여 호출할 수 있다.
  • 람다표현은 정의 즉시 호출하여 사용할 수 있다. 이때, (람다표현)(인자값) 형식을 사용한다.
  • 람다표현의 호출시 인자는 일반 함수와 동일한 규칙이 적용된다.

  • 실행문의 결과값은 자동으로 return된다.
  • 만약 결과값이 없다면 Nonereturn된다.
  • 실행문에는 return, raise, assert, pass 키워드를 사용할 수 없다.
  • #예제(변수에 저장하여 호출)
    a = lambda x: x*x         #제곱
    print(a(3))               #결과: 9
    
    b = lambda x, y: 2*x + y  #수식(2*x + y)
    print(b(3, 2))            #결과: 8
    
    #예제(즉시 호출)
    print((lambda x, y: f"{x}학년 {y}반")(1,2))
    #결과: '1학년 2반'
    

    입력(Input) 함수

    input()함수는 터미널에서 사용자의 키보드 입력을 받아 문자열로 반환하는 빌트인(built-in) 함수이다.

    변수명 = input("입력요청")
  • 입력요청에는 사용자의 입력을 요청하는 내용의 문자열 또는 문자열 블락을 사용한다.
  • input()의 결과는 문자열이다.
  • 따라서, 숫자를 입력 받았을 때 숫자문자를 숫자로 변환시켜야 한다.
  • #예제
    ans = input("가장 좋아하는 숫자를 입력하세요 : ")
    ans_num = int(ans)  #정수로 변환
    

    파일(Files) 읽고 쓰기

    open()함수는 파일을 열어 읽거나 쓰기 위해 사용하는 함수이다.

    파일을 열땐 with 키워드를 사용할 것을 강력 추천

    파일이 열린 시간을 최소화할 수 있도록 코드를 작성할 것을 강력 추천

    즉, 파일을 열었을 땐 읽기 또는 쓰기 등의 파일과 관련된 작업만 하고, 파일과 무관한 것은 사전 또는 사후에 할 것

    파이썬 문서 보기: open()

    #단독으로 열기
    f = open("파일명", "모드")
    실행문
    f.close()
    
    #with 키워드와 함께 열기
    with open("파일명", "모드") as f:
        실행문
    
  • open()함수로 열린 파일은 반드시 close()함수로 닫아야 한다.
  • 열린 파일을 닫지 않으면, 매우 중대한 결함인 메모리 누수(memory leak) 현상이 발생한다.
  • with 키워드를 사용하여 파일을 열면, 코드블락이 끝나는 시점에 자동으로 파일을 닫으므로 close()를 할 필요가 없다.

  • 파일명
    "파일경로/파일이름.확장자"
    • 파일명은 문자열이어야 한다.
    • 파일명은 대상파일이 위치한 경로와 확장자를 포함한다.
    • 파일경로 안에서 상/하위 디렉토리를 구분하는 특수문자로 /(슬래쉬)를 사용할 것을 추천
    • 파일경로는 상대적 경로를 사용하는 경우, 생략할 수 있다.
    • 확장자 앞에 있는 .도 반드시 포함시켜야 한다.
    • 파일이 존재하지 않는 경우, 모드에 따라 새파일을 생성하거나 에러를 발생시킨다.

  • 파일모드
    r r+ w w+ a a+
    read()
    readline()
    readlines()
    write()
    writelines()
    seek() 후에 write()
    새파일 생성
    기존 내용 삭제
    시작 위치부터
    끝 위치부터

    t(텍스트), b(바이너리)는 위의 읽기/쓰기 모드 뒤에 추가하여 사용할 수 있다.

    디폴트값은 rt이며 의미는 텍스트 읽기이다.

  • 설명글(Docstring)

  • 설명글(Docstring)이란, 간략한 설명을 포함하는 문자열 블락이다.
  • help(함수명)을 사용하면 설명글이 출력된다.
  • 설명글은 함수 뿐만 아니라, 클래스, 메서드, 모듈, 패키지에서도 사용된다.
  • 함수의 경우, 함수의 역할, 매타변수의 타입과 짧은 설명, return타입, 발생할 수 있는 에러 타입 등을 설명한다.
  • #예제(reStructuredText(reST) 스타일)
    def gcd(a, b):
        """Euclidean algorithm으로 최대공약수(GCD)를 찾는다.
    
        :param a: 첫번째 숫자
        :param b: 두번째 숫자
        :type a: int
        :type b: int
        :returns: a와 b의 최대공약수
        :rtype: int
        """
        pass
        
    #예제(한줄 스타일)
    def gcd(a, b):
        """두 정수의 최대공약수(GCD)를 Euclidean algorithm으로 찾아 반환한다."""
        pass
    

    클래스(Classes)

    파이썬은 객체 지향 프로그래밍(Object-Oriented Programming(OOP)) 언어이다.

    파이썬의 대부분은 객체로 이루어져 있다.

    개념(Concepts)

  • 클래스(Classes)
    • 클래스란, 그 속성과 행동이 다른 그룹과 구별되는 공통점이 있어 묶어놓은 그룹을 말한다.
    • 클래스는 객체를 생성하기 위한 설계도와 같은 역할을 한다.

    • 클래스는 사용자 정의 자료형에 해당된다.
    • 클래스는 추상적이며 개념적이다.
  • 객체(Objects)
    • 객체란, 소속된 클래스의 다른 객체와 구별되어 독립적으로 존재하는 것을 말한다.
    • 객체는 클래스의 인스턴스(하나의 경우)이다.
    • 즉, 객체는 설계도에 따라 만들어진 하나의 제품 같은 것이다.

    • 클래스에 따라 데이터가 생성되어 컴퓨터 메모리의 물리적 공간에 저장될 때 객체는 생성된다.
    • 따라서, 일반적으로 객체는 변수에 할당된다.
    • 객체는 구체적이며 현실적이다.
  • 속성(Attributes)과 메서드(Methods)
      속성(Attributes) 메서드(Methods)
      설명 객체가 보유한 데이터 객체가 자기 또는 다른 객체의 데이터를 처리하는 것
      의미 객체의 상태 객체의 동작
      구현방법 변수 함수
      클래스가 보유 가능 가능
      각 객체가 보유 가능 가능

    • 속성(Attributes)과 특성(Property)은 의미가 비슷하여 혼용이 가능하지만, 특성(Property)이 좀더 넓은 개념이다.
    • 객체가 가진 특성(Property)을 속성(Attributes)이라 한다.
    • 클래스가 가진 속성(Attributes)을 특별히 클래스 변수(Class Variable)라 한다.
    • 속성과 메서드는 .(닷 연산자, 멤버 엑세스 연산자)를 통해 사용할 수 있다.
    • 파이썬에는 비공개라는 개념이 존재하지 않는다. 즉, 모두 접근이 가능하다.
    • 단지, 이름 앞에 _ 1개가 붙어 있는 속성 및 메서드는 비공개처럼 다루기로 약속한 것이다.
  • 상속(Inheritance)
    • 상속이란, 한 클래스가 다른 클래스의 속성과 메서드를 모두 이어받는 것을 말한다.
    • 이때, 속성과 메서드를 전수해주는 클래스를 부모클래스라 하고, 이어받는 클래스를 자식클래스라 한다.
    • 부모클래스가 상위클래스이고, 자식클래스는 하위클래스이다.
    • 예를 들면, '포유류'는 '고양이'의 부모클래스(상위)이고, '동물'의 자식클래스(하위)이다.
    • 따라서, '포유류'는 '동물'의 모든 속성과 동작을 가지고 있고, '고양이'는 '포유류'의 모든 속성과 동작을 가지고 있다.
    • 자식클래스로 갈 수록 부모클래스가 구체화되어 확장되는 개념이다.
  • class

    class 클래스명:
    #======== 클래스 ========
        #클래스 변수
        _변수명 = 데이터  #클래스 비공개 변수
        변수명 = 데이터  #클래스 공개 변수
    
        #클래스 메서드
        @classmethod
        def 메서드명(cls, 매개변수):
            ...
            print(cls.변수명)  #클래스 변수 접근
    
    #======== 객 체 ========
        #객체 초기화
        def __init__(self, 매개변수):
            self._속성명 = 데이터  #객체 비공개 속성 초기화
            self.속성명 = 데이터  #객체 공개 속성 초기화
    
        #객체 Setter
        def set_속성명(self, 매개변수):
            self.속성명 = 데이터  #객체 속성 업데이트
    
        #객체 Getter
        def get_속성명(self, 매개변수):
            return self.속성명  #객체 속성 return
    
        #객체 공개 메서드
        def 메서드명(self, 매개변수):
            ...
            print(self.속성명)  #객체 속성 접근
            print(클래스명.변수명)  #클래스 변수 접근
            클래스명.메서드명(데이터)  #클래스 메서드 호출
    

    클래스명은 보통 영문 CamelCase 스타일로 작명한다.

    속성명은 변수와 동일하게 보통 snake_case 스타일로 작명한다.

    메서드명은 함수와 동일하게 보통 snake_case스타일로 작명한다.

    객체의 생성과 삭제

    #생성
    객체명 = 클래스명(초기화데이터)
    
    #삭제
    del 객체명
    
  • 객체는 클래스명 + () 으로 생성한다.
  • 객체를 생성할 때, () 안에 클래스의 __init__()의 정의에 따라 초기화에 필요한 데이터를 입력한다.
  • 생성된 객체는 변수 객체명에 저장하여 사용한다.
  • 각 객체는 독립성이 있으므로 객체명은 서로 달라야 한다.

  • 객체의 생명주기(Life Cycle)
    • 클래스명() : 클래스의 객체 생성자 호출
    • __new__() : 객체 생성 메서드 호출 (객체의 생성)
    • __init__() : 객체 초기화 메서드 호출
    • 객체의 사용
    • del 객체명 : 객체 삭제문 실행
    • __del__() : 삭제 전처리 메서드 호출
    • 객체의 삭제
  • 객체 속성과 메서드

  • class내부에서 객체 속성과 메서드 사용
    class 클래스명:
        def 메서드명1(self, 매개변수):  #self => 객체
    
            self._속성명               #객체의 비공개 속성에 접근
            self.속성명                #객체의 공개 속성에 접근
            self._메서드명(데이터)      #객체의 비공개 메서드 호출
            self.메서드명2(데이터)      #객체의 다른 메서드 호출
    
    • 객체는 매개변수 self를 통하여 메서드 내부에 전달된다
    • self는 키워드가 아니고 변수명일 뿐이다. 그러나 보통 self로 한다.
    • self + .(닷 연산자)로 객체의 속성과 메서드를 사용할 수 있다.
  • class외부에서 객체 속성과 메서드 사용
    객체명 = 클래스명(초기화데이터)  #객체 생성
    
    객체명.속성명                   #객체의 속성에 접근
    객체명.메서드명(데이터)          #객체의 메서드 호출
    
    • 객체는 변수 객체명에 저장되고, 그 변수를 통하여 사용한다.
    • 객체명 + .(닷 연산자)로 객체 속성과 메서드를 사용할 수 있다.
    • 객체의 비공개 속성 또는 비공개 메서드는 class문 외부에서 사용하지 않기로 한다.
  • 비공개 속성과 메서드
    • 파이썬에는 비공개라는 개념이 존재하지 않는다.
    • 하지만, 속성과 메서드의 이름 앞에 붙는 _에 따라 특별하게 다룬다.
    • _를 1개 붙여 _속성명과 같이 하면, 아무일도 일어나지 않는다. 단지, 비공개로 다루기로 약속한다.

    • _를 2개 붙여 __속성명과 같이 하면, 파이썬의 '이름 썩기 알고리즘'이 작동된다.
    • '이름 썩기 알고리즘'은 __속성명_클래스명__속성명으로 바꾸어 준다.
    • 이름이 바뀌기 때문에 좀더 비공개인 것처럼 느껴지게 된다.
    • 하지만, '이름 썩기 알고리즘'은 속성을 비공개하기 위해 존재하는 알고리즘이 아니며, 바뀐 이름을 알고 있다면 접근이 가능하다.
    • '이름 썩기 알고리즘'은 상속시 상/하위 클래스간 이름의 충돌을 방지하기 위한 알고리즘이다.
  • 클래스 변수와 메서드

  • 객체처럼 .(닷 연산자)로 클래스 변수와 메서드를 사용할 수 있다.
  • 다만, 아래와 같이 경우에 따라 .(닷 연산자)의 대상 달라진다.

  • 사용위치 클래스 변수 접근 클래스 메서드 호출
    비공개 공개 비공개 공개
    class문 내부 클래스 메서드 정의 내부 cls._변수명 cls.변수명 cls._메서드명(데이터) cls.메서드명(데이터)
    객체 메서드 정의 내부 클래스명._변수명 클래스명.변수명 클래스명._메서드명(데이터) 클래스명.메서드명(데이터)
    class문 외부 사용 ✗ 클래스명.변수명 사용 ✗ 클래스명.메서드명(데이터)

    cls는 키워드가 아니고 변수명일 뿐이다. 그러나 보통 cls로 한다.

    상속(Inheritance)

    class 자식클래스명(부모클래스명):
        pass
    
  • 자식클래스는 부모클래스가 정의하고 있는 속성과 메서드를 별도로 정의하지 않아도 이미 모두 포함하고 있다.

  • super() 함수
    • super()는 자식클래스의 class문 내에서 호출할 수 있다.
    • super()는 부모클래스를 return한다.
    • 자식클래스가 오버라이딩한 메서드가 아닌 부모클래스의 메서드를 사용코자 할 때 사용하는 함수이다.
  • 메서드 오버라이딩(Method Overriding)
    • 메서드 오버라이딩이란, 자식클래스가 부모클래스의 메서드를 재정의하는 것을 말한다.
    • 메서드명이 부모클래스와 동일해야 한다.
    • 매개변수는 부모클래스와 다를 수 있다.

    • 자식클래스가 새로운 행위를 하는 것이 아니라, 부모클래스의 행위를 변형시켜 하는 경우를 구현한 것이다.
    • 즉, 자식클래스가 부모클래스가 하지 않는 새로운 행위를 한다면, 새 메서드를 추가하여 구현한다.
    • 하지만, 자식클래스가 부모클래스가 하는 행위를 변형시켜 한다면, 메서드 오버라이딩을 하여 구현한다.
  • #예제
    class Person:                                  #부모클래스
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        def greeting():
            print("Hi")
    
    class Student(Person):                         #자식클래스1
        def __init__(self, name, age, class_num):  #메서드 오버라이딩
            super().__init__(name, age)            #부모클래스 메서드 호출
            self.class_num = class_num             #속성 추가
    
        def study(subject):                        #메서드 추가
            print(f"Studying {subject}")
    
    class Teacher(Person):                         #자식클래스2
        def __init__(self, name, age, subject):    #메서드 오버라이딩
            super().__init__(name, age)            #부모클래스 메서드 호출
            self.subject = subject                 #속성 추가
    
        def greeting(to_whome="Everyone"):         #메서드 오버라이딩
            print(f"Hi {to_whome}")
    
        def teach():                               #메서드 추가
            print(f"Teaching {self.subject}")
    

  • 메서드 오버로딩(Method Overloading)
    • 메서드 오버로딩이란, 한 클래스 내에서 같은 이름의 메서드를 매개변수의 수와 타입을 달리하여 여러개 정의하는 것을 말한다.

    • 엄밀히 말하면, 파이썬은 메서드 오버로딩을 지원하지 않는다.
    • 같은 이름의 메서드를 여러개 정의하면, 가장 마지막에 정의된 메서드만을 실행하기 때문이다.

    • 하지만, 파이썬은
      • 메서드 정의시 매개변수의 자료형을 특정하지 않는다. 즉, 매개변수가 동적변수이다.
      • 디폴트값과 위치/키워드인자를 활용하여 다양한 형태의 함수 호출이 가능하다.
      따라서, 메서드 오버로딩과 비슷한 효과를 구현할 수 있다.
  • 상속시 속성명 충돌 방지
    • 이름 앞에 _ 2개를 붙여 __속성명으로 작명하면 파이썬의 '이름 썩기 알고리즘'이 작동한다.
    • '이름 썩기 알고리즘'은 __속성명_클래스명__속성명으로 바꾸어 충돌을 방지한다.
    • 따라서, 자식클래스는 자기 속성을 __속성명으로 접근하고, 부모클래스의 속성을 _부모클래스명__속성명으로 접근할 수 있다.
    • 자식클래스와 부모클래스가 동일한 이름의 속성을 각각 가져야할 필요가 있을 때 사용한다.
  • 모듈(Modules)

    모듈이란, 파이썬 파일을 말한다. 즉, .py 확장자를 가지고 있는 파일이 모듈이다.

    1개의 파이썬 파일이 1개의 모듈이다.

    만들기(Create)

  • 파이썬 코드를 작성하여, 모듈명.py로 저장한다.
  • 파이썬 파일이름과 모듈명은 동일하다.
  • 모듈명snake_case 스타일로 간결하게 작명한다.
  • 가져오기(Import)

    다른 파일에서 작성한 코드를 사용하려면, 우선 그 코드를 가져와야 한다.

    모듈은 import문으로 가져올 수 있다.

    #모듈명으로 가져오기
    import 모듈명
    
    #가져온 코드 사용하기
    모듈명.변수명
    모듈명.함수명()
    객체명 = 모듈명.클래스명()
    
  • import문은 가져와서 사용코자하는 코드보다 먼저 실행돼야 한다.
  • 보통, 모듈의 시작부분에 import문을 위치시킨다.
  • 가져온 코드는 객체처럼 .(닷 연산자)로 모듈의 멤버들(변수, 함수, 클래스)에게 접근하여 사용한다.
  • 가져올 모듈이 그 코드를 사용할 모듈과 다른 디렉토리(폴더)에 저장되어있는 경우, 패키지의 가져오기 방법을 따라야 한다.
  • 멤버 가져오기

    from-import문으로 모듈의 멤버를 특정하여 가져올 수도 있다.

    #모듈의 멤버 가져오기
    from 모듈명 import 함수명                   #1개만 특정하여
    from 모듈명 import 변수명, 함수명, 클래스명  #여러개 (콤마로 구분)
    from 모듈명 import *                       #전부 가져오기 (비추)
    
    #가져온 코드 사용하기
    변수명
    함수명()
    객체명 = 클래스명()
    
  • from-import문은 '모듈' 자체를 가져오는 것이 아니라 특정된 일부만 가져오는 것이다.
  • 대상모듈의 변수명, 함수명, 클래스명으로 가져올 대상을 특정한다.
  • 한 모듈에서 여러 멤버를 동시에 가져오는 경우 ,로 구분하여 한 줄의 import문으로 축약할 수 있다.
  • 가져올 모듈의 크기가 크고 방대한 경우, import 모듈명을 사용하는 것보다 코드의 로딩시간을 줄여 실행속도를 빠르게 할 수 있다.

  • 가져온 코드는 모듈명.(닷 연산자) 없이 바로 import한 이름으로 사용한다.
  • 따라서, 가져온 코드의 이름과 자기 모듈의 이름간에 충돌이 발생하지 않도록 주의하여야 한다.

  • import *를 사용하면 대상모듈에서 가져올 수 있는 코드를 모두 가져온다.
  • 즉, 이름이 _로 시작하는 멤버들을 제외하고 전부 가져온다.

  • import *를 사용하여 가져오기는 아래와 같은 이유로 특별한 이유가 없는한 사용하지 말기를 추천
    • 자기 코드와 가져온 코드 간의 구별이 힘들어, 코드의 가독성이 떨어진다.
    • 무엇을 가져왔는지 알기 힘들어, 이름 충돌이 일어날 확률이 매우 높다.
    • 제3개발자와 자동화도구의 혼동을 초래해, 코드의 유지보수가 힘들다.
    • import 모듈명으로 가져오는 것과 로딩속도에 차이가 없다.
  • as 키위드

    as 키위드는 이름을 바꿔주는 키워드이다.

    #모듈을 별명으로 가져오기
    import 모듈명 as 모듈별명
    
    #가져온 코드 사용하기
    모듈별명.변수명
    모듈별명.함수명()
    객체명 = 모듈별명.클래스명()
    
    #모듈의 멤버를 별명으로 가져오기
    from 모듈명 import 함수명 as 함수별명
    from 모듈명 import 변수명 as 변수별명, 함수명 as 함수별명, 클래스명 as 클래스별명
    
    #가져온 코드 사용하기
    변수별명
    함수별명()
    객체명 = 클래스별명()
    
  • as 키워드를 사용하여 좀더 읽기 쉽고 쓰기 쉬운 이름으로 바꿀 수 있다.
  • 별명을 사용하여 자기코드와 가져온 코드간의 이름 충돌을 회피할 수도 있다.
  • __name__ 변수

  • 각 모듈은 빌트인(built-in) 변수 __name__를 가지고 있다.
  • __name__에는 그 모듈의 모듈명이 저장되어 있다.
  • 모듈별명이 아니라 모듈본명이 저장되어 있다.
  • 메인모듈의 __name__변수에는 모듈명과 상관없이 "__main__"이 저장된다.

  • 자주 쓰는 코드
    if __name__ == "__main__":
        main()
    
    • 해석: 변수 __name__"__main__"이 저장되어 있다면, 함수 main()를 실행하라.
    • 의미: 현재 실행 중인 모듈이 메인모듈인 경우에만, 함수 main()를 실행하라.
    • 이유:
      • import 모듈명으로 가져온 모듈은 import 지점에서 실행되는데,
      • 모듈의 사용부분을 함수로 정의하지 않으면, 코드를 가져간 본 모듈이 원치않는 지점에서 코드가 사용되는 문제가 발생한다.
      • 따라서, 모듈이 메인모듈일 때만 실행할 코드들을 함수 main() 안에 넣어 정의한 후,
      • 변수 __name__로 메인모듈임이 확인된 경우만 실행하는 것으로 해결한다.
  • 메인모듈 실행하기

    터미널에서 파이썬 실행명령(python,python3,py 등 OS에 따라 다름)으로 메인모듈을 실행시킬 수 있다.

    python 모듈명.py
    python3 모듈명.py
    
    py 모듈명.py  #축약형
    
  • 파이썬 실행명령(예: py)의 뒤를 따르는 모듈명.py를 '메인모듈'이라 한다.
  • 메인모듈의 __name__변수에는 모듈명과 상관없이 "__main__"이 저장된다.
  • 패키지(Packages)

    패키지란, 파이썬 파일(모듈)들을 담고 있는 디렉토리(폴더)를 말한다.

    패키지는 다층구조를 가질 수 있다. 즉, 패키지 안에 다층의 하위 디렉토리들을 둘 수 있다.

    만들기(Create)

    패키지를 만들기 위해서는 우선 패키지 구조를 결정해야 한다.

    패키지 구조는 소프트웨어 아키텍쳐(Software Architecture)와 밀접한 관계를 갖는다.

    패키지명은 영어 소문자로 간결하게 작명하며, _는 될 수 있으면 포함시키지 않는다.

    루트패키지명/
        __init__.py
        __main__.py
        하위패키지명1/
            __init__.py
            모듈명1-1.py
            모듈명1-2.py
            ...
        하위패키지명2/
            __init__.py
            모듈명2-1.py
            모듈명2-2.py
            ...
        하위패키지명3/
            __init__.py
            모듈명3-1.py
            모듈명3-2.py
            ...
    

    /으로 끝나는 것은 디렉토리이며, .py로 끝나는 것은 파일이다.

    __init__.py 파일

  • __init__.py 파일은 패키지 초기화 모듈이다.
    • 패키지 초기화란, 패키지의 소속 모듈들을 실행하기 위해 먼저 실행하여야 할 필요가 있는 코드들을 실행하는 것을 말한다.
    • 따라서, 패키지(디렉토리)마다 1개씩 가지고 있다.

    • 내용이 없는 빈 파일로 생성하는 경우가 대부분이다.
    • 빈 파일이라도 생성하는 이유는 __init__.py 파일이 패키지의 구조를 파이썬 인터프리터에게 알려주는 모듈이기 때문이다.
    • 빈 파일이라면 파이썬 버전 3.3 이상에서는 생략 가능하다.

    • __init__.py 파일은 해당 패키지의 모듈이 import될 때, 먼저 로딩되어 실행된다.
    • setup()등의 함수를 정의하여 실행시키기도 한다.
  • __init__.py 파일 내에서도 import문을 사용하여 다른 모듈을 가져올 수 있다.

  • __all__ 변수

      __all__ 변수는 __init__.py 파일 내에 위치하여, from 패캐지명 import *를 통해 가져오는 모듈들의 이름을 지정하고 리스트로 저장하고 있는 변수이다.

      #__init__.py 안에서
      __all__ = [모듈명1, 모듈명2, ...]
      
      
      #모듈 안에서
      from 패캐지명 import *  #가져오는 모듈들: 모듈명1, 모듈명2, ...
      

      __all__ 변수는 리스트 자료형을 받는다.

  • 가져오기(Import)

    #방법1: import
    import 루트패키지명.하위패키지명.모듈명                              #모듈 가져오기
    import 루트패키지명.하위패키지명.모듈명.함수명                        #모듈 멤버 가져오기 (이 경우에는 함수)
    
    #방법2: from-import
    from 루트패키지명.하위패키지명 import 모듈명                         #모듈 가져오기
    from 루트패키지명.하위패키지명.모듈명 import 변수명, 함수명, 클래스명  #모듈 멤버 가져오기
    
    #방법3: from-import *(wildcard)
    from 루트패키지명.하위패키지명 import *                              #하위패키지의 __init__.__all__에 정의된 모든 모듈 가져오기
    from 루트패키지명.하위패키지명.모듈명 import *                        #모듈 멤버 전부 가져오기
    
  • 코드를 사용하기 위해서는 패키지가 아니라, 모듈을 가져와야 한다.
  • import 패키지명을 실행시키면 패키지를 가져오게 되고, 결국 모듈 내의 코드에 접근할 수 없게 된다.
  • 패키지는 가져올 모듈로 가는 경로에 해당한다.
  • 따라서, 모듈명 또는 모듈의 멤버가 import의 최종 목적지가 되어야 한다.

  • as 키워드는 모듈의 경우와 동일하게 사용할 수 있다.

  • 가져온 코드의 사용법
    #가져온 방법1: import
    루트패키지명.하위패키지명.모듈명.변수명
    루트패키지명.하위패키지명.모듈명.함수명()
    객체명 = 루트패키지명.하위패키지명.모듈명.클래스명()
    
    #가져온 방법2: from-import
    #모듈을 가져온 경우
    모듈명.변수명
    모듈명.함수명()
    객체명 = 모듈명.클래스명()
    
    #모듈 멤버를 가져온 경우
    변수명
    함수명()
    객체명 = 클래스명()
    
    #가져온 방법3: from-import *(wildcard) => 방법2와 동일
    
  • 메인모듈 실행하기

    메인모듈을 실행하는 방법은 2가지가 있다.

    #파일명으로 실행하기
    python 상위/경로/루트패키지명/하위패키지명/모듈명.py
    python3 상위/경로루트패키지명/하위패키지명/모듈명.py
    py 상위/경로/루트패키지명/하위패키지명/모듈명.py
    
    #모듈 옵션으로 실행하기
    python -m 루트패키지명.하위패키지명.모듈명
    python3 -m 루트패키지명.하위패키지명.모듈명
    py -m 루트패키지명.하위패키지명.모듈명
    

    상위/경로/란, 루트패키지가 위치한 컴퓨터 파일시스템상의 상위 경로를 말한다.

  • 파일명으로 메인모듈을 실행하는 경우, 메인모듈은 최상위패키지로 취급하므로 상대경로를 사용한 모든 import문에서 에러가 발생한다.
  • 따라서, 이 경우 import문은 모두 절대경로를 사용하여야 한다.

  • 모듈 옵션으로 메인모듈을 실행하는 방법은 옵션 -m 뒤에 .(닷 연산자)를 사용하여 import문처럼 패키지와 모듈의 이름을 나열하여 실행하는 것이다.
  • 환경변수 PYTHONPATH를 셋팅하여야 파이썬 인터프리터가 루트패키지를 찾을 수 있다.
  • __main__.py 파일

    #터미널에서
    py -m 패키지명  #패키지명/__main__.py가 실행된다.
    

    모듈 옵션으로 메인모듈을 실행할 때 패키지명을 사용하면, 패키지명/ 디렉토리의 __main__.py 파일이 메인모듈로 실행된다.

    환경변수 PYTHONPATH

    파이썬 인터프리터는 sys.path에서 패키지를 검색하여 가져온다.

    sys.path 내에 루트패키지의 경로가 없다면 import문 사용시 에러가 발생한다.

    메인모듈 실행시 터미널의 환경변수 PYTHONPATH를 설정해주면 이 에러를 방지할 수 있다.


  • 디렉토리 루트패키지명/이 위치한 컴퓨터 파일시스템상의 파일경로를 C:/상위/경로/루트패키지명/이라 한다면,
  • #터미널
    set PYTHONPATH=C:/상위/경로              #루트페키지의 상위경로
    py -m 루트패키지명.하위패키지명.메인모듈명  #메인모듈을 실행
    
  • 루트페키지의 상위 경로인 C:/상위/경로/를 환경변수 PYTHONPATH에 셋팅한다.
  • 설정된 PYTHONPATH는 해당 터미널 내에서만 유효하다.
  • 터미널이 종료되면 환경변수가 초기화되므로, 실행시킬 때마다 설정해주어야 한다.
  • 어떤 방법으로 메인모듈을 실행하든지 PYTHONPATH를 설정하는 것이 좋다.
  • 패키지의 상대 경로

    루트패키지명부터 시작하여 모듈에 도달하기까지 하위패키지명.(닷 연산자)로 이어붙이는 것은 패키지의 절대 경로를 이용하는 것이다.

    파이썬은 상대 경로를 사용하여 코드를 가져올 수 있는 방법도 제공한다.

    하지만, 절대 경로를 사용할 것을 추천한다.


  • 패키지의 상대 경로 접근자
    • . : 현재패키지
    • .. : 한단계 상위패키지
    • ... : 두단계 상위패키지
    • 점이 하나씩 늘수록 한단계씩 위로 올라간다.
  • 상대 경로의 기준은 코드를 가져오기 위해 import문을 사용하는 모듈이다.
  • 즉, 각 모듈의 패키지 구조 내의 위치를 기준으로 상대 경로를 따라간다.
  • #예제
    
    #패키지 구조
    #root/
    #    subpack1/
    #        module1.py
    #        module2.py
    #        subpack2/
    #            module3.py
    #    subpack3/
    #        module4.py
    
    #기준: root.subpack1.module1
    #현재모듈: module1 | 현재패키지: subpack1 | 부모패키지: root
    
    #예제1
    from . import module2
    #결과: root.subpack1.module2 => 현재패키지(subpack1)의 다른 모듈(module2)
    
    #예제2
    from .subpack2 import module3
    #결과: root.subpack1.subpack2.module3 => 현재패키지(subpack1)의 하위패키지(subpack2)의 모듈(module3)
    
    #예제3
    from ..subpack3 import module4
    #결과: root.subpack3.module4 => 부모패키지(root)의 하위패키지(subpack3)의 모듈(module4)
    

    예외처리(Exceptions)

    예외처리란, 코드 내에 발생한 에러를 처리하는 방식에 예외를 두는 것을 말한다.

    일반적으로, 코드 내에 에러가 발생하면 파이썬의 실행을 종료시키면서 에러 메세지와 트레이스백을 출력한다.

    하지만, try문을 활용하면 예외적으로 다른 행동을 하도록 할 수 있다.

    try

    try:                                                 #예외처리 대상코드
        실행문1-1                                         #들여쓰기!!!
        실행문1-2
        ...
    except 예외클래스명1 as 변수명1:                       #예외처리할 에러타입
        실행문2-1                                         #변수명1로 에러를 실행문으로 전달
        실행문2-2
    except 예외클래스명2 as 변수명2:                       #여러개의 except 코드블락 가능
        실행문3-1
        실행문3-2
    except (예외클래스명3, 예외클래스명4, ...) as 변수명3:  #여러개의 에러타입을 같은 방식으로 처리
        실행문4-1
        실행문4-2
    ...
    except:                                              #모든 에러와 매칭
        실행문5-1
        실행문5-2
    else:                                                #에러가 발생하지 않았을 때 실행
        실행문6-1
        실행문6-2
    finally:                                             #마지막에 무조건 실행
        실행문7-1
        실행문7-2
    

  • try 코드블락
    • 예외처리 대상코드는 try 코드블락 안의 실행문들이다.
    • 즉, try문은 예외처리 대상코드를 둘러싸듯이 작성한다.

    • 파이썬의 모든 실행문try 코드블락 안의 실행문이 될 수 있다.
    • except 코드블락 안의 실행문을 둘러싸는 또 다른 try문을 위치시켜 다중 try문을 작성하는 경우도 있다.
      #예제(다중 try문)
      try:                     #외부 try문
      
          try:                 #실행문1의 try문
              실행문1           #내부 try 코드블락의 실행문
          except 예외클래스명:
              실행문2           #실행문1의 에러 중 '일부'를 처리하는 실행문
      
          실행문3               #외부 try 코드블락의 실행문
      
      except:
      
          try:                 #실행문4의 try문
              실행문4           #실행문1의 처리되지 못한 에러와 실행문2, 실행문3의 에러를 처리하는 실행문
          except:
              실행문5           #실행문4의 에러를 처리하는 실행문
      

    • try 코드블락 안의 실행문에서 에러가 발생하게 되면, 에러발생 지점에서 실행문의 실행이 중단된다.
    • 즉, 에러발생 지점 이후의 코드들은 실행되지 않고 except 코드블락으로 넘어간다.

  • except 코드블락
    • except 코드블락은 try 코드블락 안에서 발생한 에러를 처리할 예외적인 방법들을 정의한 것이다.
    • except 코드블락은 여러개가 올 수 있다.

    • 에러가 발생하면 그 에러의 예외클래스명과 매칭되는 except 코드블락이 실행된다.
    • 만약, 다수의 매칭이 발생한다면 위에서부터 먼저 매칭되는 코드블락을 실행한다.
    • 예외클래스명이 없는 except:은 모든 에러타입과 매칭되므로 가장 마지막 except 코드블락이 되어야 한다.
    • 한번 매칭이 발생하여 예외처리가 된 에러는 처리가 완료되면 삭제된다.
    • 한번 처리를 한 에러를 외부 try문으로 전달하기 위해선 다시 그 에러를 raise하여야 한다.

    • 매칭이 발생되지 않은 에러는 처리가 되지 않았으므로, 외부 try문이 있다면 그 try문의 except 코드블락에서 다시 매칭을 시도한다.
    • 어떤 try문에서도 발생한 에러를 처리하지 않게되면, 그 에러는 파이썬의 디폴트 에러처리 방법인 종료와 메세지 및 트레이스백을 출력하게 된다.

    • 여러 타입의 에러를 동일한 방법으로 처리한다면, (예외클래스명1, 예외클래스명2, ...)처럼 에러 타입을 튜플로 묶어, 여러가지 에러를 한가지 방법으로 처리할 수 있다.
    • as키워드를 사용하면, 발생한 에러를 변수에 저장하여 except 코드블락 안으로 전달할 수 있다.
    • as키워드를 통해 저장된 에러는 해당 except 코드블락이 끝나는 시점에서 삭제되므로, 해당 코드블락 외부에서 접근할 수 없다.

    • except 코드블락 내에서 발생한 에러는 별도의 try문으로 감싸지 않는 한 예외처리되지 않는다.

  • else 코드블락
    • try 코드블락의 실행문이 에러 없이 모두 실행됐을때, else 코드블락이 실행된다.
    • 단, return문, continue문, break문을 통해 try 코드블락의 실행이 종료된 경우, else 코드블락은 실행되지 않는다.

    • else 코드블락 내에서 발생한 에러는 별도의 try문으로 감싸지 않는 한 예외처리되지 않는다.

  • finally 코드블락
    • try코드블락은 에러 발생 지점에서 실행이 중단되기 때문에 에러가 발생하더라도 반드시 실행되어야 하는 실행문들을 실행할 수 없다.
    • finally 코드블락은 에러가 발생하더라도 반드시 실행되어야 하는 실행문들을 정의한 것이다.

    • try문의 모든 코드블락(try 코드블락, except 코드블락, else 코드블락)이 실행된 이후, 마지막으로 finally 코드블락이 실행된다.
    • finally 코드블락은 에러 발생여부, 종료방식과 상관없이 무조건 실행된다.
    • finally 코드블락은 try문에서 발생한 것들을 정리하는 역할을 한다.
    • 그래서, finally 코드블락을 '클린업' 코드블락이라고도 한다.

    • finally 코드블락 내에서 발생한 에러는 별도의 try문으로 감싸지 않는 한 예외처리되지 않는다.
  • raise

    특정 조건이 충족되면 에러가 발생한 것으로 간주하고, 현재 코드의 실행을 중단시켜야할 때가 있다.

    이때, raise문은 파이썬 인터프리터에게 에러의 발생을 알리는 역할을 한다.

    #단독형
    raise 예외객체
    
    #연결형
    raise 예외객체 from 원인예외명
    
  • 예외객체자리에 예외클래스명을 사용하면 예외클래스명()을 통해 해당 클래스의 인스턴스를 사용한다.
  • 예외객체로 보통 빌트인(built-in) 예외 객체들을 사용하지만, 사용자 정의 예외 클래스의 인스턴스를 사용할 수도 있다.

  • from 원인예외명을 더하여 예외 객체들을 연결시킬 수 있다. 즉, 여러개의 에러를 복합시킬 수 있다.
  • 원인예외명예외객체의 빌트인(built-in) 속성인 __cause__에 저장된다.
  • 연결형은 주로 try문의 except코드블락 안에서 다시 예외를 발생시키는 경우에 주로 사용한다.

  • #예제
    class MyError(Exception):                     #사용자 정의 예외클래스
        pass
    
    try:                                          #외부 try 코드블락
        try:                                      #내부 try 코드블락
            print("시험용 에러 발생을 시작합니다.")
            raise MyError("원인에러")              #에러 발생
        except MyError as e:                      #내부 except 코드블락
            print("에러 발생을 감지하였습니다.")
            raise Exception("연결된 에러") from e  #에러를 외부 try문으로 전달
    except Exception as e:                        #외부 except 코드블락
        print("에러를 처리합니다.")
        print(f"에러: {e} | 원인: {e.__cause__}")  #에러 처리
    

    사용자 정의 예외클래스(User Defined Exception Class)

    예외클래스를 상속받아 나만의 예외클래스를 만들면 좀더 효율적인 예외처리가 가능하다.

    class 예외클래스명(Exception):  #Exception 클래스를 상속
        pass
    
    Advertisement