[내일배움캠프_TIL]2023.03.22_8일차

yell·2023년 3월 22일
1

NBCAMP

목록 보기
9/17

Today

#🔚Python 문법 기초 강의 수강

#🔚Python 문법 심화 강의 수강


오늘공부한 내용📝

  • class 심화

    • init 함수 ;class에 init메소드를 사용할 경우 인스턴스 생성 시 해당 메소드가 실행됨.

      class CookieFrame():
          def __init__(self, name):
              print(f"생성 된 과자의 이름은 {name} 입니다!")
              self.name = name
      
      cookie1 = CookieFrame("cookie1") # 생성 된 과자의 이름은 cookie1 입니다!
      cookie2 = CookieFrame("cookie2") # 생성 된 과자의 이름은 cookie2 입니다!
    • 상속이란?
      : python의 class 상속이란, 클래스를 생성할 때 다른 클래스에 선언된 변수, 메소드 등의 기능들을 가져와 사용할 수 있도록 해주는 기능

      동일한 코드를 여러 클래스에서 조금씩 수정해 사용하거나 모듈에 내장되어 있는 클래스를 변경할 때 주로 사용

      • 부모(parents) 혹은 슈퍼(super) 클래스 ;상속 해주는 클래스
      • 자식(child) 혹은 서브(sub) 클래스 ;상속 받는 클래스
    • 상속 받은 클래스를 기반으로 새로운 클래스 만들기

      class Monster():
          def __init__(self, hp):
              self.hp = hp
              
          def attack(self, damage):
              self.hp -= damage
      
          def status_check(self):
              print(f"monster's hp : {self.hp}")
              
      class FireMonster(Monster):
          def __init__(self, hp):
              self.attribute = "fire"
              # super()를 사용하면 부모 클래스의 코드를 그대로 사용할 수 있다.
              # 해당 코드는 self.hp = hp 코드를 실행시키는 것과 동일
              super().__init__(hp)
          
          # 부모 클래스에 존재하는 status_check 메소드를 overriding 
          def status_check(self):
              print(f"fire monster's hp : {self.hp}")
              
      class IceMonster(Monster):
          def __init__(self, hp):
              self.attribute = "ice"
              super().__init__(hp)
          
          def status_check(self):
              print(f"ice monster's hp : {self.hp}")
              
      fire_monster = FireMonster(hp=100)
      # FireMonster 클래스에는 attack 메소드가 없지만
      # 부모 클래스에서 상속받았기 때문에 별도의 선언 없이 사용 가능
      fire_monster.attack(20)
      fire_monster.status_check()
      
      ice_monster = IceMonster(hp=200)
      ice_monster.attack(50)
      ice_monster.status_check()
    • 상속 받은 클래스의 특정 코드를 변경해 사용하기

      class Calc:
          def _print_zero_division_error(self):
              print("can't be division by zero")
              
          def plus(self, num1, num2):
              ...
      
          def minus(self, num1, num2):
              ...
      
          def divide(self, num1, num2):
              if num2 == 0:
                  self._print_zero_division_error()
                  return False
              ...
      
          def multiply(self, num1, num2):
              ...
      
      calc = Calc()
      calc.divide(5, 0)
      # result print
      """
      can't be division by zero
      """
      # print를 영어가 아닌 한글로 하고 싶을 때, 상속을 활용하여 별로의 생성이나 변경없이 원하는 코드를 수정
      class CustomCalc(Calc):
          def _print_zero_division_error(self):
              print("0으로는 나눌 수 없습니다.")
      
      calc = CustomCalc()
      calc.divide(5, 0)
      """
      0으로는 나눌 수 없습니다.
      """
  • class 객체(object) 다루기

    • 객체란?
      : 객체와 인스턴스는 동일한 용어이며, CookieFrame 클래스를 사용해 생성된 cookie를 “객체” 혹은 “CookieFrame의 인스턴스”라고 표현

    • 객체를 사용하는 방법

      sample_list = [1, 2, 3, 4]
      sample_dict = {"key": "value"}
      
      print(type(sample_list)) # <class 'list'>
      print(type(sample_dict)) # <class 'dict'>
      
      sample_list.sort() # list 클래스의 sort 메소드 사용
    • datetime 모듈에서 객체 활용해보기

      from datetime import datetime
      
      now = datetime.now() # 현재 시간이 담긴 datetime의 객체(object) 생성
      print(type(now)) # <class 'datetime.datetime'>
  • 정규표현식(regex)
    : 정규표현식은 regular expression의 약자인 regex라고도 하며 문자열이 특정 패턴과 일치하는지 판단하는 형식 언어

    • 정규표현식 예제

            # 정규표현식 없이 이메일 검증하기
            from pprint import pprint
            
            alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
            number = "0123456789"
            special_char = "-_."
            
            def verify_email(email):
                # 이메일에 @가 한개 포함되어 있는지 확인
                if email.count("@") != 1:
                    return False
                
                # @를 기준으로 사용자명과 도메인을 분리
                username, domain = email.split("@")
                
                # username이 1자 이상인지 확인
                if len(username) < 1:
                    return False
                
                # 도메인에 한개 이상의 .이 포함되어 있는지 확인
                if domain.count(".") < 1:
                    return False
                
                # username에 알파벳, 숫자, 허용된 특수문자 이외의 문자가 포함되어 있는지 확인
                if not all([x in alphabet + number + special_char for x in username]):
                    return False
                
                # domain에 알파벳, 숫자, 허용된 특수문자 이외의 문자가 포함되어 있는지 확인
                if not all([x in alphabet + number + special_char for x in domain]):
                    return False
                
                # 마지막 .을 기준으로 도메인을 분리
                _, last_level_domain = domain.rsplit(".", 1)
                
                # 마지막 레벨의 도메인의 길이가 2~4글자인지 확인
                if not 2 <= len(last_level_domain) <= 4:
                    return False
                
                # 모든 검증이 완료되면 True를 리턴
                return True
            
            test_case = [
                "apple",              # False
                "sparta@regex",       # False
                "$parta@regex.com",   # False
                "sparta@re&ex.com",   # False
                "sparta@regex.com",   # True
                "sparta@regex.co.kr", # True
                "sparta@regex.c",     # False
                "sparta@regex.cooom", # False
                "@regex.com",         # False
            ]
            
            result = [{x: verify_email(x)} for x in test_case]
            
            pprint(result)
            
            # 정규표현식을 사용해  이메일 검증하기
            from pprint import pprint
            import re
            
            # rstring : backslash(\)를 문자 그대로 표현
            # ^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$ : 이메일 검증을 위한 정규표현식 코드
            email_regex = re.compile(r"^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$")
            
            def verify_email(email):
                return bool(email_regex.fullmatch(email))
                
            test_case = [
                "apple",              # False
                "sparta@regex",       # False
                "$parta@regex.com",   # False
                "sparta@re&ex.com",   # False
                "spar_-ta@regex.com", # True
                "sparta@regex.co.kr", # True
                "sparta@regex.c",     # False
                "sparta@regex.cooom", # False
                "@regex.com",         # False
            ]
            
            result = [{x: verify_email(x)} for x in test_case]
            
            pprint(result)
    • 정규표현식 코드를 짜는 방법
      : 정규표현식으로 내가 원하는 패턴의 코드를 직접 짜는 것은 매우 어려워, 이미 만들어져 있고, 검증 된 정규표현식을 가져다가 사용하는 것을 권장.
      참고) https://regexr.com/

  • 파일과 디렉토리 다루기

    • glob을 활용한 파일 및 디렉토리 목록 확인

      from pprint import pprint
      import glob
      
      # ./는 현재 python 파일이 위치한 경로를 의미
      # *은 "모든 문자가 일치한다" 라는 의미
      # ./venv/*은 venv 폴더 내 모든 파일들을 의미
      path = glob.glob("./venv/*")
      pprint(path)
      
      # result output
      """
      ['./venv\\Include', './venv\\Lib', './venv\\pyvenv.cfg', './venv\\Scripts']
      """
      
      # **은 해당 경로 하위 모든 파일을 의미하며, recursive 플래그와 같이 사용
      # recursive를 True로 설정하면 디렉토리 내부의 파일들을 재귀적으로 탐색
      path = glob.glob("./venv/**", recursive=True)
      pprint(path)
      
      # result output
      """
      ['./venv\\',
       './venv\\Include',
       './venv\\Lib',
       './venv\\Lib\\site-packages',
       './venv\\Lib\\site-packages\\autopep8-2.0.1.dist-info',
       ...
      ]
      """
      
      # *.py와 같이 작성 시 특정 확장자를 가진 파일들만 볼 수 있다.
      # ./venv/**/*.py는 venv 하위 모든 폴더들을 재귀적으로 탐색하며 .py 확장자 파일을 탐색
      path = glob.glob("./venv/**/*.py", recursive=True)
      pprint(path)
      
      # result output
      """
      ['./venv\\Lib\\site-packages\\autopep8.py',
       './venv\\Lib\\site-packages\\pycodestyle.py',
       './venv\\Lib\\site-packages\\pip\\__init__.py',
       './venv\\Lib\\site-packages\\pip\\__main__.py',
       './venv\\Lib\\site-packages\\pip\\__pip-runner__.py',
       ...
      ]
      """
    • open을 활용한 파일 다루기
      : python에서는 파일을 편집하거나 생성할 때, with open 문법을 사용할 수 있다.

      # "file.txt" : 파이썬에서 사용할 파일을 지정
      # "w" : 파일을 쓰기 모드로 열거나 만약 파일이 없다면 새로 생성
      # r, a, 등 다양한 mode가 존재 
      # encoding : 파일의 encoding 형식을 지정
      
      # case 1. open 함수를 사용해 파일 열기
      f = open("file.txt", "w", encoding="utf-8")
      f.write("파이썬 파일 쓰기 테스트!\n")
      
      # open 함수를 실행하면 python 스크립트가 끝날때 까지 파일이 열려있다.
      # 때문에 파일에 대한 작업이 끝나면 close()를 사용해 파일을 닫아줘야 한다.
      f.close()
      
      # open을 with와 같이 사용하면 with 구문이 끝날 때 자동으로 파일이 close됨.
      # 때문에 with를 사용할 떄는 별도로 close 해주지 않아도 됨.
      # a 모드는 기존 내용을 유지한 상태로 추가
      with open("file.txt", "a", encoding="utf-8") as w:
          w.write("파이썬 내용 추가 테스트!")
      
      # r 모드는 파일 읽기 모드
      with open("file.txt", "r", encoding="utf-8") as r:
          # readlines는 파일의 모든 내용을 list 자료형으로 한번에 읽어들임.
          print(r.readlines())
      
      # result output
      """
      ['파이썬 파일 쓰기 테스트!파이썬 내용 추가 테스트!']
      """
      
      with open("file.txt", "r", encoding="utf-8") as r:
          while True:
              # readline은 파일을 한 줄 씩 읽어옴.
              line = r.readline()
      
              # 파일 끝까지 텍스트를 읽어들였다면 반복문을 중지
              if not line:
                  break
      
              # 텍스트의 줄바꿈 문자 제거
              line = line.strip()
              print(line)
      
      # result output
      """
      파이썬 파일 쓰기 테스트!
      파이썬 내용 추가 테스트!
      """

      참고) 더 많은 mode의 종류

  • itertools
    : 효율적인 루핑을 위한 이터레이터를 만드는 함수
    참고) 더 많은 이터레이터의 기능들

    • 데카르트곱 구하기

      from itertools import product
      
      sample1 = ["A", "B", "C", "D", "E"]
      sample2 = [1, 2, 3, 4]
      
      # 행 / 열을 구분하여 프린트 하기 위해 enumerate 사용
      for i, v in enumerate(product(sample1, sample2), 1):
          print(v, end=" ")
          if i % len(sample2) == 0:
              print("")
      
      # result output
      """
      ('A', 1) ('A', 2) ('A', 3) ('A', 4) 
      ('B', 1) ('B', 2) ('B', 3) ('B', 4) 
      ('C', 1) ('C', 2) ('C', 3) ('C', 4) 
      ('D', 1) ('D', 2) ('D', 3) ('D', 4) 
      ('E', 1) ('E', 2) ('E', 3) ('E', 4) 
      """
    • 원소의 개수가 n개인 순열

      from itertools import permutations
      
      sample = ["A", "B", "C"]
      
      # 원소의 개수가 3개인 순열 출력
      for i in permutations(sample, 3):
          print(i)
      
      # result output
      """
      ('A', 'B', 'C')
      ('A', 'C', 'B')
      ('B', 'A', 'C')
      ('B', 'C', 'A')
      ('C', 'A', 'B')
      ('C', 'B', 'A')
      """
    • 원소의 개수가 n개인 조합 구하기

      from itertools import combinations
      
      sample = ["A", "B", "C"]
      
      # 원소의 개수가 2개인 조합 출력
      for i in combinations(sample, 2):
          print(i)
      
      # result output
      """
      ('A', 'B')
      ('A', 'C')
      ('B', 'C')
      """
    • 원소의 개수가 n개인 조합 구하기(중복 허용)

      from itertools import combinations_with_replacement
      
      sample = ["A", "B", "C"]
      
      # 중복을 포함한 원소의 개수가 3개인 조합 출력
      for i in combinations_with_replacement(sample, 3):
          print(i)
      
      # result output
      """
      ('A', 'A', 'A')
      ('A', 'A', 'B')
      ('A', 'A', 'C')
      ('A', 'B', 'B')
      ('A', 'B', 'C')
      ('A', 'C', 'C')
      ('B', 'B', 'B')
      ('B', 'B', 'C')
      ('B', 'C', 'C')
      ('C', 'C', 'C')
      """
  • requests
    : 파이썬에서 http 통신을 가능하게 해주는 모듈로, beautifulsoup과 함께 웹 크롤링을 하거나 api 통신이 필요할 때 사용

    • requests 요청에는 크게 네가지 종류의 method가 존재

      • GET : 데이터 정보 요청
      • POST : 데이터 생성 요청
      • PUT : 데이터 수정 요청
      • DELETE : 데이터 삭제 요청
    • requests를 요청하면 서버에서는 응답(response)을 내려주며, 응답은 내용(content)과 상태 코드(status code)를 받아온다. content는 서버에서 사용자에게 주는 응답 본문이며, status는 서버가 어떤 상태인지를 표현
      참고) 상태 코드 정보

      • 자주 사용되는 상태 코드 정보
        - 2xx - 성공
        - 200 : 정상 통신 완료
        - 201 : 정상 생성 완료
        - …
        - 3xx : 페이지 리다이렉션
        - 301 : url 변경
        - …
        - 4xx : 클라이언트 오류
        - 400 : 클라이언트가 잘못 된 요청을 보냄
        - 401 : 인증되지 않은 사용자
        - 403 : 액세스 권한이 없음
        - …
        - 5xx : 서버 오류
        - 500 : 서버에서 처리할 수 없음
        - 502 : 게이트웨이에서 잘못된 응답을 받음
        - …
        사이트에 접속하다 보면 한번씩 보이는 에러에서 502가 status code를 의미
    • requests 모듈로 request 보내보기

            # get 요청 테스트코드
            import requests
            from pprint import pprint
            
            # 통신 할 base url 지정
            url = "https://jsonplaceholder.typicode.com/"
            
            # 1번 사용자 정보를 받아오기 위해 users/1 경로에 get 요청
            r = requests.get(f"{url}users/1")
            
            pprint({
                "contents": r.text,
                "status_code": r.status_code,
            })
            
            # result output
            """
            {'contents': '{\n'
                         '  "id": 1,\n'
                         '  "name": "Leanne Graham",\n'
                         '  "username": "Bret",\n'
                         '  "email": "Sincere@april.biz",\n'
                         '  "address": {\n'
                         '    "street": "Kulas Light",\n'
                         '    "suite": "Apt. 556",\n'
                         '    "city": "Gwenborough",\n'
                         '    "zipcode": "92998-3874",\n'
                         '    "geo": {\n'
                         '      "lat": "-37.3159",\n'
                         '      "lng": "81.1496"\n'
                         '    }\n'
                         '  },\n'
                         '  "phone": "1-770-736-8031 x56442",\n'
                         '  "website": "hildegard.org",\n'
                         '  "company": {\n'
                         '    "name": "Romaguera-Crona",\n'
                         '    "catchPhrase": "Multi-layered client-server neural-net",\n'
                         '    "bs": "harness real-time e-markets"\n'
                         '  }\n'
                         '}',
             'status_code': 200}
            """
            
            # post 요청 테스트코드
            import requests
            from pprint import pprint
            
            # 통신 할 base url 지정
            url = "https://jsonplaceholder.typicode.com/"
            
            # 데이터 생성에 사용될 값 지정
            data = {
                "name": "sparta",
                "email": "sparta@test.com",
                "phone": "010-0000-0000",
            }
            
            # 사용자를 생성하기 위해 users 경로에 data를 담아 post 요청
            r = requests.post(f"{url}users", data=data)
            
            pprint({
                "contents": r.text,
                "status_code": r.status_code,
            })
            
            # result output
            """
            {'contents': '{\n'
                         '  "name": "sparta",\n'
                         '  "email": "sparta@test.com",\n'
                         '  "phone": "010-0000-0000",\n'
                         '  "id": 11\n'
                         '}',
             'status_code': 201}
            """
  • json 다루기

    • json이란?

      • javascript Object Notation의 약자로 데이터를 저장하거나 데이터 통신을 할 때 주로 사용
      • json을 파일로 다룰 때는 .json 확장자를 사용
      • json의 형태는 key: value 쌍으로 이루어져 있으며, 파이썬의 dictionary 형태와 매우 유사.
      • 이러한 특성으로 인해 파이썬에서는 json 데이터를 dictionary 데이터로 변경하고, 반대로 dictionary 데이터를 json으로 변경할 수 있다.
    • python에서 json 형태 다뤄보기

      # json 모듈을 사용하기 위해 import 
      import json
      import requests
      
      # 해당 사이트는 요청에 대한 응답을 json 형태의 문자열로 
      url = "https://jsonplaceholder.typicode.com/"
      
      r = requests.get(f"{url}users/1")
      print(type(r.text))  # <class 'str'>
      
      # 문자열 형태의 json을 dictionary 자료형으로 변경
      response_content = json.loads(r.text)
      print(type(response_content))  # <class 'dict'>
      
      # dictionary 자료형이기 때문에 key를 사용해 value를 확인할 수 있다.
      print(f"사용자 이름은 {response_content['name']} 입니다.")
      
      # result output
      """
      사용자 이름은 Leanne Graham 입니다.
      """
  • csv 파일
    : csv는 comma-separated values의 약자로 텍스트에 쉼표( , )를 사용해 필드를 구분하며 .csv 확장자를 사용. 쉼표를 사용해 데이터를 구분한다는 특성 덕분에 텍스트 편집기를 사용해 간단한 csv 파일을 만드는 것도 가능

    • csv 파일 읽기

      # 파이썬에서 csv 파일을 다루기 위해 모듈 import
      import csv
      
      csv_path = "sample.csv"
      
      # csv를 list 자료형으로 읽기
      csv_file = open(csv_path, "r", encoding="utf-8")
      csv_data = csv.reader(csv_file)
      for i in csv_data:
          print(i)
      
      # 작업이 끝난 csv 파일을 닫아준다.
      csv_file.close()
      
      # result output
      """
      ['email', 'birthyear', 'name', 'Location']
      ['laura@example.com', '1996', 'Laura Grey', 'Manchester']
      ['craig@example.com', '1989', 'Craig Johnson', 'London']
      ['mary@example.com', '1997', 'Mary Jenkins', 'London']
      ['jamie@example.com', '1987', 'Jamie Smith', 'Manchester']
      ['john@example.com', '1998', 'John', 'Manchester']
      """
      
      # csv를 dict 자료형으로 읽기
      csv_file = open(csv_path, "r", encoding="utf-8")
      csv_data = csv.DictReader(csv_file)
      
      for i in csv_data:
          print(i)
      
      csv_file.close()
      
      # result output
      """
      {'email': 'laura@example.com', 'birthyear': '1996', 'name': 'Laura Grey', 'Location': 'Manchester'}
      {'email': 'craig@example.com', 'birthyear': '1989', 'name': 'Craig Johnson', 'Location': 'London'}
      {'email': 'mary@example.com', 'birthyear': '1997', 'name': 'Mary Jenkins', 'Location': 'London'}
      {'email': 'jamie@example.com', 'birthyear': '1987', 'name': 'Jamie Smith', 'Location': 'Manchester'}
      {'email': 'john@example.com', 'birthyear': '1998', 'name': 'John', 'Location': 'Manchester'}
      """
    • csv 파일 쓰기

      # 파이썬에서 csv 파일을 다루기 위해 모듈 import
      import csv
      
      csv_path = "sample.csv"
      
      # csv 파일을 쓸 때는 newline='' 옵션을 줘서 중간에 공백 라인이 생기는 것을 방지합니다.
      csv_file = open(csv_path, "a", encoding="utf-8", newline='')
      csv_writer = csv.writer(csv_file)
      
      # csv에 데이터를 추가
      csv_writer.writerow(["lee@sparta.com", '1989', "lee", "Seoul"])
      
      csv_file.close()
      
      csv_file = open(csv_path, "r", encoding="utf-8")
      csv_data = csv.reader(csv_file)
      for i in csv_data:
          print(i)
      
      csv_file.close()
      
      # result output
      """
      ...
      ['lee@sparta.com', '1989', 'lee', 'Seoul'] # 추가 된 행
      """
  • 데코레이터(decorator)
    : 이름 그대로 파이썬의 함수를 장식해주는 역할. 선언되는 함수 위에 골벵이를 사용해 @decorator 형태로 작성하며 해당 함수가 실행될 때 데코레이터에서 선언 된 코드가 같이 실행됨.
    • 데코레이터 코드 구조 이해하기

         # 데코레이터는 호출 할 함수를 인자로 받도록 선언
         def decorator(func):
             # 호출 할 함수를 감싸는 wrapper 함수를 선언
             def wrapper():
                 # func.__name__ ;데코레이터를 호출 한 함수의 이름
                 print(f"{func.__name__} 함수에서 데코레이터 호출")
                 func()
                 print(f"{func.__name__} 함수에서 데코레이터 끝")
         
             # wrapper 함수를 리턴
             return wrapper
             ```
         
         선언되는 함수 위에 @decorator를 추가해 데코레이터를 사용할 수 있습니다.
         
         ```python
         @decorator
         def decorator_func():
             print("decorator_func 함수 호출")
         
         decorator_func()
         
         # result output
         """
         decorator_func 함수에서 데코레이터 호출
         decorator_func 함수 호출
         decorator_func 함수에서 데코레이터 끝
         """
    • 데코레이터 예제

      # 특정 함수의 실행 시간 구하기
      import time
      import random
      
      def time_checker(func):
          def wrapper():
              # 함수가 실행될 때 시간을 저장
              start_time = time.time()
      
              # 함수 실행
              func()
      
              # 함수가 종료된 후 시간에 실행될 때 시간을 빼 실행 시간을 구한다.
              executed_time = time.time() - start_time
      
              # 실행 시간을 소수점 5자리까지만 출력
              print(f"{func.__name__} 함수의 실행시간 : {executed_time:.05f}s")
      
          return wrapper
      
      @time_checker
      def main():
          # 함수의 실행 시간을 테스트하기 위해 0.1초 ~ 1초간 sleep 
          time.sleep(random.randint(1, 10) / 10)
      
      for i in range(10):
          main()
      
      # result output
      """
      main 함수의 실행시간 : 0.80095s
      main 함수의 실행시간 : 0.90009s
      main 함수의 실행시간 : 1.00027s
      main 함수의 실행시간 : 0.20020s
      main 함수의 실행시간 : 0.90011s
      main 함수의 실행시간 : 0.60041s
      main 함수의 실행시간 : 0.30027s
      main 함수의 실행시간 : 0.40024s
      main 함수의 실행시간 : 0.10026s
      main 함수의 실행시간 : 0.50032s
      """
    • 인자가 있는 함수의 데코레이터 예제

      # 입력받은 인자에 2를 곱해주기
      def double_number(func):
          def wrapper(a, b):
              # 함수에서 받은 인자에 곱하기 2
              double_a = a * 2
              double_b = b * 2
      
              return func(double_a, double_b)
      
          return wrapper
      
      @double_number
      def double_number_add(a, b):
          return a + b
      
      def add(a, b):
          return a + b
      
      print(double_number_add(5, 10))
      print(add(5, 10))
      
      # result output
      """
      30
      15
      """
profile
...

0개의 댓글