Naver Ai Boostcamp

[DAY 5] 파이썬으로 데이터 다루기

잡담연구소 2021. 1. 23. 00:02

File / Exception / Log Handling

📌Exeption

  • 예상 가능한 예외 

    - 발생 여부를 사전에 인지할 수 있는 예외 -> 미리 알고 명시적으로 정의함 

    ex ) 주소지가 입력되지 않았습니다. 입력해주세요 라는 문구가 뜨며 결제창으로 넘어가지 않음
    - if문 사용해서 미리 처리

  • 예상이 불가능한 예외 

    - 인터프리터 과정에서 발생하는 예외

    - 수행 불가시 인터프리터가 자동으로 오류를 호출 

    - 예외가 발생할 경우 후속 조치가 필요 -> "Exepton handling"

📌 Exeption handiling : try ~ except 문법

try : 
	예외 발생 가능 코드
except <Exeption Type> : 
	예외 발생시 대응하는 코드 

 

❗ except에 예외 이름을 지정하면 특정 예외가 발생했을 때만 처리코드를 실행할 수 있다. 

for i in range(10):
    try :
        print(i , 10//i)
    except ZeroDivisionError : 
        print("Error")
        print("Not divided by 0")
        
 ##############################################
Error
Not divided by 0
1 10
2 5
3 3
4 2
5 2
6 1
7 1
8 1
9 1

try 구문을 실행하면 i == 0 일 때, 오류가 나서 프로그램이 종료 될 것이다. 

이런 경우를 대비해 except 구문에 ZeroDivisionError라는 built-in error를 넣어준다. 

i == 0일 때, try 구문에서 except 구문으로 넘어가게 되고 두 문장을 출력한 후 다시 위로 올라가 i는 1부터 시작한다. 

 

그냥, 오류가 생길 경우 빌트인 에러를 넣어주면 될까? 아니다. 

현재 정수를 0으로 나눠야 하는 경우가 생겨 문제이므로 이에 맞는  ZeroDivisionError가 아닌 다른 빌트인 에러를 넣는 경우 아래와 같이 오류 메시지가 뜨며 프로그램이 종료된다.

 

예를 들어, 프로그램을 짤 때, 잘못된 빌트인 에러를 넣어주어 사용자가 작업을 하다가 저장도 되지 않고 프로그램이 종료되어버린다면,,? 재앙이다,,, 문제에 맞는 정확한 빌트인 에러를 넣어주어야한다.  

for i in range(10):
    try :
        print(i , 10//i)
    except ValueError : 
        print("Error")
        print("Not divided by 0")
        
 ##########################################3
 ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-3-0923c6ed3898> in <module>
      1 for i in range(10):
      2     try :
----> 3         print(i , 10//i)
      4     except ValueError :
      5         print("Error")

ZeroDivisionError: integer division or modulo by zero

 Error 종류가 많으니 필요할 때마다 찾아서 참고하자. 

  • IndexError : List 인덱스 범위를 넘어갈 때

  • NamError : 존재하지 않은 변수를 호출할 때 

  • ZeroDivisionError : 0으로 숫자를 나눌 때

  • ValueError : 변환할 수 없는 문자/숫자를 변환할 떄

  • FileNotFoundError : 존재하지 않는 파일을 호출할 때

a= [1,2,3,4,5]
for i in range(10):
    try :
        print(i , 10//i)
        print(a[i])
        print(v)
    except ZeroDivisionError : 
        print("Error")
        print("Not divided by 0")
    except IndexError as e : 
        print(e)
    except Exception as e: 
        print()
        
 ########################################################
 Error
Not divided by 0
1 10
2
name 'v' is not defined
2 5
3
name 'v' is not defined
3 3
4
name 'v' is not defined
4 2
5
name 'v' is not defined
5 2
list index out of range
6 1
list index out of range
7 1
list index out of range
8 1
list index out of range
9 1
list index out of range

❗ exception을 사용하면 예외의 종류에 관계없이 모든 예외를 처리할 수 있다.

❗ except  [발생오류 [as 오류 메시지 변수]] :except만 사용해도 되고, 추가적으로 발생오류 또는 오류메시지까지 설정ok

❗ except를 여러 개 사용할 수도 있다. 

ZeroDivisionError를 except 1 , IndexError를 except 2 , exception을 except 3 이라고 해보자. 

i == 0 일 때, try 구문에서 벗어나 맨처음 except1을 만나게 되고, 해당 오류가 맞으므로 print문을 출력하고 다시 위로 올라가 i가 하나 커진다.

i == 1 ~ 4 일 때는 10/i 를 출력하고, a[i]를 출력한 다음 , v를 출력해야되는데 v가 현재 정의되어있지 않다.

try구문에서 벗어나 except구문으로 가서 위에서 하나씩 내려오면서 ValueError를 포함하고 있는 except3를 만나 해당 print문을 출력하고 다시 위로 올라가 i를 하나씩 키운다. 

i == 5 ~9 일때는 10/i를 출력한 후 , a[i]에서 인덱스 범위를 벗어났기 때문에 IndexError가 있는 except2로 넘어가 print문을 출력한 후 다시 위로 올라가 i를 하나씩 키워준다.  

예외가 여러개 발생하더라도 먼저 발생한 예외의 처리 코드만 실행된다. 

클래스의 경우 높은 계층의 예외부터 처리된다. 부모클래스의 예외 -> 자식 클래스의 예외 

 

  • else 구문 

try:
    실행할 코드
except:
    예외가 발생했을 때 처리하는 코드
else:
    예외가 발생하지 않았을 때 실행할 코드
a= [1,2,3,4,5]
for i in range(10):
    try :
        print(i , 10//i)
    except ZeroDivisionError : 
        print("Error")
    else :
        print("에러 없지롱")

try문을 실행한다 -> 오류가 난다면 except구문으로 넘어가 출력한 후 , 위로 올라와 i 증가 

                      -> 오류가 나지 않았다면 else 구문으로 넘어가 출력한 후 , 위로 올라와 i 증가

 

  • try~except~finally 구문

try:
    실행할 코드
except:
    예외가 발생했을 때 처리하는 코드
else:
    예외가 발생하지 않았을 때 실행할 코드
finally:
    예외 발생 여부와 상관없이 항상 실행할 코드
a= [1,2,3,4,5]
for i in range(10):
    try :
        print(i , 10//i)
    except ZeroDivisionError : 
        print("Error")
    finally : 
        print("코드가 실행되었습니다.")

finally 는 예외의 유무와 상관없이 항상 실행된다.

보통 예외 여부와 관계없이 사용한 resource를 close해야할 때 많이 사용한다고 한다.

 

❗ else , finally 등 한 번에 쓰는 것을 알아보기 힘들어 권장하지 않으심

 

❓ 왜 if가 아니라 except를 사용하는가 

if는 로직적인 문제를 다룰 때 사용

상황마다 무엇을 쓰는 지 고려를 해봐야함 

파일이 비어있는 경우 except 권장 

 

📌오류 일부러 발생시키기 : raise

  • raise 구문 

    - 필요에 따라 강제로 예외를 발생 

    ex ) 처음부터 오류라서 쓰레기값만 쓰여서 시간낭비, 메모리 낭비만 될 수 있는 상황 
    ex ) 부모 클래스의 함수가 제대로 정의가 안되어있는 경우, 자식 클래스가 그 함수를 사용할 때

    - 지정한 예외를 일으킨다. -> raise 예외클래스(예외메시지)

while True : 
    value = input("변환할 정수 값을 입력해주세요 : ")
    for digit in value : 
        if digit not in "0123456789":
            raise ValueError("숫자 값이 아닙니다")
    print("정수 값으로 변환된 숫자 - " , int(value))
    
    ######################################################
    변환할 정수 값을 입력해주세요 : abc
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-f4abf58f24e6> in <module>
      3     for digit in value :
      4         if digit not in "0123456789":
----> 5             raise ValueError("숫자 값이 아닙니다")
      6     print("정수 값으로 변환된 숫자 - " , int(value))

ValueError: 숫자 값이 아닙니다

 

  • assert 구문 

    - 특정 조건에 만족하지 않을 경우 예외 발생 
    - 상태를 검증하기 위한 명령어로 , 결과가 참일 때는 아무 일도 일어나지 않고, 결과가 거짓일 때만 AssertionError가 발생한다.
    - 사용하기 간편하지만 , 발생시킬 예외를 직접 지정할 수 없다.
    - assert 검증식 , 오류메시지 

assert 1 + 1 == 2 , "참 잘했어요"
assert 1 + 1 == 1 , "계산실수"

################################################
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-2-64bcc45c0772> in <module>
      1 assert 1 + 1 == 2 , "참 잘했어요"
----> 2 assert 1 + 1 == 1 , "계산실수"

AssertionError: 계산실수

 

def get_binary_number(decimal_number : int) :
    assert isinstance(decimal_number , int)
    return bin(decimal_number)

get_binary_number(10.0)

##########################################################################
---------------------------------------------------------------------------
AssertionError                            Traceback (most recent call last)
<ipython-input-5-3139dcbd4147> in <module>
      3     return bin(decimal_number)
      4 
----> 5 get_binary_number(10.0)

<ipython-input-5-3139dcbd4147> in get_binary_number(decimal_number)
      1 def get_binary_number(decimal_number : int) :
----> 2     assert isinstance(decimal_number , int)
      3     return bin(decimal_number)
      4 
      5 get_binary_number(10.0)

AssertionError: 

❓ isinstance(parameter a , parameter b) 

처음에는 assert와 같이 쓰는 exception같은 뭐 그런 건 줄 알았다..

isinstance함수는 주어진 인스턴스가 특정 클래스/데이터 타입이니 검사해주는 함수다.

isinstance (인스턴스 , 클래스/데이터타입) 으로 써준 후 일치할 경우 True , 불일치할 경우 False를 리턴해준다. 

현재 입력받은 decimal_number가 정수(int)인지 검사를 하는데 10.0 으로 실수값을 주었기때문에 assert 예외가 발생한다.

 

assert vs raise  : 둘 다 똑같이 예외를 일으키는 구문 아니야?

비교

raise문 

assert문

용도

예외의 발생 

상태의 검증

언제 예외가 일어나나?

항상

검증식이 거짓일 떄만 

어떤 예외가 일어나나?

지정한 예외

AssertionError

 

File handling

📌 파일의 종류 

  • 기본적으로 text 파일과 binary 파일로 나뉜다. 

  • text파일은 사람이 볼 수 있고, 메모장으로 열었을 때 잘 읽을 수 있다면 뭐든 text파일이다. 
    ex ) HTML , 파이썬 코드 등 

  • binary 파일은 사람은 읽을 수 없고, 기계가 읽는다. 메모장으로 열었을 때 뭐야이건,,? 싶으면 binary 파일이다.
    ex ) 엑셀파일 , 워드 파일 

  • text파일도 실제로는 binary 파일이다. 하지만 아스키/유니코드 문자열 집합으로 저장돼 사람이 읽을 수 있는거다.

📌python File I/0 

  • "open"을 통해 파일에 접근 , "close"로 열린 파일을 다시 닫는다.
    r : 파일 읽어오기  , w : 파일 쓰기 , a : 파일 추가하기 
    encoding = "utf - 8" 혹은 "cp949"

f = open('text.txt' , "r")
content = f.read()
print(content)
f.close()

별도의 close 없이도 가능 

with open('text.txt' , "r") as f:
    content = f.read()
    print(content)
  • 한 줄 씩 읽어 list 형태로 저장해줌
    - f.readlines() : 한 줄 씩 읽어서 리스트에 한 줄씩 저장됨.
    - f.readline() : 반복문과 함께 사용 , 실행 시 마다 한 줄씩 읽어옴 

###1
with open('text.txt' , "r") as my_file:
    content = my_file.readlines()
    print(content)

###2
with open('text.txt' , "r") as my_file:
    content = my_file.readline()
    print(content)

두 문장은 "s" 하나 차이 뿐인데 출력문이 완전 달라진다. 

1번 같은 경우 readlines로 txt가 한 줄씩 읽혀 , 한 줄씩 리스트의 원소로 추가된다.  

['hi i am hyerin\n', 'i am 24\n', 'i am very hungry ']

2번 같은 경우 readline으로 실행 시 txt의 한 줄을 읽어온다. 

hi i am hyerin

 그래서 보통 txt 파일이 너무 커서 한 번에 불러오기엔 버거워서 한 줄식 실행시키며 확인하고싶을 때는 아래와 같이 

반복문 + readline()을 이용하는 거 같다.

with open('text.txt' , "r") as my_file:
    while True: 
        content = my_file.readline()
        if not content : break
        print(str(content.replace("\n" , "")))

 

📌 OS 모듈 사용하여 디렉토리 다루기

-굳이 cmd에 가지 않고도 파이썬 내에서 directory에 접근,생성할 수 있다. 

 

 

📌 Pickle

  • 파이썬에 특화된 binary file 

  • 파이썬의 객체를 영속화하는 빌트인 객체 

  • 실행 중 정보를 저장시켜 게속 사용하고싶을 때 pickle 사용 
    - 객체는 원래 메모리에 있어야한다 -> 메모리는 인터프리터가 끝나면 사라진다(free)

import pickle

f = open("list.pickle", "wb")
test = [1, 2, 3, 4, 5]
pickle.dump(test, f)
f.close()

wb를 사용하여 list.pickle이라는 새로운 binary file을 생성한다.

dump라는 함수를 사용하여 test라는 객체를 f 즉, list.pickle에 담아준다. 

새로운 binary file을 만들 때 wb로 열어 , dump로 객체를 넣어준다. 

이 상태로 list.pickle이라는 파일을 열어보면 알 수 없는 문자들만 나온다.

왜? binary file은 읽을 수 없으니까

f = open("list.pickle", "rb")
test_pickle = pickle.load(f)
print(test_pickle)
f.close()

저장해놓은 list.pickle을 재사용하고싶어 불러올 떄는 rb를 사용하여 읽어준다.

load함수를 통해 list.pickle 에 담긴 정보를 test_pickle에 저장해준다.  

 

클래스도 가능 

import pickle


class Mutltiply(object):
    def __init__(self, multiplier):
        self.multiplier = multiplier

    def multiply(self, number):
        return number * self.multiplier


muliply = Mutltiply(5)
muliply.multiply(10)

f = open("multiply_object.pickle", "wb")
pickle.dump(muliply, f)
f.close()


f = open("multiply_object.pickle", "rb")
multiply_pickle = pickle.load(f)
multiply_pickle.multiply(5)

 

📌 logging 

  • 프로그램이 실행되는 동안 일어나는 정보를 기록 남기기

  • 유저의 접근 , 특정 함수의 사용 , 프로그램의 exception을 시간과 함께 기록 

  • 어디에 기록해둘까? console 화면에 출력 ,파일에 저장 ,DB에 저장

  • 하지만 CONSOLE창에 남기면 분석 시 사용불가 -> 어딘가에 따로 남겨둬야함

  • 로그를 분석해 의미있는 결과를 도출 -> 데이터 분석 -> (이런 로그들이 모여 비즈니스까지 가는 거 아닐까...?)

import logging 
logging.debug("틀렸다") # 디버깅 
logging.info("확인해") #정보
logging.warning("조심")# 경고 , 조심 주의 
logging.error("에러났어")# esception이 일어낫을 때 에러가 났다고 알려줌 
logging.critical("망했다")# 프로그램이 완전 종료되었을 때

 

 

 파이썬의 로깅레벨이 기본적으로 WARNING 부터 설정되어있어서, 사용자인 나는 WARNING 부터 볼 수 있음 

  • basicConfig(level = ) : 로깅 레벨을 변경
    - 화면에 출력만 되고 기록이 따로 저장되지 않음 

  • FileHandler 사용 -> "my.log"라는 파일에 기록됨.

steam_handler = logging.FileHandler(
    "my.log" , mode ="w" , encoding = "utf8")
logger.addHandler(steam_handler)

 

📌 parser

데이터 파일 위치 , 저장 장소 , operation type 등 프로그램 실행 설정 방법이 필요 

  • configparser 
    - 프로그램의 실행 설정을 file 에 저장함 

    - section , key , value 값의 형태로 저장되어 dict type 형태로 관리 및 호출된다.

[SectionOne]
Status: Single
Name: Derek
Value: Yes
Age: 30
Single: True

[SectionTwo]
FavoriteColor = Green

[SectionThree]
FamilyName: Johnson

- 각각의 섹션마다 key - value가 저장된다.  key : value  , key = value 모두 가능 

import configparser
config = configparser.ConfigParser()
config.sections()

config.read('example.cfg')
config.sections()

print(config.sections())
>> ['SectionOne', 'SectionTwo', 'SectionThree']

print(config["SectionOne"])
>> <Section: SectionOne>

- config.sections()로 cfg 내 section을 리스트에 저장해준다.

- sectionOne 값을 출력하고 싶어 print(config["SectionOne"]) 를 출력하면 sectionOne은 객체로 저장되기때문에 우리가 원하는 k-v값들이 나오지 않는다. 접근하고싶다면 for 를 사용하여 아래와 같이 출력하면 된다 

for key in config['SectionOne']:
    print(f" {key} : {config['SectionOne'][key]}")
    
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 status : Single
 name : Derek
 value : Yes
 age : 30
 single : True
  • argparser 

    - 콘솔 창에서 프로그램 실행시 setting 정보를 저장함.

    - command - line option이라고도 부름 

프로젝트를 할 때, 남들이 쓰길래 따라써봤던 경험이 있다. 아래 코드가 내가 썼던 argparser 코드다.
그냥 변수에 대해서 설명?정도만 해주는 역할이라고 생각했는데, 프로그램 실행시 셋팅정보를 알려주는 거였다니,,,

parser = argparse.ArgumentParser(description='Train')
parser.add_argument('--experiment_dir', dest='experiment_dir', required=True,
                    help='experiment directory, data, samples,checkpoints,etc')
parser.add_argument('--experiment_id', dest='experiment_id', type=str, default="0",
                    help='sequence id for the experiments you prepare to run')
args = parser.parse_args()

  

📌 logging 적용하기

  • 로그의 결과값의 format 지정

formatter = logging.Formatter('%(asctime)s %(levelname)s %(process)d %(message)s')

👉 logging은 당장 쓸 필요가 없지만 개념정도는 알아두고  ,argparser 나 configparser 중심으로 알아두자.

 

 

Python Data Handling : csv , html , xml , json

 

📌 CSV(comma separate value)

  • 엑셀 양식의 데이터를 프로그램에 상관없이 손 쉽게 쓰기 위한 데이터 형식 , 필드를 쉼표로(,)로 구분함 

  • 문제점 : 문장 내 쉼표는 전처리 과정이 필요 -> 파이썬에서 csv객체 제공

import csv
reader = csv.reader(f , delimeter = ',' , quotechar = '"' , quoting = csv.QUOTE_ALL)

- delimeter :  데이터를 무엇을 기준으로 자를 거인가 (쉼표, 공백 등 ) default 값은 쉼표다

 - quotechar : 무엇을 기준으로 하나의 스트링으로 볼 것인가 

    hello,hyerin 같은 경우 나뉘지 않고 하나로 묶여야 된다. 그때 quotechar 를 사용하여 나뉘면 안되는 데이터를 무엇으로        묶을 건지를 설정할 수 있다. default값은 " 이다. 

- quoting : quotechar의 레벨을 결정한다. 묶는 것을 최소로 할 건지, 모두 묶을 건지와 같을 걸 설정할 수 있다. 

  default 값은 quoteminimal 

  • 한글 처리 : 한글을 적을 때 앞에 u를 붙여줌 -> 한글처리로 유니코드 데이터를 cp949로 변환

locataion.find(u"성남시") != -1

❗ 읽어올 때 , 인코딩 윈도우에서는 웬만하면 cp949다. 안되면 utf-8 해봐라 

❗ 저장할 때는 utf-8로 저장해라 

❗ delimeter는 데이터를 자르는 기준 ,quotechar 는 데이터를 싸매는 기준 

 

📌 HTML

  • Web : 데이터 송수신을 위한 HTTP 프로토콜 , 데이터를 표시하기 위해 HTML사용

    - 웹은 HTML의 덩어리- html 을 다운로드 받은 후 , 브라우저에서 해석/표시 하면 우리가 보는 웹이 만들어진다.    이 과정을 '렌더링'이라고 함

  • html : 웹 상의 정보를 구조적으로 표현하기 위한 언어 

  • 제목 , 단락 ,링크 등 요소 표시를 위해 Tag를 사용 - 모든 요소들은 꺽쇠 괄호 안에 둘러 쌓여있음 

  • 트리 모양의 포함관계를 가짐- html 아래로 head, body가 있고 head 아래로 title  , body 아래로 h1,p가 있다. -> 트리 모양 

http://www.devkuma.com/books/pages/115

- <!DOCTYPE> : 현재 문서가 HTML 문서 타입을 명시한다. (HTML5 문서 타입은 <!DOCTYPE html> 이다.)

- <html> : HTML 문서의 루트(root) 요소를 정의한다.

- <head> : HTML 문서의 메타데이터(metadata)를 정의한다.

❓ 메타데이터
: 메타데이터(metadata)란 HTML 문서에 대한 정보(data)로 웹 브라우저에는 직접적으로 표현되지 않는 정보를 의미한다.

  이러한 메타데이터는 <title>, <style>, <meta>, <link>, <script>, <base>태그 등을 이용하여 표현할 수 있다.

- <title> : HTML 문서의 제목(title)

- <body> : 웹 브라우저를 통해 보이는 내용(content) 부분이다.

- <h1> ~ <h6> : 제목(heading)을 나타낸다.

- <p> : 단락(paragraph)을 나타낸다.

http://www.devkuma.com/books/pages/340

<태그명 속성명="속성값">내용</태그명>

- 태그 : 시작태그와 종료태그 두 종류 

          시작 태그는 요소를 시작하고 종료태그는 요소를 끝내는데 종료태그는 없어도 된다.

- 요소(element) : 시작태그와 종료태그로 이뤄진 모든 명령어들을 얘기한다. 

- 속성 : 시작 태그 안의 좀 더 구체화된 명령어 , 속성 이름과 속성값(value)로 표현된다. 

<li class="active">HTML 요소 구조</li>

li : 태그명 (리스트에 포함되는 아이템을 정의할 때 사용하는 태그)

class = "active" :  속성명과 그에 맞는 속성값 

HTML 요소 구조 : 내용으로 우리가 웹에서 볼 수 있는 내용이다. 

</li> : 종료태그

 

  • 많은 데이터들이 웹을 통해 공유 -> HTML의 규칙을 분석하여 데이터의 추출 -> 분석 

    - regex(정규표현식) , beautifulsoup등 사용 가능 

  • 정규식(regular expression) 

    - 복잡한 문자열 패턴을 정의하는 문자 표현 공식 

    - 특정한 규칙을 가진 문자열의 집합 추출 

    ex ) 010- 8241- 9037 -> 세글자 - 네글자 - 네글자라는 특정한 규칙 존재 => 01082419037숫자만 뽑아냄

  • HTML 역시 tag를 사용한 일정한 형식이 존재해 regex로 추출 용이 

❗ 정규식 문법은 너무 방대해서 필요할 때마다 검색해서 차츰차츰 배워나가라. 

정규식 연습장 (regexr.com/)

 

📌 XML

  • 데이터의 구조와 의미를 설명하는 TAG를 사용하여 표시하는 언어 (≒ HTML) 
  • TAG와 TAG 사이 값이 표시되고 구조적인 정보 표현 
  • 정규표현식으로 parsing 가능 but,,, beautifusoup이 가장 많이 쓰임 
    - 느리지만  간편하게 사용 가능 
#BeautifulSoup 모듈
from bs4 import BeautifulSoup

with open("books.xml", "r", encoding="utf8") as books_file:
    books_xml = books_file.read()  # File을 String으로 읽어오기

# xml 모듈을 사용해서 데이터 분석
# File을 xml로 파싱해라 태그로 author가 들어간 정보를 모두 찾은 후 book_info에 모두 넣어라
soup = BeautifulSoup(books_xml, "lxml")
# author가 들어간 모든 element 추출
for book_info in soup.find_all("author"):
    print (book_info)
    print (book_info.get_text())
    # get_text : 반환된 패턴의 값 (태그와 태그 사이 값) 반환

 

📌 JSON (JavaScript Object Notation)

  • 원래 웹 언어이 자바스크립트의 데이터 객체 표현 방식 
  • "간결성" -> 데이터 용량이 적고 code로의 전환이 쉬움 
  • dict type처럼 key : value 쌍으로 표시 
  • json 모듈을 사용해 손쉽게 파싱 및 저장 가능 -> 저장 및 읽기 dict type가 상호호환됨 
import json

with open("json_example.json", "r", encoding="utf8") as f:
    contents = f.read()
    json_data =  json.loads(contents)

print(type(json_data))
>> <class 'dict'>
# json은 dict type과 호환이 가능 

print(json_data)
>>{'employees': [{'firstName': 'John', 'lastName': 'Doe'}, {'firstName': 'Anna', 'lastName': 'Smith'}, {'firstName': 'Peter', 'lastName': 'Jones'}]}
# employees 라는 key에 리스트가 value로 대응됨 
# 리스트의 원소들도 각각의 key - value 쌍으로 이루어져있음 

for employee in json_data["employees"]:
    print(employee)
>> {'firstName': 'John', 'lastName': 'Doe'}
>> {'firstName': 'Anna', 'lastName': 'Smith'}
>> {'firstName': 'Peter', 'lastName': 'Jones'}
  • pickle과 같이 파일을 가져올 때는 load , 파일에 쓸 때는 dump를 사용

 

피어세션 

오늘 피어세션에서는 6명 각자 과제 코드를 리뷰했다.

확실히 남의 코드를 읽어봐야 이렇게도 쓰는 구나 저렇게도 쓰는 구나 하면서 많이 배우는 거 같다.

꼭 거창하지 않아도 사소한 것도 이렇게 하면 더 편해요~~하고 알려주셨다. 

난 특히 set을 잘 못 쓰는데, 이번 과제에서 중복처리 할 일이 많아 set 쓰는 법을 많이 알아가는 거 같다.

 

1.  return 이후 식이 맞다면 알아서 True를 반환해주고 틀리면 False를 반환해준다. 

 ################ 남의 코드 #########################
 return 100 <= num < 1000
 
################# 내 코드###########################
if num > 99 and num < 1000: result = True 
else : result = False
return result

 2. 세자리 중 중복되는 수가 있는지 확인하려면 ? 그냥 set의 개수를 세면 된다. 🥴

##################### 남의 코드 ###############3
return len(set(three_digit)) == 3

##################### 내 코드 ##################
 used = []
    for i in three_digit:
        if i in used : 
            result = True
            break
        else : 
            result = False 
            used.append(i)
return result 

3. 맞고 틀리고를 떠나서 아래 코드가 다 간결하니 잘 읽히는 거 같다 (내 기준)

############################ 내 코드 ##############################
if one_more_input.lower() == "y" or  one_more_input.lower() == "yes": result = True

########################### 남의 코드 #############################
return one_more_input.lower() in ['y' , 'yes]

4. is_digit과 is_decimal의 차이 

해설 강의시간에 어떤 똑똑한 캠퍼가 알려주셨다. 이 블로그를 참고했다.

is_digit과 is_decimal 둘 다 주어진 문자열이 숫자로 되어있는지 검사하는 함수다. 

a = '3²' 
print(a.isdigit()) 
print(a.isdecimal())

>> True
>> False

isdigit은 단일 글자가 "숫자 모양"으로 생겼으면 무조건 True를 반환한다. 

숫자처럼 생겼다면 모든 글자를 숫자로 간주한다. 

반면 isdecimal은 주어진 문자열이 int 형으로 변환이 가능한지 알아내는 함수이기 때문에 제곱과 같은 특수문자인 숫자모양은 숫자로 간주하지 않는다. 

보너스로 isnumeric()이라는 것도 있는데, "숫자값 표현" 이라면 문자열까지 인정한다. 

제곱근 ,분수 ,거듭제곱 같이 숫자값을 표현하는 문자열이라면 True!

-> 여기서 드는 의문은 그렇다면 '3²'은 과연 숫자로 보는 게 맞을까 문자로 보는 게 맞을까,,,,? 
    상황마다 어떻게 간주할지 미리 정하고 맞는 함수를 사용하면 좋을 거 같다는 생각!

 

5. nonlocal  

함수 코드를 짜면 nonlocal이 뭔지 바로 와닿는데 말로 설명하라고 하면 좀 힘들다,,, 

nonlocal x 를 사용하면 함수 g를 감싸고 있는 f의 x를 사용한다는 뜻이다.

그렇다고 전역변수인 x =20과 같은 x는 아니다 😂

 

x = 20  # global   
 
def f():
    x = 40
    
    def g():
        nonlocal x      // x = 40  : 메모리에 40이 할당되어있는 변수 x를 함수 g에서도 사용
        x = 80
        print(x)
        
    g() 
    print(x)  			// x = 40 이었지만 g에서 80으로 재할당해줬기때문에 80으로 바뀜

f()
print(x)  		//함수 밖의 전역변수 x = 20 이 출력

>> 80
>> 80
>> 20

그리고 무조건 nonlocal은 함수 한 개에 사용해서는 안된다.

함수 g에서 nonlocal을 사용했다면, 무조건 f같이 g를 감싸고 있으며 x가 정의되어있는 함수가 존재해야한다. 

x = 20  # global   
 
def f():
    def g():
        nonlocal x    
        x = 80
        print(x)
        
    g() 
    print(x)  		

f()
print(x) 

>> SyntaxError: no binding for nonlocal 'x' found

'Naver Ai Boostcamp' 카테고리의 다른 글

[DAY 7] 경사하강법  (0) 2021.01.26
[DAY 6] Numpy / 벡터 / 행렬  (0) 2021.01.26
[DAY 4] 파이썬 기초 문법 III  (1) 2021.01.21
[DAY 3] 파이썬 기초 문법 II  (0) 2021.01.20
[DAY 2] 파이썬 기초 문법  (0) 2021.01.19