ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 파이썬 문법 심화
    Python 2024. 6. 30. 07:54

     

    자주 사용되는 모듈 및 패턴

     

    1. type()

    integer = 10
    float_ = 1.23
    string = "hello world!!"
    list_ = [1, 2, 3]
    tuple_ = (1, 2, 3)
    set_ = {1, 2, 3}
    dictionary = {"key": "value"}
    boolean = True
    
    print(type(integer)) # <class 'int'>
    print(type(float_)) # <class 'float'>
    print(type(string)) # <class 'str'>
    print(type(list_)) # <class 'list'>
    print(type(tuple_)) # <class 'tuple'>
    print(type(set_)) # <class 'set'>
    print(type(dictionary)) # <class 'dict'>
    print(type(boolean)) # <class 'bool'>

     

    a = 1

    b = '1' 

     

    이럴 경우 숫자 1인지 문자 1인지 알 수 없는데 이때 type() 함수를 쓰면 알 수 있다.

    a = 1
    b = "1"
    
    print(a, type(a))
    print(b, type(b))

     

    이러면 

    1 <class 'int'>
    1 <class 'str'>

     

    첫번째는 숫자 1, 두번째는 문자 1 이다 이렇게 알기쉽게 알려준다.


     

    split(), join(), repalce()

     

    split() 괄호 안에 쓴 값을 기준으로 문자열을 쪼개고,

    string = "hello/python/world!!"
    string_list = string.split("/") # split() 안에 들어간 값을 기준으로 문자를 나눈다.
    
    print(string_list) # ['hello', 'python', 'world!!']

     

    " ".join()을 사용하여 구분하고 싶은 값으로 문자열을 만들고

    # join은 "사이에 들어갈 문자".join(리스트)로 구성
    
    string_list = ["hello", "python", "world"]
    string = "!! ".join(string_list)
    
    print(string) # hello!! python!! world

     

    replace()를 사용하여 바꾸고자 하는 문자를 원하는 문자로 바꾸면 된다.

    # replace는 "변경할 문자".replace("변경 전 문자", "변경 후 문자")로 구성
    
    before_string = "hello world!!!"
    after_string = before_string.replace("!", "~") # !를 ~로 변경
    
    print(after_string) # hello world~~~

     

     


     

    pprint

     

    말그대로 pretty print라는 뜻으로ㅋㅋ 예쁘게 출력해주는 기능이다. 

     

    일단, from pprint import pprint 해줘야한다.

    from pprint import pprint
    
    sample_data = {
        "id": "0001",
        "type": "donut",
        "name": "Cake",
        "ppu": 0.55,
        "batters":
            {
                "batter":
                    [
                        {"id": "1001", "type": "Regular"},
                        {"id": "1002", "type": "Chocolate"},
                        {"id": "1003", "type": "Blueberry"},
                        {"id": "1004", "type": "Devil's Food"}
                    ]
            },
        "topping":
            [
                {"id": "5001", "type": "None"},
                {"id": "5002", "type": "Glazed"},
                {"id": "5005", "type": "Sugar"},
                {"id": "5007", "type": "Powdered Sugar"},
                {"id": "5006", "type": "Chocolate with Sprinkles"},
                {"id": "5003", "type": "Chocolate"},
                {"id": "5004", "type": "Maple"}
            ]
    }
    
    print(sample_data)
    pprint(sample_data)

     

    이런식의 복잡한 코드가 있다고 했을때, 그냥 print로 출력하면 

    {'id': '0001', 'type': 'donut', 'name': 'Cake', 'ppu': 0.55, 'batters': {'batter': [{'id': '1001', 'type': 'Regular'}, {'id': '1002', 'type': 'Chocolate'}, {'id': '1003', 'type': 'Blueberry'}, {'id': '1004', 'type': "Devil's Food"}]}, 'topping': [{'id': '5001', 'type': 'None'}, {'id': '5002', 'type': 'Glazed'}, {'id': '5005', 'type': 'Sugar'}, {'id': '5007', 'type': 'Powdered Sugar'}, {'id': '5006', 'type': 'Chocolate with Sprinkles'}, {'id': '5003', 'type': 'Chocolate'}, {'id': '5004', 'type': 'Maple'}]}

     

    이렇게 한줄로 나오는데 가독성이 떨어진다.

     

    pprint로 출력하면 데이터마다 개행도 시켜주고 보기 좋게 예쁘게 나온다.

    {'batters': {'batter': [{'id': '1001', 'type': 'Regular'},
                            {'id': '1002', 'type': 'Chocolate'},
                            {'id': '1003', 'type': 'Blueberry'},
                            {'id': '1004', 'type': "Devil's Food"}]},
     'id': '0001',
     'name': 'Cake',
     'ppu': 0.55,
     'topping': [{'id': '5001', 'type': 'None'},
                 {'id': '5002', 'type': 'Glazed'},
                 {'id': '5005', 'type': 'Sugar'},
                 {'id': '5007', 'type': 'Powdered Sugar'},
                 {'id': '5006', 'type': 'Chocolate with Sprinkles'},
                 {'id': '5003', 'type': 'Chocolate'},
                 {'id': '5004', 'type': 'Maple'}],
     'type': 'donut'}

     

     


     

    random

     

    말그대로 임의의 숫자를 생성하거나 무작위로 섞거나 할 때 쓰는 모듈

    import random
    
    numbers = [1, 2, 3, 4, 5, 6, 7, 8]
    random.shuffle(numbers) # numbers를 무작위하게 섞기
    print(numbers) # [2, 8, 6, 4, 3, 7, 1, 5]
    
    random_number = random.randint(1, 10) # 1 ~ 10 사이의 무작위 번호 생성
    print(random_number) # 4

     

     

    로또번호 추첨 프로그램을 만들거나 리스트 안에 있는 요소를 랜덤하게 골라서 보여줄 때 쓰면 됨


     

    time

    import time
    
    start_time = time.time() # 현재 시간 저장
    
    time.sleep(1) # 1초간 대기
    
    end_time = time.time()
    
    # 코드가 종료된 시간 - 코드가 시작된 시간으로 실행 시간 구하기 (단위 : 초)
    print(f"코드 실행 시간 : {end_time-start_time:.5f}") # 코드 실행 시간 : 1.00100

     

    파이썬 코드 안에서 시간을 다뤄야할 때 쓴다.

    (.5f 는 소숫점 5자리까지 나타낸다 라는 뜻)


     

    datetime

     

    현재 날짜 및 시간을 출력하려면 이렇게 하면 하면 되는데

    from datetime import datetime
    
    now = datetime.now()
    print(now)

     

    그럼 이렇게 출력된다.

    2024-06-29 19:24:04.087131

     

     

    만약 이걸 날짜와 시간으로 구분하고 싶어서 split(" ") 공백으로 자르게 되면?

    from datetime import datetime
    
    now = datetime.now().split(" ")
    print(now)

     

    그럼 이런 오류가 뜬다.

    AttributeError: 'datetime.datetime' object has no attribute 'split' 

     

    출력됐던 datetime이 string이 아니기 때문이다.

    string으로 바꿔서 split으로 쪼개서 출력하면 리스트 형태로 잘 나눠진다. 그럼 [0]은 날짜 [1]은 시간으로 구분하면 된다.

    from datetime import datetime
    
    now = str(datetime.now()).split(" ")
    print(now) #['2024-06-29', '19:31:12.968277']

     

     

    그래서 이때, strptime, strftime을 사용하면 손쉽게 string을 datetime 날짜로, datetime 날짜를 string으로 바꿀 수 있다.

    from datetime import datetime, timedelta
    
    # 현재 날짜 및 시간 출력
    print(datetime.now()) # 2023-02-22 15:55:32.277095
    
    # datetime의 format code 
    %y : 두 자리 연도 / 20, 21, 22
    %Y : 네 자리 연도 / 2020, 2021, 2022
    %m : 두 자리 월 / 01, 02 ... 11 ,12
    %d : 두 자리 일 / 01, 02 ...  30, 31
    %I : 12시간제 시간 / 01, 02 ... 12
    %H : 24시간제의 시간 / 00, 01 ... 23
    %M : 두 자리 분 / 00, 01 ... 58, 59
    %S : 두 자리 초 / 00, 01 ... 58, 59
    
    # string을 datetime 날짜로 변경하기
    string_datetime = "23/12/25 13:20"
    datetime_ = datetime.strptime(string_datetime, "%y/%m/%d %H:%M")
    print(datetime_) # 2023-12-25 13:20:00
    
    # datetime 날짜를 string으로 변환하기
    now = datetime.now()
    string_datetime = datetime.strftime(now, "%y/%m/%d %H:%M:%S")
    print(string_datetime) # 22/09/04 04:04
    
    # 3일 전 날짜 구하기
    three_days_ago = datetime.now() - timedelta(days=3)
    print(three_days_ago) # 2023-02-19 16:27:52.526502

     

    timedelta는 - , + 를 써서 3일 전 또는 3일 후 날짜를 구할 수 있다.

     


     

    조건문 심화

     

    값이 일치 ==

    "a" == "a" # True
    "a" == "b" # False
    1 == "1" # False, 값은 동일하지만 자료형이 다르기 때문

     

    세번째 줄에서처럼 1, "1" 이렇게 값이 똑같더라도 자료형이 다르면 if문을 통과하지 못해서 false가 나오기때문에 주의해야한다.

     

     

    값이 일치하지 않음 !=

    0 != 1 # True
    0 != 0 # False

     

     

    값이 큰지 작은지  >, <

    5 > 2 # True
    1 < 0 # False
    1 > 1 # False

     

     

    값이 크거나 같은지, 작거나 같은지 >=, <=

    1 >= 1 # True

     

     

    특정 값이 list / tuple / set에 포함되어 있는지 확인 > in

    4 in [1, 2, 3] # False
    1 in (1, 2, 3) # True

     


     

    특정 비교 결과 혹은 값이 True 혹은 False일 경우 실행 될 로직

    if condition: # 조건이 True일 경우
        # some code
    
    # not 키워드를 사용할 경우 조건이 False일 때 실행된다
    elif not condition: # 조건이 False일 경우
        # some code
    
    else: # 위 조건들 중 만족하는게 없을 경우
        # some code

     

     

    and, or을 사용해 2개 이상의 조건을 복합적으로 사용할 수도 있다.

    if condition1 and condition2: # 두 조건을 모두 만족할 경우
        # some code
    
    elif condition or condition: # 두 조건 중 하나라도 만족할 경우
        # some code
    
    else: 
        # some code

     

     

    또한 아래와 같이 and 와 or 을 여러개 써서 if 문을 만들 수 있고, 괄호()를 사용해서 우선순위를 잡아줄 수 있다.

    if (True or False) and True and True:
        print("Pass!")

     


     

    비어있는 string, list 등은 분기문에서 False로 판단한다.

    empty_string = ""
    empty_list = []
    
    if not empty_string:
        print("string is empty!!")
    
    if not empty_list:
        print("list is empty!!")

     

    if not 은 False일때 True인데, 비어있는 string, list는 False니까 위 코드를 실행하면 정상적으로 

    string is empty!!

    list is empty!!

    라는 값이 출력된다.

     

     

    특정 값이 True인지 False인지는 bool() 함수를 사용해 확인할 수 있다.

    print(bool(""))
    print(bool(0))
    print(bool([]))
    
    print(bool("sample"))
    print(bool([1, 2]))
    print(bool(1))
    print(bool(-1)) # 0이 아닌 숫자는 True로 판단
    
    # sample result
    """
    False
    False
    False
    
    True
    True
    True
    True
    """

     

    예를들어 [""] 이건 빈 리스트일까 아닐까? 앞에 불을 붙여보면 확인할 수 있다.

    print(bool([""]))

     

    출력해보면 이렇게 True가 나온다. 

    True

     

    ""은 빈 스트링이지만, [""] 얘는 빈 스트링이라는 값을 가지고 있는 list이므로 True가 출력된 것.


     

    all(), any() 함수를 사용해 여러 값들에 대한 조건을 판단할 수 있다.

     

    all()모두 True일 때 True값을 리턴하고

    any()는 값 중 하나라도 True가 있으면 True값을 리턴한다.

     

    그래서 아래 코드를 실행하면

    if all([True, True, True, False, True]):
        print("1.통과")
    
    if any([False, False, False, True, False]):
        print("2.통과")

     

    이렇게 2.통과 만 출력된다.

    2.통과

     


     

    함수의 인자와 리턴타입

     

    파이썬의 함수들은 비슷해보여도 사용방법이나 리턴타입이 다르므로 해당 기능의 결과물이 어떤 데이터를 리턴해주는지 알아야 한다.

     

    예를들어,

    sort()는 단순히 정렬만 해주는 기능을 하는 함수이므로 따로 변수를 지정해주지 않아도 된다.

    # sort
    sample_list = [3, 2, 4, 1, 5]
    sample_list.sort() # return data 없이 list 자체를 정렬
    
    print(sample_list) # [1, 2, 3, 4, 5]

     

     

    sorted는 정렬과 동시에 정렬된 리스트를 리턴해주기 때문에 변수에 따로 담아줘야한다.

    # sorted
    sample_list = [3, 2, 4, 1, 5]
    sorted_list = sorted(sample_list) # 정렬 된 list를 return
    
    print(sorted_list) # [1, 2, 3, 4, 5]

     

     

    이렇게 따로 변수를 지정해주면 sorted(sample_list) 를 써야한다. .sort() 를 쓰면 None이 출력된다.

    # 잘못된 방법
    sample_list = [3, 2, 4, 1, 5]
    sorted_list = sample_list.sort() # .sort()의 return data는 None 입니다.
    
    print(sorted_list) # None

     

     

    함수의 리턴타입을 알아보는 방법은

    docstring 확인하는 방법과 외부 라이브러리를 import 해서 사용할 때 구현부의 코드를 보고 사용 방법을 익히는 방법이 있다.

     


     

    try / exception을 활용한 에러 처리

     

    except를 여러개 쓰고 뒤에 에러 종류를 써줘서, 발생하는 에러에 따라 어떤 코드를 실행시킬지를 정해줄 수 있다.

    number = input(0)
    
    try:
        int(number)
        10 / number
    
    except ValueError:  # int로 변환하는 과정에서 에러가 발생했을 떄
        print(f"{number}은(는) 숫자가 아닙니다.")
    
    except ZeroDivisionError:  # 0으로 나누면서 에러가 발생했을 때
        print("0으로는 나눌수 없습니다.")
    
    except Exception as e:  # 위에서 정의하지 않은 에러가 발생했을 때(권장하지 않음)
        print(f"예상하지 못한 에러가 발생했습니다. error : {e}")

     

    number = "a" 를 입력하면,

    문자열 a는 숫자로 바꿀 수 없으니까 ValueError로 빠지고

     

    number = 0 을 입력하면,

    0으로는 나눌 수 없다는 ZeroDivisionError 로 빠지고 

     

    number = "0" 을 입력하면,

    try에서 int(number)를 해주긴하지만 실질적으로 10 / number 를 실행할때는 문자열 "0"인 상태이기 때문에 에러가 발생한다. 즉 ,이 경우는 밸류에러도 아니고 제로디비전에러도 아니니까  마지막 경우인 Exception 으로 빠진다.

    if문의 else처럼 정의되지 않은 모든 에러에 대해 Exception구문으로 빠지도록 처리되지만 너무 남발하면 어떤 에러가 발생했는지 추적이 어려워진다. 그렇기때문에 ValueError, ZeroDivisionError 처럼 어떤 에러가 발생했을때 어떤 처리를 해주겠다 이렇게 정확하게 코드를 짜는게 좋다고 한다.

     


     

    패킹과 언패킹

     

    말그대로 묶어주거나 풀어주는 걸 의미한다. 주로 리스트나 딕셔너리의 값을 함수에 입력할 때 사용한다.

     

    리스트별 * 하나를 붙이고 아규먼츠라는 뜻으로 함수가 받는 인자에 args 를 써준다.

     

    [아래 코드 설명]

    add라는 함수가 받는 숫자 개수에 제한을 두고싶지 않을때 *args를 쓸 수 있다.

    또한 리스트 앞에 *을 붙이면 리스트가 풀어진다.

    즉, *numbers , *[1, 2, 3, 4] , (1, 2, 3, 4) 이 세개는 다 같은거고, print해보면 결과도 모두 같은 걸 볼 수 있다.

    def add(*args):
        result = 0
        for i in args:
            result += i
    
        return result
    
    
    numbers = [1, 2, 3, 4]
    
    print(add(*numbers))
    print(add(*[1, 2, 3, 4]))
    print(add(1, 2, 3, 4))
    """
    
    # result output
    """
    10
    10
    10
    """

     

     

    딕셔너리도 동일한데 별을 ** 두개 붙이고, 키워드가 붙어서 kwargs 로 써주면 된다.

     

    [코드 설명]

    set_profile이라는 함수가 있고 데이터를 kwargs로 받아온다. ** 이므로 딕셔너리가 된다.

    딕셔너리에서 .get 으로 데이터를 받아오는데, 

    .get은 딕셔너리 안에 해당되는 키가 있을 경우 키에 해당되는 밸류를 보여주고 키가 없을 경우에는 뒤에 지정해준 값 "-"을 보여준다.

    def set_profile(**kwargs):
        profile = {}
        profile["name"] = kwargs.get("name", "-")
        profile["gender"] = kwargs.get("gender", "-")
        profile["birthday"] = kwargs.get("birthday", "-")
        profile["age"] = kwargs.get("age", "-")
        profile["phone"] = kwargs.get("phone", "-")
        profile["email"] = kwargs.get("email", "-")
    
        return profile
    
    
    user_profile = {
        "name": "lee",
        "gender": "man",
        "age": 32,
        "birthday": "01/01",
        "email": "python@sparta.com",
    }
    
    print(set_profile(**user_profile))

     

     

    즉, user_profile에는 phone 키값이 없으니까 실행시켜보면 'phone' : '-' 이렇게 출력된다.

    {'name': 'lee', 'gender': 'man', 'birthday': '01/01', 'age': 32, 'phone': '-', 'email': 'python@sparta.com'}

     


     

    args와 kwargs를 같이 쓸 수도 있다.

     

    def sample(a, b, *args, **kwargs):
        print(a)
        print(b)
        print(args)
        print(kwargs)
    
    
    sample(1, "안녕", 3, 4, 5, "a", "b", key="a", test="b", test_key="c")

     

    이렇게 sample안에 값을 막 써도 실행시켜보면

     

    1
    안녕
    (3, 4, 5, 'a', 'b')
    {'key': 'a', 'test': 'b', 'test_key': 'c'}

     

    문제없이 결과가 잘 나온다.

     


     

    class 심화

     

    __init__ 함수는 클래스의 인스턴스를 생성하는 과정에서 무조건 실행되는 함수다.

     

     

    아래의 __init__함수

    name이라는 인자를 받고 > 생성된 과자의 이름은 name입니다 라고 출력을 해주고 > self.name에 name이라는 변수를 저장해준다.

    class CookieFrame():
        def __init__(self, name):
            print(f"생성 된 과자의 이름은 {name} 입니다!")
            self.name = name
    
    cookie1 = CookieFrame("cookie1") # 생성 된 과자의 이름은 cookie1 입니다!
    cookie2 = CookieFrame("cookie2") # 생성 된 과자의 이름은 cookie2 입니다!

     

    이닛 함수에서 쿠키의 name을 변수로 저장해줬기 때문에 나중에 인스턴스로 생성된 쿠키의 이름이 뭔지 확인하고 싶으면

    print(cookie1.name)으로 확인해볼 수 있다.

     

    name을 입력하지 않아도 에러가 나지 않도록 하려면 아래와 같이 name에 기본값으로 default를 넣어줘야 한다.

    class CookieFrame():
        def __init__(self, name="default"):
            print(f"생성 된 과자의 이름은 {name} 입니다!")
            self.name = name
    
    
    cookie1 = CookieFrame("초코칩 쿠키")
    cookie2 = CookieFrame("마카다미아 쿠키")
    cookie3 = CookieFrame()
    
    print(cookie1.name)
    print(cookie2.name)
    print(cookie3.name)

     

    실행시켜보면 이렇게 잘 출력된다.

    생성 된 과자의 이름은 초코칩 쿠키 입니다!
    생성 된 과자의 이름은 마카다미아 쿠키 입니다!
    생성 된 과자의 이름은 default 입니다!
    초코칩 쿠키
    마카다미아 쿠키
    default

     


     

    상속

     

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

     

    Monster 라는 부모 클래스가 있고 

    파이어몬스터 클래스와 아이스몬스터 클래스가 super().__init__을 사용하여 부모클래스의 코드를 상속받으면

    super().__init__(hp)

     

    코드를 반복해서 쓰지 않아도 간편하게 코드를 짤 수 있다.

    만약 부모 클래스와 다른 코드를 오버라이딩 하고싶으면 그냥 자식 클래스에 안에 새로 코드를 써주면 된다.

     

    class Monster():
        def __init__(self, hp, attribute='generic'):
            self.hp = hp
            self.attribute = attribute
    
        def attack(self, damage):
            self.hp -= damage
    
        def status_check(self):
            print(f"{self.attribute} monster's hp : {self.hp}")
    
    
    class FireMoster(Monster):
        def __init__(self, hp):
            super().__init__(hp)
            self.attribute = 'fire'
    
    
    class IceMoster(Monster):
        def __init__(self, hp):
            super().__init__(hp)
            self.attribute = 'ice'
    
    
    monster1 = Monster(90)
    monster1.attack(50)
    monster1.status_check()
    
    fire_monster = FireMoster(120)
    fire_monster.attack(60)
    fire_monster.status_check()
    
    ice_monster = IceMoster(100)
    ice_monster.attack(30)
    ice_monster.status_check()

     

     

    위 코드를 실행시키면 

    generic monster's hp : 40
    fire monster's hp : 60
    ice monster's hp : 70

     

    이렇게 값이 잘 나온다.

     

     

    다른 사람이 만든 모듈의 코드를 가져와서 수정해서 쓸 때도 사용할 수 있다. 코드를 직접 변경하면 오류가 생길 수 있으므로, 커스텀할 클래스를 복사해와서 새로운 이름으로 따로 정의해주고 변경하고자 하는 메쏘드를 새로 오버라이딩해주면 된다.

     


     

    정규표현식(regex)

     

    정규표현식은 문자열이 특정 패턴과 일치하는지 판단하는 형식 언어로, 이메일 검증, 패스워드 검증 등을 간소화된 코드로 작성할 수 있다.

     

    아래 예시는 이메일을 검증하는 정규표현식이다.

    re를 import 해줘야 하고 (re는 regex의 약자)

    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)

     

    re.compile() 괄호 안에 정규표현식 코드를 가져오면 된다.

     

    참고로 re.compile(r"^[\w\.-]+@([\w-]+\.)+[\w-]{2,4}$") 에서

    괄호 안에 처음 있는 r은 \n(개행), \t(탭) 으로 쓰이지 않고 문자 그대로 쓰여지기 위해 붙여준거다.  

     


     

    파일 탐색

     

    glob이라는 라이브러리를 import하고 glob.glob으로 가져와야 한다.

     

    ./  : 현재 경로에 있는

    venv 폴더 안에 있는 

    * 모든 폴더 또는 파일을 탐색하겠다 라는 뜻이다. 

     

    상위 폴더 안에 있는 모든 하위 폴더를 다 보고 싶으면 recursive라는 플래그를 써줘야 한다. 그리고 별 ** 두개를 추가해야한다.

    **를 추가 하고 , recursive=True  추가

     

    만약, 파이썬 확장자 파일만 찾고 싶으면

    **/ 뒤에 *.py 이렇게 확장자명을 붙여서 추가해주면 파이썬 확장자를 가진 파일들만 볼 수 있다.

    from pprint import pprint
    import glob
    
    path = glob.glob("./venv/*")
    pprint(path)
    
    path = glob.glob("./venv/**", recursive=True)
    pprint(path)
    
    path = glob.glob("./venv/**/*.py", recursive=True)
    pprint(path)

     


     

    open

     

    파이썬에서 open이라는 함수를 이용해서 파일을 열고 쓸 수 있다.

    이렇게 하면 file.txt라는 이름을 가진 텍스트파일이 열리고 만약 없으면, file.txt라는 이름의 새로운 파일이 생성된다.

    w는 쓰기모드새롭게 내용이 써진다. 덮어쓰기 기능과 같아서 여러번 실행해도 file.text에는 안녕! 이라는 텍스트 하나만 저장된다.

    f = open("file.txt", "w", encoding="utf-8")
    f.write("안녕!\n")
    
    f.close()

     

     

     

    만약 기존 텍스트에 새로운 내용을 추가로 작성하고 싶으면 w대신에 a를 써야한다. (a는 append의 약자)

    읽기모드로 파일을 열고 싶으면 r을 써주면 된다.

    인코딩은 파일의 인코딩 형식을 지정해주는건데 보통 utf-8로 하면 제대로 불러와진다고 한다.

    f = open("file.txt", "a", encoding="utf-8")
    f.write("파이썬!\n")
    f.write("파이썬!\n")
    
    f.close()

     

    이렇게 쓰고 난 후에는 꼭 f.close()로 파일을 닫아줘야한다

     


     

    with open 으로도 파일을 열 수 있다. 

    as r 로 파일 객체를 r이라는 변수에 할당하고, r.readlines()로 파일의 내용을 한줄씩 읽어 리스트에 저장한다.

     

    with open으로 연 파일은, with에서 나오는 순간 파일이 자동으로 닫힌다.

    close() 해주지 않아도 되서 잠깐 보는 경우 깔끔하기도 하고 휴먼에러를 방지할 수 있다.

    with open("fiie.text", "r", encoding="utf-8") as r:
        result = r.readlines()
        print(result)

     

    실행시켜보면 이렇게 출력된다.

    ['안녕!\n', '파이썬!\n', '파이썬!\n']

     

     

    만약 파일이 너무 수십만줄이 되는 경우, 읽기가 불편할 수가 있다. 반복문을 써서 한줄씩 읽을 수도 있다.

    with open("fiie.text", "r", encoding="utf-8") as r:
        while True:
            line = r.readline()
            if not line:
                break
    
            line = line.strip()
            print(line)

     

     

    이렇게 하면 더이상 읽을 라인이 없을때까지 한줄씩 결과값을 출력한다. 

    안녕!
    파이썬!
    파이썬!

     


     

    itertools

     

    itertools는 효율적인 루핑을 위한 이터레이터를 만드는 함수.

     

    이터툴즈를 쓰면 데카르트 곱(두 집합 간의 모든 가능한 조합을 나타내는 수학적 연산)도 간단하게 구할 수 있다.

    from itertools import product
    
    sample1 = ["A", "B", "C", "D"]
    sample2 = [1, 2, 3]
    
    for i, v in enumerate(product(sample1, sample2), 1):
        print(v, end="")
        if i % 3 == 0:
            print("")

     

    enumertate는 행과 열 형식으로 표현해주기 위해 쓴거고, product 안에 샘플1,2를 넣어주면 된다. 뒤에 오는 1은 인덱스값을 i를 1부터 시작하게 하겠다는 뜻이다.

    print(v, end="") 는 v라는 튜플을 프린트 할건데 end="" 을 넣어주므로써 한줄에 쭉 출력하라는 뜻이다.

    근데 샘플2의 개수에 따라 줄바꿈을 해줘야 보기가 좋으니까, if문을 넣어서 i가 샘플2의 길이인 3의 배수일때마다 줄바꿈해주도록 한 것이다.

     

    이런 결과값을 볼 수 있다.

    ('A', 1)('A', 2)('A', 3)
    ('B', 1)('B', 2)('B', 3)
    ('C', 1)('C', 2)('C', 3)
    ('D', 1)('D', 2)('D', 3)

     

     

    순열

     

    순열도 이터툴즈로 permutations 모둘을 임포트 해주고 안에 데이터만 넣어주면 알아서 계산해준다.

    from itertools import permutations
    
    sample = ["A", "B", "C"]
    
    for i in permutations(sample, 3):
        print(i)

     

    이러면 원소의 개수가 3개인 순열을 만들어준다.

    ('A', 'B', 'C')
    ('A', 'C', 'B')
    ('B', 'A', 'C')
    ('B', 'C', 'A')
    ('C', 'A', 'B')
    ('C', 'B', 'A')

     

     

    이와 같이,

    원소의 개수가 n개인 조합을 구할 땐 combinations 모듈을 import 해서 위와 동일한 방법으로 사용하고 

    원소의 개수가 n개인 조합 (중복 허용) 을 구할 땐  combinations_with_replacement 모듈을 import해서 사용하면 된다.

     


     

    requests

     

    requests는 http 통신을 가능하게 해주는 모듈로, beautifulsoup과 함께 웹 크롤링을 하거나 api 통신이 필요할 때 사용된다.

     

    터미널, pip install requests 설치

     

    먼저 requests를 임포트 해주고 

    해당 사이트 url을 가져오고 requests.get으로 정보를 요청해 가져올 수 있다. 

    r이라는 변수로 지정해준 유저의 정보를 r.text로, 상태 코드 정보를 t.status_code로 가져오면 된다.  

    import requests
    from pprint import pprint
    
    url = "https://jsonplaceholder.typicode.com/"
    
    r = requests.get(f"{url}users/1")
    pprint({
        "contents": r.text,
        "status_code": r.status_code,
    })

     

    그럼 이렇게 유저의 정보와 정상 통신 완료 (200) 이라는 status_code를 확인할 수 있다.

    {'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}

     

    참고로 출력 결과는 딕셔너리같지만 json이라는 포맷 형태이다.


     

    get 대신에 post를 써서 정보를 생성할 수도 있다.

    import requests
    from pprint import pprint
    
    url = "https://jsonplaceholder.typicode.com/"
    
    data = {
        "name": "sparta",
        "email": "sparta@test.com",
        "phone": "010-0000-0000",
    }
    
    r = requests.post(f"{url}users", data=data)
    pprint({
        "contents": r.text,
        "status_code": r.status_code,
    })

     

    이렇게 해서 실행시켜보면 이러한 결과값이 출력된다.

    201은 정보 생성 완료 라는 코드 번호로 정상적으로 실행된 걸 볼 수 있다.

    {'contents': '{\n'
                 '  "name": "sparta",\n'
                 '  "email": "sparta@test.com",\n'
                 '  "phone": "010-0000-0000",\n'
                 '  "id": 11\n'
                 '}',
     'status_code': 201}

     

     

    정보를 수정할 때는 put 

    정보를 삭제할 떄는 delete 를 쓰면 된다.

     


     

    json

     

    json의 형태는 key: value 쌍으로 이루어져 있고 파이썬의 dictionary 형태와 유사하다. 때문에 파이썬에서 json 데이터를 dictionary 데이터로 변경하거나 dictionary 데이터를 json으로 변경할 수 있다.

     

    일단 import 해주고

    r.text를 json.loads()안에 넣어서 출력하면 보기 좋게 출력되면서 딕셔너리 형태로 바로 바꿔준다. 

    import json
    import requests
    from pprint import pprint
    
    url = "https://jsonplaceholder.typicode.com/"
    
    r = requests.get(f"{url}users/1")
    
    response_content = json.loads(r.text)
    
    pprint(response_content)
    print(type(response_content))
    print(f"사용자의 아름은 {response_content['name']}입니다.")

     

     

    reponse_content 타입도 딕셔너리로 나오는 걸 볼 수 있다.

    또한 딕셔너리로 바꿔줬기 때문에 키를 이용해서 밸류를 가져올 수 있게 된다.

    {'address': {'city': 'Gwenborough',
                 'geo': {'lat': '-37.3159', 'lng': '81.1496'},
                 'street': 'Kulas Light',
                 'suite': 'Apt. 556',
                 'zipcode': '92998-3874'},
     'company': {'bs': 'harness real-time e-markets',
                 'catchPhrase': 'Multi-layered client-server neural-net',
                 'name': 'Romaguera-Crona'},
     'email': 'Sincere@april.biz',
     'id': 1,
     'name': 'Leanne Graham',
     'phone': '1-770-736-8031 x56442',
     'username': 'Bret',
     'website': 'hildegard.org'}
    <class 'dict'>
    사용자의 아름은 Leanne Graham입니다.

     


     

    csv

     

    csv 파일 읽기

    import csv
    
    csv_path = "sample.csv"
    
    csv_file = open("sample.csv", "r", encoding="utf-8")
    csv_data = csv.reader(csv_file)
    
    for i in csv_data:
        print(i)
    
    csv_file.close()

     

    csv를 임포트 해주고

    csv_path 로 불러올 csv파일의 경로를 지정해주고,

    open, r 로 읽기전용으로 파일을 열고,

    csv.reader() 함수를 사용해서 텍스트데이터를 리스트 형태로 읽어온다. 

    그런 다음, for문으로 csv데이터를 돌면서 데이터를 출력한다.

     

    작업이 끝난 이후에는 꼭 .close() 해줘야 햔다.

     

    ['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']
    ['jhon@example.com', '1998', 'John', 'Manchester']

     

    리스트 형태로 읽어왔기 때문에 이렇게 출력된다.

     


     

    csv를 dict 자료형으로 읽기

     

    모두 동일하고 reader를 DictReader로 바꿔주면 된다.

    import csv
    
    csv_path = "sample.csv"
    
    csv_file = open("sample.csv", "r", encoding="utf-8")
    csv_data = csv.DictReader(csv_file)
    
    for i in csv_data:
        print(i)
    
    csv_file.close()

     

    그럼 dict 형태로 출력된다.

    {'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': 'jhon@example.com', 'birthyear': '1998', 'name': 'John', 'Location': 'Manchester'}

     


     

    csv 파일 쓰기

     

    reader나 DictReader대신 csv.writer() 을 쓰면 된다.

    import csv
    
    csv_path = "sample.csv"
    
    # newline='' 으로 공백 라인이 생기지 않도록 해준다.
    csv_file = open(csv_path, "a", encoding="utf-8", newline='')
    csv_writer = csv.writer(csv_file)
    
    # .writetow로 행추가
    csv_writer.writerow(["lee@sparta.com", '1989', "lee", "Seoul"])
    
    csv_file.close()
    
    #제대로 행이 추가됐는지 확인하기 위해 다시 파일을 읽기모드로 열어서 출력해본다.
    csv_file = open(csv_path, "r", encoding="utf-8")
    csv_reader = csv.reader(csv_file)
    for row in csv_reader:
        print(row)

     

    실행시켜 보면, 맨 아랫줄에 제대로 추가된 걸 볼 수 있다.

    ['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']
    ['jhon@example.com', '1998', 'John', 'Manchester']
    ['lee@sparta.com', '1989', 'lee', 'Seoul']

     


     

    데코레이터(decorator)

     

    데코레이터의 구조

    # 데코레이터는 호출 할 함수를 인자로 받도록 선언
    def decorator(func):
        # 호출 할 함수를 감싸는 wrapper 함수를 선언
        def wrapper():
            # func.__name__에는 데코레이터를 호출 한 함수의 이름이 들어간다
            print(f"{func.__name__} 함수에서 데코레이터 호출")
            func()
            print(f"{func.__name__} 함수에서 데코레이터 끝")
    
        # wrapper 함수를 리턴
        return wrapper

     

    그 다음, 선언되는 함수 위에 @decorator를 추가해 데코레이터를 사용한다.

    @decorator
    def decorator_func():
        print("decorator_func 함수 호출")
    
    decorator_func()
    
    # result output
    """
    decorator_func 함수에서 데코레이터 호출
    decorator_func 함수 호출
    decorator_func 함수에서 데코레이터 끝
    """

     

     

     

    위 구조와 동일하게 

    double_number는 함수를 인자로 받고, 래퍼로 감싸진 함수 내부에서 각각의 인자 a, b를 두배로 만들고 함수를 호출한다.

    def double_number(func):
        def wrapper(a, b):
            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
    
    
    @double_number
    def double_number_subtract(a, b):
        return a - b
    
    
    print(double_number_add(5, 10))
    print(double_number_subtract(5, 10))

     

    double_number_add 함수 double_number_subtract 함수@double_number를 추가하면

     

    데코레이터가 적용되어,

    double_number_add 함수 double_number_subtract 함수의 인자인 a와 b가 두 배로 변환되어 더해지거나 뺀 결과값이 반환된다.

     

    30
    -10

     

    출력하면 이렇게 두배가 된 인자로서 계산된 값이 출력되는 걸 확인할 수 있다.

     

     

     

Designed by Tistory.