posted by 귀염둥이채원 2018. 4. 3. 01:59

1. 주석

  • 한 줄 주석: #
  • 여러 줄 주석
    • 문자열을 만드는 방법과 동일하게 """ 내용 """ or ''' 내용 ''' 사이에 넣을 수도 있지만
    • PEP8에선 한 줄짜리 주석을 연속해서 쓰는 것을 권장하고 있다.
    • 서브라임 텍스트 등 대부분의 에디터는 cmd(or ctrl) + / 단축키를 지원한다.

2. 자료형

2.1. 숫자형

항목사용 예
정수123, -123, 0
실수1.2, -0.4, 3.4e10
복소수1+2j, -3J
8진수0o45, 0O42
16진수0xA1, OXFF
  • 지수 표현하기: 1의 자리 수와 소수로만 표현한다. 그리고 뒤에 e(E 동일)를 붙여서 10의 제곱수를 곱해서 표현한턴. 1.23e10은 1.23에 10의 10승을 곱한 것이고, 3.45e-10은 3.45에 10의 -10승을 곱한 것이다.
  • 복소수 활용: 내장함수가 있다.
    • 복소수.real복소수.imag 처럼 뒤에 붙여 사용하면 순서대로 실수부와 허수부를 리턴한다.
    • 복소수.conjugate()라는 내장함수를 사용하면 켤레복소수를 리턴한다.
    • abs(복소수)는 절대값을 리턴하는데 계산 방식은 1+2j일 때 1의 제곱과 2의 제곱을 더해서 루트씌운것이다.

2.2 문자열

2.2.1 기본

  • 문자열 나타내는 방법: ''""''' '''""" """ 이렇게 4가지다.
  • 문자열 합칠 때: 더하면 된다. "hihi" + "hello" => "hihihello"
  • 문자열 반복시키기: 곱하면 된다. "hi" * 2 => "hihi"
  • 문자열 역시 iterable이다. 인덱싱과 슬라이싱 활용할 수 있다.
    • 'abc'[2] => 'c''abcde'[-1] => 'e''abc'[-0] => 'a'
    • 'abc'[:2] => 'abc''abcde'[1:3] => 'bcd''abcde'[1:-2] => 'bc'
    • 하지만 인덱싱을 활용해서 문자열의 내용을 바꿀 수는 없다. 'abc'[0] = 'A' 를 하려면 에러가 뜬다. 새로 만들어야 한다. 기존 것을 활용하고 싶다면 바꾸고 싶은 글자의 인덱스를 확인하여 전과 그 후 부분을 슬라이싱해서 이어붙이면 된다.
    • :을 기준으로 start, end, stride 다. 만약 stride가 -면 뒤에서부터 역순으로 밟아나간다 생각하면 된다. 'abc'[::-1]이면 'cba'이고, 'abc'[::-2]이면 'ca'이다.

2.2.2 문자열 포매팅

코드설명
%s문자열 String
%c문자 character
%d정수 Integer
%f부동 소수 floating-point
%o8진수
%x16진수
%%퍼센트 문자 나타내기
  • '%d %s + %' 사용 방법
    • "I eat three %s" % "apple"
    • "I eat %d %s" % (3, "apple")
    • “I eat %s apples” % 3 이렇게 하면 3이 문자열 형태로 치환돼서 들어감. 변수가 무슨 타입인지 모르면 그냥 %s로 다 받아도 상관없다.
    • 값을 나타내는 변수를 활용해도 된다.
    • %를 사용할 때 % 문자를 나타내려면 %% 두 번 적어야 한다. %d%%
    • %10s 우측정렬. %-10s 좌측정렬. 공백 10개
    • %.4f 소수점 4자리까지
  • format 사용 방법
    • "{0} is {1}".format(1, “hi”)
    • 역시 % 때와 마찬가지로 숫자는 문자열로 자동 변환되고 값이 아닌 변수를 활용해도 오케이.
    • 이름으로 치환 가능하고 혼용도 된다: “I ate {0} applse. so I was {sick}”.format(3, sick=“hi”)
  • format에서 정렬하기
    • {0:<10} 좌측 정렬, {0:>10} 우측 정렬, {0:^10} 가운데 정렬 10칸 공백
    • 정렬기호(<, >, ^) 앞에 문자 하나 넣으면 그걸로 빈칸 채움. {0:_^10} 이런 식
  • .format에서 소수점 표현: {0:10.4f}
  • .format에서 curly bracket { }를 문자 그 자체로 표현하려면 2번 써준다. {{ }}
  • 문자열 앞에 r을 붙여서 r'hello' 이렇게 쓰면 순문자열이 된다. 즉 excape 문자 \를 쓰지 않아도 \n이나 \t 같은 문자를 나타낼 수 있다.

2.2.3 주요 함수들

  • 문자열에서 특정 문자 개수 세기: a = ‘hobby’ , a.count(‘b’)
  • 문자열에서 특정 문자 위치: a.find(‘b’) 또는 a.index(‘b’)
  • 문자열 삽입 join: “,”.join(‘abcd’) 를 하면 “a,b,c,d” 가 된다.
  • 공백 지우기: a.lstrip()a.rstrip() 왼쪽 오른쪽 지우기. 양쪽은 그냥 strip()
  • 문자열 바꾸기 replace. 정규표현식 간편하게 만든 느낌이다.
    • a = “life is too short”
    • a.replace(“life”, “yours”)
    • a = “yours is too short” 가 됨
  • split(). 나눠서 리스트에 넣음
    • () 사이에 아무것도 안넣으면 공백 기준으로 구분함
    • a=“a:b:c:d” 일 때 a.split(“:”) 하면 [‘a’, ‘b’, ‘c’, ‘d’]
  • str.maketrans(x[, y[, z]]) : 문자 단위 매핑되는 사전을 만드는 것
    • 매개변수 한 개: dictionary 객체
    • 두 개: 동일한 길이의 두 문자열이 들어가서 같은 위치끼리 대치된다.
    • 세 개: 앞의 두 매개변수는 두 개일 때와 같고, 세 번째 문자열은 모든 문자가 None으로 매핑된다.
  • 'Hello world!'.translate(dict_obj) : maketrans 함수로 나온 dict 객체를 규칙으로 해서 문자열을 변환한다.

2.3 리스트

2.3.1 기본

  • 리스트에 다양한거 다 들어갈 수 있다. 리스트까지 들어갈 수 있음.
  • 빈 리스트 생성은 a = list() or a = []
  • 리스트의 리스트는 이차원배열처럼 이해하면 됨. 리스트의 리스트의 리스트는 당연하게도 삼차원배열처럼 뽑아냄
  • 리스트 슬라이싱. 문자열 슬라이싱과 동일
  • 리스트 더하면 합쳐진 리스트가 됨. 곱하기는 같은게 반복되서 리스트가됨.
  • 리스트 수정은 그 부분 뽑아서(요소 하나만 인덱스로 뽑든, 슬라이싱으로 뽑든) 다른거 대입하면 된다. 리스트를 집어넣으면 리스트가 들어간다. 다만 한 가지 다른 것은
    • a[0] = [1, 2, 3] 으로 하면 리스트 자체가 들어가게되고
    • a[0:1] = [1, 2, 3]으로 하면 첫 칸에 요소 세 칸이 들어가는 것. 리스트가 들어가는게 아니다.
  • 리스트 요소 삭제는 a[0]=[] , a[1:3]=[] 식으로 빈 리스트를 대입하면 된다. 혹은 del 함수를 사용해서 del a[0] 해도 된다. del 하면 객체 자체가 지워진다. 즉 사용하던 메모리를 free 시킨다는 것을 의미한다. 즉 garbage collection이며 파이썬이 자체적으로 하고 있기 때문에 메모리 사용량을 위해 굳이 따로 해줄 필요는 없다.

2.3.2 관련 함수들

  • 리스트 + 리스트 하면 두 리스트가 연결된다.

  • [1] * 5 를 하면 [1, 1, 1, 1, 1]이 된다. 초기값 세팅할 때 좋을듯. 다음 예는 5X5 이차원 배열에 문자 'O'를 세팅하는 예다.

    board = []
    for i in range(5):
        board.append(["O"]*5)
  • a.append('something') 요소 추가는 맨 마지막에 붙는다.

  • a.sort()는 요소를 순서대로 정렬하는 것. 숫자도 되고, 문자도 된다. 오름차순.

  • a.reverse()는 요소 순서를 반대로 바꾸는거. 즉 sort한 다음에 리버스하면 내림차순 정렬이 됨.

  • a.index(요소) 를 하면 인덱스값을 반환.

  • a.insert(index, value) 를 하면 대체가 아니라 추가가 된다. 0 인덱스에 넣으면 원래 있던 요소들이 앞으로 한 칸씩 밀린다. 즉 설정한 인덱스 이후의 요소들이 모두 한칸씩 뒤로 밀린다.

  • a.remove(value)를 하면 a의 요소들 중 첫 value 요소를 제거한다. 만약 요소가 없다면 에러가 난다. 모든 요소를 다 제거하고 싶으면 try 안에 반복문 돌리는 것도 괜찮겠다.

  • a.pop() 은 맨 마지막 요소 빼낸다. 매개변수로 인덱스 값을 넣어주면 remove와 똑같이 첫 요소를 제외한다. 다만 remove와 다른 점은 뽑은 값을 리턴한다는 것.

  • a.count(1)은 1이 몇 겐지 세아려서 갯수를 리턴함

  • a.extend([1,2,3])을 하면 a 리스트 뒤에 매개변수 값이 합쳐진다. a += [1, 2, 3]과 동일한 의미다. append와 다른 점은 만약 a.append([1, 2, 3]) 하면 a의 마지막에 리스트 자체가 원소로 들어간다. 리스트가 합쳐지는게 아니라 리스트가 붙는다. 즉 위의 리스트 수정에서 extend는 슬라이싱, append는 인덱싱과 매칭된다 할 수 있다.

2.4 튜플

  • 리스트와 대부분 쓰는 방법이 같다. 생성은 my_tuple = ()를 쓰는 것이 일반적이고 아예 안써도 된다. 예를 들어 a = 1, 2, 3 처럼.
  • 위처럼 적용되기 때문에 리스트 내포 for문을 사용할 때 []로 감싸주지 않고도 바로 sum이나 max 함수를 쓸 수 있는 것이다.
  • 수정이 불가능하다. 상수화 된 리스트라고 생각하면 될까. 이 특성이 가장 중요하다. 대부분의 메소드를 똑같이 쓸 수 있지만 수정, 삭제, 추가는 안된다.
  • 요소 한 개만 쓰려면 a = (1,) 이렇게 뒤에 콤마 붙여야 함

2.5 딕셔너리

2.5.1 기본

  • a = {‘key’:’value’, ‘key’:’value’}
  • 키와 밸류로 이루어짐. 키를 인덱스처럼 활용해서 밸류를 뽑아낼 수 있다.
  • 키에는 숫자도 되고 문자열도 됨. 튜플도 됨. 하지만 리스트는 안됨. 키에는 변하는 값이 들어가면 안된다. 밸류에는 어떤 값이든 다 됨
  • 딕셔너리에는 인덱싱이나 슬라이싱 안된다. 무조건 키를 인덱스처럼 활용해서 밸류를 뽑아내는 수밖에 없다.
  • 뽑아내는거랑 같은 방식으로 썼을 때 만약 그 쌍이 없다면 추가되는 것.
  • 딕셔너리에는 순서가 없음.
  • 삭제는 del a[key] 형태로.
  • 처음 딕셔너리를 생성할 때 {1:111, 1:222} 형태로 키를 중복시키면 랜덤으로 하나만 남는다. 뭐가 없어지고 남을지 모른다.
  • 딕셔너리도 len(dict) 먹힌다. key-value pair 개수를 리턴.

2.5.2 관련 함수

  • a.keys() 라고 하면 딕셔너리의 키들이 뽑혀나옴. dict_keys 라는 객체 형태로 뽑힘. 만약 리스트가 필요하다면 list(a.keys()) 로 형변환하면 됨. 근데 굳이 변환 안해도 반복문 쓸 수 있음.
  • dict_keys 객체에선 append, insert, pop, remove, sort 메소드 사용 안된다.
  • a.values() 라고 하면 dict_values 객체가 리턴됨. 키객체와 같음
  • a.items()를 하면 쌍을 튜플로 각각 묶어서 dict_items 객체로 리턴함
  • 다 지우려면 a.clear()
  • a[key] 와 비슷하게 a.get(key) 도 됨. 다른 점은 없는걸 원했을 때 전자는 에러를 띄우지만 후자는 NONE을 출력. 후자가 나은듯. 에러 없으니
  • a.get(key)를 쓸 때 만약 값이 없을 때 논 대신 다른걸 쓰려면 디폴트값 설정할 수 있다. 이렇게. a.get(key, default)
  • key가 있는지 조사할 때 key in my_dict 쓰면 된다. 사실 in은 리스트나 튜플, 문자열 등에서도 모두 쓰일 수 있다. True False 리턴한다.

2.6 집합(Sets)

  • set은 my_set = set(my_list) 형태로 만든다.
    • my_set = set([1,2,3,4,5,5,5,5,5]) => set([1, 2, 3, 4, 5])
    • my_set2 = set(‘hello’) => set([‘h’, ‘e’, ‘l’, ‘o’])
  • 중복도 없고 순서도 없다.(index 미지원)
  • list(my_set) 처럼 형변환해서 인덱스 써라.
  • 교집합: & 또는 set1.intersection(set2)
  • 합집합: | 또는 set1.union(set2)
  • 차집합: set1 - set2 또는 set1.difference(set2)
  • 집합에 추가할 때
    • 한개만 추가: set1.add(value)
    • 여러개 동시 추가: set.update([5,6,7])
  • 제거: set.remove(value) 이것도 매개변수 딱 하나만 받는 함수다.
  • 세트의 원소로 리스트, 세트, 딕셔너리는 들어갈 수 없다. unhashable type이라고 TypeError라고 뜬다.

2.7 Boolean

  • 문자열, 리스트, 튜플, 사전형, 세트가 차있으면 참. 비어있으면 거짓
  • a = [1, 2, 3, 4] 일 때 a 리스트를 조건으로 해서 pop으로 뽑아내면 모두 뽑힌다. 예를 들어 while(a): print(a.pop())대신 이렇게 하면 반복이 끝난 후 a는 빈 리스트가 된다.

2.7 변수에 대하여

  • (a, b) = 1, 2 혹은 [a, b] = [3, 4] 식으로 여러 변수에 값을 한 방에 대입할 수 있다.
  • 두 변수의 값을 swap 하는 재밌는 방법: a, b = b, a
  • list를 복사할 때는 단순히 b = a 처럼 대입하면 안된다.
    • 두 레퍼런스 변수가 같은 객체를 가리키는 것이 되어버린다. 동일한 놈을 가리키고 있음.
    • 이러면 a가 가리키는 list의 원소를 수정했을 때 b가 가리키는 list의 원소도 변한다. 같은 list니까.
    • b = a[:] 처럼 하거나 from copy import copy 한 후에 b = copy(a) 처럼 활용한다.

3. 제어문(if, while, for)

  • value in iterable 형태 잘 쓰임. value not in iterable 도 가능.

  • is 와 == 는 같은 의미. 동시에 is not과 != 역시 같은 의미

  • 조건문에서 아무것도 하기 싫으면 pass 사용. 아예 안적으면 오류나서 이거 적어줘야 한다.

  • 가장 가까운 반복문 빠져나가는 break

  • 반복문에서 아래 코드는 더 이상 실행하지 않고 다음 반복으로 넘어가는 continue

  • 리스트 내포: [표현식 for 항목 in 반복가능객체 if 조건문]

  • for문에서 2개씩 변수를 받을 수도 있다.

    • 근데 만약 변수를 하나로만 받으면 아래 코드의 케이스에서 [1,2] [3,4] [5,6] 이렇게 세 뭉치로 튀어나오고
    • 변수를 i, j, k 세 개로 받으면 2개밖에 없는데 왜 3개 지정했냐고 에러가 난다. (루비에서는 알아서 k에 None을 넣더라. 에러 없이)
    test_list = [[1, 2], [3, 4], (5, 6)]
    for i, j in test_list:
        print(i, j)
  • print는 자동으로 개행한다. 없애려면 print("somethin", end=" ") 식으로 end에 원하는 문자를 지정해주면 된다. 디폴트가 개행문자 \n인 셈이다.

  • for와 while에서 else를 같이 쓸 수 있다.

    • 조건에 맞게 반복을 돈 후, 빠져나올 때 else의 실행문을 한 번 실행한다.
    • 하지만 조건이 아니라 중간에서 break 때문에 빠져나올 경우엔 else를 실행하지 않는다.
    • 리스트에서 조건 검사를 할 때 온전히 통과했다는 메시지를 else를 통해 해줄 수 있겠다. 만약 중간에서 틀린 검사가 나와서 break 했을 경우엔 else가 실행되지 않으므로 통과 메시지가 출력되지 않는다.
  • zip : 리스트가 2개 있는데 매칭해서 출력하고 싶을 때 사용한다. 짧은 쪽 리스트가 끝날 때 반복이 멈추고 원하는 만큼 리스트들을 zip할 수 있다.

    list_a = [3, 9, 17, 15, 19]
    list_b = [2, 4, 8, 10, 30, 40, 50, 60, 70, 80, 90]
    
    for a, b in zip(list_a, list_b):
        print max(a, b)

4. 입출력

4.1 함수

  • 함수 정의할 때 매개변수 없더라도 빈 괄호를 붙여줘야 한다.

    def hi():
        print("HI")
  • def 라인 바로 아래에는 주석으로 함수에 대한 설명을 적어주면 좋다.

  • 함수를 정의할 때 다른 함수 활용 가능. 즉 함수 내에서 함수 호출 가능

  • 함수의 리턴값은 오직 하나다. 두 개 이상을 리턴하는 것으로(예로 return a, b) 함수가 짜여진다면 이것은 (a,b)라는 하나의 튜플이 리턴되는 형태다. 그래서 c, d = a() 이런식으로 바로 두 개 변수에 집어넣을 수 있음.

  • 매개변수로 몇 개를 받을지 모를 때 앞에 * 붙여주면 된다. 주로 *args 라고 칭하는게 컨벤션이고 원하면 args 말고 다른 단어(python)를 써도 된다. 마지막에 써줘야 함. 이 args를 쓰려면 튜플 형태로 매개변수가 들어오기 때문에 iterable 활용하는 방식으로 써주면 된다.

  • 매개변수가 입력되지 않았을 때 디폴트값(초기값)을 설정할 수 있다. 매개변수 뒤에 param=value 하면 된다. 대신 디폴트값이 없는 매개변수 뒤에 있어야한다.

  • 함수 내의 변수 효력 범위

    • 아래 코드처럼 함수를 실행해도 a의 값은 변하지 않는다.
    • 정말 단순히 함수 내의 지역변수일 뿐이다. 값만 전달받은 것 뿐(call by value), 그 값 자체를 변화시키지(call by reference) 않는다.
    • 1을 증가시킨 값을 리턴해서 원래 변수에 다시 대입하는 방식밖에 없다.
    a = 1
    def variable_test(n):
        n += 1
        return
    variable_test(a) # a doesn't change

4.2 입력과 출력

  • print에서 print('hi' 'hi' 'hi')처럼 붙여쓰면 +랑 똑같고,
  • comma(,)로 이으면 띄워써진다. print(‘hi’, ‘hi’, ‘hi’)
  • 사용자 입력은 input() 해주면 된다. 리턴값은 입력받은 값이고, 매개변수로 문자열을 넣으면 콘솔에 "입력하세요: " 이런 문구로 사용된다. 무조건 문자열 타입 리턴

4.3 파일 읽고 쓰기

4.3.1 파일 스트림 열고 닫기

  • 아래 코드가 가장 일반적인 포맷이다. 즉 파일객체 = open(파일이름, 모드) 형태.

  • 모드는 r, w, a가 있고 순서대로 읽고, 쓰고, 추가한다. r+를 넣으면 read, write 둘 모두 된다.

    # 디렉토리에서 ~ 단축키는 안 먹힌다. 절대경로 쓰려면 다 적어줘야 함
    f = open("/Users/gyubin/Desktop/hi.txt", 'w')
    f.close()

4.3.2 읽기 함수

  • f.read() : 파일의 모든 데이터를 읽어온다. 모든 데이터를 읽어왔다면 다시 이 함수를 실행했을 때 빈 문자열 ""을 리턴한다.
  • f.read(int_value) : 숫자크기 만큼만 글자를 읽어온다. 3을 넣으면 3글자씩 읽어온다. 실행할 때마다 정한 크기만큼 글자를 읽어오고 모두 읽어왔을 때는 역시 빈 문자열 ""를 리턴한다.
  • f.readline() : \n이 발견될 때까지 개행문자를 포함해서 읽어온다. 즉 한 줄씩 읽어온다. 파일이 개행문자 없이 끝난다면 파일 끝까지 읽어들인다. 역시 파일 끝에 도달한 후에는 빈 문자열 ""이 리턴된다.
  • 쓸데없는 실험
    • 재밌는 현상 1: 만약 write 함수를 이용해서 f.write('hi\n') , f.write('hello\n') 이 두 명령어를 실행했다고 하자. 그리고 파일을 에디터로 열어보면 hi와 hello 딱 두 줄만 있다.
    • 재밌는 현상 2: 현상 1에 f.write('\n')이 추가로 실행한다면 세 번째 줄에 공백라인이 하나 더 있다.
    • 재밌는 현상 3: 에디터에서 바로 위의 예처럼 hi와 hello 딱 두 줄만 적고 저장해서 f.readline() 해보면 hello 뒤에는 \n 문자가 없이 나온다.
    • 재밌는 현상 4: 그런데 만약 현상 3에 추가로 한 줄을 띄워서 공백 라인을 하나 만든다면 hi\nhello\n이 됨은 물론 \n이라는 놈이 하나 또 나온다.
    • \n의 의미: '보여지는' 관점에서 개행문자의 의미는 에디터에서 개행문자를 기준으로 이전 문자열과 이후 문자열은 줄을 나눠서 보여라!는 의미다. 반대로 '입력하는' 관점에서 개행문자의 의미는 그 다음 줄부터 입력할 준비가 되었다!는 의미다.
    • 에디터에서 엔터키: 단순히 엔터키를 치기 전까지의 편집하던 줄 끝에 개행문자를 붙이는게 아니다. 엔터키를 친 이후 넘어간 라인의 끝에도 자동으로 개행문자를 붙인다. 즉 에디터에서 엔터키란 이전 라인, 이후라인 모두의 끝에 개행문자를 붙인다는 의미다.
    • 결론: 의미없다. 그냥 뭐가 다른지 궁금했을 뿐이다. 하나 정하자면 f.write을 통해 데이터를 입력할 때 에디터에서 마지막에 한 줄 공백라인을 보이고싶다면 파일 끝에 개행문자를 2개 넣어라. f.write('end of file\n\n'
  • for line in f: print(line, end="")
    • f 파일 객체에서 바로 반복문을 돌릴 수 있다. readline()처럼 개행문자까지 읽어들인다. 즉 한 줄씩 line 변수에 문자열로 할당된다.
    • readline()과 달리 콘솔에 출력하면 개행문자가 보이지 않는다. 보여지는 대신 에디터에서처럼 개행이 적용되어 출력된다. 그래서 개행문자가 연달아 입력되어있다면 공백 라인이 여러줄 출력되기도 한다.
    • print 함수가 기본적으로 개행을 하기 때문에 end=""를 적어줘서 중복되지 않게 해야 한다.
    • 가장 빠르고 효율적인 코드라고 공식문서에 적혀있다.

4.3.3 쓰기 함수

  • f.write(str_data): str_data에 들어있는 값을 파일에다가 쓴다. str_data는 문자열이어야 한다. 숫자거나 boolean이라면 에러난다. 리턴값은 쓰여진 문자열의 문자 개수다. "hi\n"을 입력했다면 3이 리턴된다.
  • JSON 파일로 저장하기!: 파이썬 데이터를 JSON으로 바꾸는 것을 serializing, JSON to Python Data를 deserializing이라고 한다.
    • import json
    • json.dumps(my_obj) : 괄호 안에 넣은 object를 serializing한 문자열을 리턴한다. 1은 '1''abc'는 "'abc'"[1, 2, 'abc']는 "[1, 2, 'abc']"로 바꿔준 값을 리턴하는 것. 결국 이 문자열을 파일 스트림을 쓰기모드로 my_json.json 이란 이름으로 열어서 쓰면 json 파일이 만들어지는 것이다.
    • json.dump(object, FILE) : s가 없어진 그냥 dump다. 매개변수로 저장할 객체와 쓰기 모드로 열린 파일 스트림 객체를 받는다. 이 코드를 실행하면 객체를 serializing한 문자열을 파일 스트림과 연결된 json 파일에 쓴다. 리턴값은 따로 없다.
    • [1, 2, 3]을 '[1, 2, 3]' 문자열로 바꿔서 파일에 쓰고, 파일을 에디터에서 열어보면 [1, 2, 3] 이라고 적혀있다.
    • my_var = json.load(FILE) : load 함수는 json 파일과 읽기 모드로 연결된 파일 객체를 매개변수로 받는다. 그리고 json 파일을 deserializing해서 데이터 객체로 만든 후 my_var 변수에 할당한다.
  • 즉 정리하면 "쓰기모드 파일객체 + json.dump"와 "읽기모드 파일객체 + json.load" 요렇게만 잘 쓰면 끝이다.

4.3.4 기타 관련 함수

  • with: 함수가 시작되면 파일이 열리고, 함수가 끝나면 파일이 닫힌다. 파일 객체는 빌트인 메소드로 __enter__() 와 __exit__()를 가지고 있다. 여기서 exit 메소드가 실행되면 파일 스트림이 닫히게된다. 이 메소드가 with에서 구현되어있다. 그래서 아래처럼 가능한 것.

    with open("foo.txt", "w") as f:
        f.write("Life is too short, you need python")
  • f.closed : 파일 객체인 f가 close 되었는지 확인할 수 있는 boolean 값이다. 닫혔으면 True를 리턴한다.

  • sys: 파일을 python으로 실행할 때 파일 외부에서 매개변수로 데이터를 받아올 수 있게 한다.

    • 예를 들어 아래 코드가 sys1.py 라는 파일이라면 python sys1.py 로 코드를 실행할 것이다. 여기서 python 명령어 다음에 오는 것이 매개변수다.
    • sys.argv는 이 매개변수들을 여러개 받아서 저장한 리스트다.
    • 'python sys1.py aaa bbb ccc' 라고 명령어를 터미널에서 실행하면 aaa bbb ccc가 출력될 것이다.
    • 아래 코드에선 2번째 원소부터 반복을 돌렸는데 첫 원소부터 돌리면 첫 번째 원소는 "sys1.py" 일 것이다.
    # 파일명: sys1.py, 명령어: python sys1.py aaa bbb ccc
    import sys
    args = sys.argv[1:] 
    for i in args: 
        print(i)
    # => aaa
    #    bbb
    #    ccc

5. 클래스

기본 구조는 다음과 같다.

class MyClass(ParentClass):
    <클래스 변수 1>
    <클래스 변수 2>
    ...
    def 클래스함수1(self[, 인수1, 인수2,,,]):
        <수행할 문장 1>
        <수행할 문장 2>
        ...
    def 클래스함수2(self[, 인수1, 인수2,,,]):
        <수행할 문장1>
        <수행할 문장2>
        ...
    ...
  • 클래스 내 로컬 함수를 정의할 땐 무조건 매개변수로 self 넣어줘야 한다. 인스턴스를 생성한 후 '인스턴스.함수' 형태로 함수를 실행하면 자동으로 매개변수로 self를 넣어주기 때문이다.

  • def __init__(self, *args): ~~ : init 함수는 생성자라고도 하며 인스턴스가 만들어질 때 항상 실행된다. self 무조건 들어감.

  • 클래스 상속은 뒤에 () 안에 상속받을 클래스를 적어주면 된다.

  • 연산자 오버로딩: 객체끼리 +, -, *, / 등의 연산을 할 수 있다.

    • 예를 들어 A라는 클래스에 __add__ 함수를 추가하면 + 연산이 가능하다.
    • A로 만든 a 객체가 앞에 있든 뒤에 있든 + 연산은 수행 가능하지만, self의 적용은 달라진다.
    • a + b 인 경우 self는 a이고, b + a인 경우에 self는 b이다. 두 객체 중 하나에만 add가 있으면 된다.
  • 변수 종류

    • global variable: 말 그대로 전역변수. 어느 위치에서도 호출 가능
    • member variable: init 함수 밖에서 선언된 변수. 결국 클래스 변수다. 클래스명.변수명 형태로 접근할 수 있다. 클래스에서도 호출할 수 있지만 인스턴스 변수 각각에서도 이 변수를 가지고 있어서 호출 가능하다. 즉 Hello 클래스에서 a, b 인스턴스를 만들었을 때 셋 모두 member variable을 갖고 있어서 다른 값을 설정할 수 있다. 웬만하면 사용하지말고 꼭 필요한 경우, 예를 들어 인스턴스 개수를 설정할 때 클래스의 멤버 변수만 활용하라고 말하는 사람들이 있다. 인스턴스에서는 웬만하면 호출하지 않는걸로.
    • instance variable: init 함수 안에서 선언된 변수. 만약 여기서 선언되지도 않고 대입되지 않았더라도 인스턴스.새로운인스턴스변수 = 값 형태로 적어주면 인스턴스에 변수가 추가된다.
    • 인스턴스 Namespace --> 클래스 Namespace --> Global Namespace 순서로 scope를 올려가며 변수를 찾는다.
    • 인스턴스 객체에서 클래스 멤버 변수로 접근하려면 myClass.__class__.classMember = 10처럼 __class__ 메소드를 활용한다.
  • 클래스의 함수를 method라고 한다. 일반 함수를 function

  • init 함수가 아니더라도 다른 함수에서 인스턴스 변수를 선언할 수 있다. init 함수가 실행되기 전엔 변수가 존재하지 않는다. 호출해도 없는 속성이라고 에러난다. AttributeError.

  • 클래스를 만들거면 웬만하면 object 클래스를 상속하자.

  • 클래스의 객체를 print했을 때 원하는 출력물을 지정하고 싶으면 __repr__ 메소드를 만들고 원하는 문자열을 return 하면 된다. 매개변수는 오직 self만.

    def __repr__(self):
        return "(%d, %d, %d)" % (self.x, self.y, self.z)
  • super: 아래 코드가 예시다. 부모 클래스의 메소드를 그대로 자식 클래스에서 쓰고 싶을 때 super를 쓴다. super(내클래스, self).메소드명(매개변수) 형태로 쓴다.

    class Employee(object):
        def __init__(self, employee_name):
            self.employee_name = employee_name
    
        def calculate_wage(self, hours):
            self.hours = hours
            return hours * 20.00
    
    class PartTimeEmployee(Employee):
        def calculate_wage(self, hours):
            self.hours = hours
            return hours * 12.00
        def full_time_wage(self, hours):
            return super(PartTimeEmployee, self).calculate_wage(hours)
    
    milton = PartTimeEmployee('Milton')
    print milton.full_time_wage(10)
  • 정적 메소드

    • 인스턴스를 통하지 않고 클래스를 통해 바로 메소드를 호출하기 위해 정적 메소드를 사용하게 된다. Python에서는 클래스의 정적 메소드를 구현하기 위해 다음과 같이 해당 메소드가 정적메소드임을 등록해야 한다.
    • Method Name = staticmethod(Method in Class)
    • 외부에서 호출 시에는 위의 Method Name으로 호출 하게 된다.
  • Private 멤버

    • Python에서는 문법적으로 클래스의 private 멤버를 지원하지 않는다. 대신 Name mangling을 이용하여 이와 유사한 기능을 수행하도록 할 수 있다.
    • 멤버 변수나 함수가 __로 시작하는 경우 외부에서 참조할 때는 자동으로 _클래스이름__멤버이름으로 변경하게 된다. 이로써 원래의 멤버이름으로는 접근 시 에러가 발생하게 되어 private 멤버 처럼 사용할 수 있게 된다. 당연히 클래스 내부에서 사용 시에는 멤버 변수 이름 그대로 사용 가능하다.
    class MyClass(parent):
        """ Class Document """
        __privateMember = 0
        def __init__(self):
            pass

6. 모듈

  • 함수 혹은 변수들로 이루어진 .py 확장자의 텍스트 파일이다.
  • abc.py라는 모듈 파일이 있다면 이 파일이 위치한 디렉토리에서 python 실행 후 import abc 하면 된다. 이렇게 모듈 파일 이름으로 단순하게 import하는것을 generic import라고 한다.
  • import abc 에서 import는 abc를 쓸 수 있게 해준다는 의미다. import 없이는 abc 라고 입력했을 때 선언되지 않은 변수라고 에러가 뜬다. 저 명령어를 쳐 줘야 abc가 의미를 갖는다.
  • abc 모듈에 AAA라는 함수가 있다고 할 때, import abc 했다고 그냥 바로 AAA 함수를 쓸 순 없다. abc.AAA라고 해야 한다. 앞에 abc를 생략하고 싶다면 from abc import AAA 라고 하면 바로 AAA 쓸 수 있다. 함수라면 뒤에 () 생략한다. 함수 이름만 써준다.
  • Universal Imports: from math import * 이렇게 하면된다. 썩 좋은 방법은 아님. 왜냐면 기본적으로 이미 import돼있는 수많은 변수나 함수가 존재한다. 근데 저렇게 math의 모든 것을 import 해버리면, 뭔가가 겹칠 수 있다. 같은 이름의 변수나 같은 이름의 함수들이. 좋은 방법이 아니다.
  • 만약 모듈에 함수나 변수만 덩그러니 있는게 아니라 실제 실행되는 명령어가 있다고 치자. 예를 들어 print문이 있다고 하면 import abc를 했을 때 그 코드들이 실행이 되게된다. import했을 때는 실행이 안되도록 하려면 if __name__ == "__main__": 이 if 블락 안에 실행문들을 넣으면 된다. 실제 python 명령어로 실행됐을 때만 실행 코드들이 동작하도록 만드는 조건이다.
  • 다른 모듈 사용할 때 import는 클래스 밖에서 사용한다.
    • vector.py 모듈과 모듈 내의 Vector class를 직접 만들었다고 하자.
    • 이 Vector 클래스는 norm이라는 메소드를 갖는데 이 메소드가 math 모듈의 sqrt 메소드를 사용한다.
    • 이럴 경우 import math를 클래스 내부에서 선언하면 norm 메소드가 동작하지 않는다. 클래서 definition 바깥에서 import 해줘야 한다.
  • 파이썬 모듈 저장 디렉토리 추가하기
    • 터미널에서 파이썬 repl을 실행한 후 import sys 한다. 그리고 sys.path를 입력해보면 리스트 형태로 경로들이 존재한다. 여기에 리스트이므로 append 함수로 경로를 문자열로 추가해주면 그 경로에 위치한 모듈은 바로 import해서 쓸 수 있다.
    • 혹은 터미널에서 set PYTHONPATH = C:\Python\Mymodules 형태로 지정해줄 수도 있다.

7. 2진수

  • 0b를 앞에 붙여주면 된다.

  • 2진수를 print 하면 10진수 형태로 출력된다.

  • bin(integers) : 정수를 매개변수로 받아서 문자열 형태인 2진수를 리턴한다.

  • oct(int)hex(int) : 8진수, 16진수로 바꾸는.

  • int(str_num, 자리수) : 첫 번째 매개변수는 문자열로 이루어진 숫자, 두 번째는 진법을 나타내는 숫자다.

    • 10이 디폴트값이고 2, 8, 16 등이 올 수 있다.
    • 진법 수는 2 이상 36 이하다.
    • 첫 번째 매개변수에 2, 8, 16진수를 나타내는 0b, 0o, 0x가 붙은 문자열이 들어올 수도 있다. 이 때는 이 진법에 맞춘 숫자가 두 번째 매개변수에 들어가야된다. 다른게 들어가면 에러난다.
  • shift 연산: operator 모듈의 lshiftrshift다. <<와 >>가 매칭된다.

    • lshift<<가 2배씩 커지는거고, rshift>>가 2배씩 작아지는 거다.
    • 하지만 항상 2배씩 변하는 것은 아니다. 예를 들어 0b0010 >> 2 하면 0이 되어버린다.
    • 오른쪽으로 1이 한 칸씩 가지만 끝에 도달하면 아예 사라지기 때문이다. 이 때문에 숫자 변화가 항상 1/2이 되는 것은 아니다.
  • bitmask: 예를 들어 오른쪽에서 3번째 자리수가 1인지 확인하고 싶다면 0b100과 검사하고싶은 수를 & 연산하면 된다. 결과가 0보다 크면 1인거고, 아니면 0인거다.

  • 원하는 비트 1로 만들기: 원하는 비트만 1인 수를 만들고 | 연산한다. 즉 오른쪽에서 세 번째 비트를 on하고 싶다. 그러면 0b100과 그 수를 | 연산하고 결과값을 쓰면 된다.

  • 비트를 다 뒤집고 싶다면: 원하는 수의 2진법 표현과 똑같은 자리수만큼 1로 채워서 ^ 연산하면 된다. 0b110101을 뒤집고싶으면 똑같은 자리수로 0b111111을 ^ 한다.

    def flip_bit(number, n):
        return bin(number ^ (0b1 << n-1))

8. 자주 쓸 것 같은 함수들

  • isalpha() : 문자열이 오로지 알파벳으로만 이루어져있는지
  • isdigit() : 문자열이 오로지 숫자로만 이루어져있는지
  • dir(math) : math 모듈에서 사용 가능한 모든 것을 리스트로 보여준다.
  • abs(-5), max(1,2,3), min(-4, -2, -10) : 절대값, 최대값, 최소값. 저렇게 단순한 콤마로 구분해서 여러 수를 넣을 수 있는 것은 콤마만 적으면 자동으로 튜플이 되기 때문이다.
  • type(something) : something의 타입을 리턴함.
  • import random
    • randint(low, high) 많이 쓰인다. low부터 high까지 임의의 정수 하나를 리턴한다. 중요한건 high 포함이고 둘 모두 정수여야 한다.
    • random.choice(iterable) : iterable에서 무작위로 원소 하나 리턴한다.
    • random.shuffle(iterable) : iterable을 무작위로 섞는다.
  • re 모듈에서 sub 함수가 있다. re.sub(pattern, replacement, string) 으로 쓰면 된다. 매개변수가 2개 더 있지만 저렇게만 자주 쓰일듯.
  • my_str.lower()my_str.upper()는 호출되는 대상을 바꾸지 않는다. 다시 대입해줘야.
  • filter(function, iterable) : iterable의 원소를 하나하나 빼내서 function에 적용한 후 리턴값이 True이면 리스트에 집어넣는다. 그리고 최종적으로 리스트를 리턴한다. Python2에선 리스트, Python3에선 필터 객체다.
  • map(func, iterable) : filter와 다르게 iterable의 원소 하나하나를 func에 대입해서 나온 결과값을 리턴 객체에 넣는다. 2에선 리스트, 3에선 맵 객체
  • locals() : 함수 내에서 실행하면 함수의 로컬 변수들을 딕셔너리 형태로 리턴한다.
  • all(iterable) : iterable 원소들이 모두 참인 경우 True 리턴한다.
  • any(iterable) : 참인 원소가 하나라도 있으면 True
  • chr(아스키코드값) : 아스키코드값을 받아서 문자로 리턴한다. ord 는 그 반대다.
  • divmod(7, 3) : 7을 3으로 나눈 몫과 나머지를 튜플로 리턴한다.
  • eval('1+2') : 실행 가능한 함수나 수식 등을 문자열로 받아서 결과값을 리턴한다. 이 코드는 3을 리턴한다. eval('divmod(7,3)') -> (2, 1)
  • repr(object) : 객체를 출력 가능한 문자열로 변환해서 리턴한다. 예를들어 repr('hi'.upper()) -> "'HI'"
  • lambda : 이름 없는 함수이며 주로 간단한 함수식을 표현할 때 쓴다. lambda 인수1, 인수2, ... : 인수를 이용한 표현식으로 나타낸다. 인수를 이용한 표현식 부분이 자동으로 리턴된다.
  • id(object) : 주소값 리턴
  • sortedziptype도 기억.
  • import os
    • os.environ: 시스템 환경변수값을 딕셔너리 객체로 리턴
    • os.chdir: 디렉토리 변경
    • os.getcwd: 현재 디렉토리 문자열 리턴
    • os.system("명령어"): 터미널에서 명령어 실행한 결과값 리턴
    • os.mkdir(디렉토리명): 디렉토리를 생성한다.
    • os.rmdir(디렉토리): 비어있는 디렉토리 삭제
    • os.unlink(파일): 파일 삭제
    • os.rename(src, dst): src 파일을 dst로 이름 변경
  • import webbrowser: 브라우저에서 URL을 연다.
    • webbrowser.open("URL")
    • webbrowser.open_new("URL")
  • import shutil -> shutil.copy("src.txt", "dst.txt") 파일 카피다. 만약 목표 디렉토리에 같은 이름의 파일이 있다면 덮어쓴다.
  • import glob -> glob.glob("/users/gyubin/dev/Q*") 지정 디렉토리의 파일명을 리스트화한다. Q*는 q로 시작하는 파일들만으로 한정한 것.
  • import tempfile 임시파일 관련 모듈이다.

9. 예외처리

9.1 에러 처리 기본

try: 
    f.open('wow.txt', 'r')
except [발생에러[as 에러메시지변수]]: # []는 생략해도 된다는 의미
    pass  # 에러 나든 말든 넘기고 싶으면 pass
else:
    pass
finally:
    f.close()
  • 에러가 날 수 있는 코드를 try에 넣고, 에러가 났을 때 처리를 except에 넣는다. 에러가 발생하지 않았을 경우 실행되는 코드는 else안에 둔다. finally는 에러가 나든 안나든 무조건 실행해주는 코드로 주로 파일 스트림 객체를 닫는데 쓰인다.
  • []는 생략해도 된다는 의미다. 그냥 except만 적어도 되고, 에러를 명시해줘도 되고, 그 에러를 내 입맛에 맞게 바꿔불러도 된다.
try:
    4 / 0 
except ZeroDivisionError as e: 
    print(e)
# => 출력: division by zero

9.2 에러 일으키기 raise

다음은 Bird 클래스를 상속하는 자식 클래스는 무조건 fly 메소드를 오버라이드 해야한다는 의미의 코드다.

class Bird:
    def fly(self):
        raise NotImplementedError

class Eagle(Bird):
    pass

eagle = Eagle()
eagle.fly()

class Eagle(Bird):
    def fly(self):
        print("very fast")

eagle = Eagle()
eagle.fly()

10. 패키지

10.1 기본

복잡한 혹은 큰 규모의 파이썬 프로그램이라면 패키지를 만들어서 관리하는게 유용하다. 예를 들어 다음과 같은 구조가 있다. 아래 패키지에서 echo.py 모듈을 사용하려면

game/
    __init__.py
    sound/
        __init__.py
        echo.py
        wav.py
    graphic/
        __init__.py
        screen.py
        render.py
    play/
        __init__.py
        run.py
        test.py
  • (O) import game.sound.echo -> game.sound.echo.echo_test()
  • (O) from game.sound import echo -> echo.echo_test()
  • (O) from game.sound.echo import echo_test -> echo_test()
  • (-) import game -> 디렉토리를 import하면 game 디렉토리의 __init__.py의 내용만 참조 가능
  • (X) import game.sound.echo.echo_test 이건 에러난다. 이렇게 .으로 구분해서 디렉토리의 모듈을 import할 땐 마지막에 무조건 패키지나 모듈이 되어야 한다. 저렇게 함수가 들어가면 안된다.

하지만 디렉토리 자체를 import할 순 없다. 예를 들어 import game 한 후에 from game.sound.echo import echo_test 사용은 불가하다. 이렇게 디렉토리를 import 하는 경우는 __init__.py의 내용만 가져온다.

10.2 __init__.py에 대하여

해당 디렉토리가 패키지의 일부라는 것을 나타내주는 것이다. 이거 없이 패키지를 import하면 에러난다. 파이썬3에선 없어도 되는걸로 바뀌었지만 그래도 하위호환성을 위해 해주는게 좋다. 이 안에 all같은 필요한 몇가지 요소들을 적어준다.

10.3 __all__

from game.sound import * 이렇게 코드를 짜면 sound 패키지의 모든 모듈을 import한다는 의미다. 이 때 __init__.py에 __all__ 이 있어야 정상적으로 작동한다. __all__ = ['echo'] 이렇게 리스트 안에 모듈명을 문자열로 집어넣어주면 된다.

물론 from에서 마지막이 패키지로 끝나는 경우에 위의 작업이 필요한것이지 만약 from에서 마지막이 모듈로 끝난다면 그냥 import * 해도 속한 모든 메소드들이 호출 가능해진다. 하지만 이는 좋은 방법이 아니다.

'파이썬' 카테고리의 다른 글

파이참(pycharm) 단축키 정리  (0) 2021.09.15
정규표현식(Regular Expression)  (0) 2018.04.09
Jupyter Notebook이란?  (0) 2018.04.03
iterator, generator 사용법  (0) 2018.04.03
decorator(wrapper) 사용법  (0) 2018.04.03