Naver Ai Boostcamp

[DAY 2] 파이썬 기초 문법

잡담연구소 2021. 1. 19. 23:17

학습정리

Variables & Memory 

변수는 잘 알지만 변수가 저장되는 메모리 를 잘 모르므로 여기에 집중해서 학습

  • 변수 : 값을 저장하는 장소 
    변수는 메모리 주소를 가지고 있고, 값은 메모리 주소(물리적인 주소)에 할당됨. 
    app에서 a=3 이런 식으로 입력을 한다면 cpu 메모리 어딘가 (변수 a의 메모리 주소에 해당하는 곳 ) 에 3이 할당됨
  • " a = 8 " 이라고 선언 되는 순간 메모리 특정영역에 물리적인 공간이 할당됨. 
    "a는 8이다" 라고 이해하지말고 a라는 이름을 가진 메모리 주소에 8을 저장하라 라는 뜻 
    파이썬(앱)이 os에 a라는 메모리 공간을 잡아달라 요청했고, os가 a라는 메모리에 8을 저장해주었다. 

https://m.blog.naver.com/PostView.nhn?blogId=sarang2594&logNo=221249066921&categoryNo=27&proxyReferer=https:%2F%2Fwww.google.com%2F

👉 0X005 라는 메모리주소에 "Audrey"라는 값이 할당 됨. 

    Audrey 값을 가져다 쓰고싶을 때 마다 메모리 주소를 불러오는 건 너무 어렵고 또 복잡하다. (이름부터 복잡,,,)

    그래서 변수라는 걸 통해서 내가 아는 쉬운 단어로 메모리 주소에 저장된 audrey 값을 불러 쓸 수 있는 것

 

  • 변수명 설정 : 줄임말 보다는 누구나 이해할 수 있는 대표적인 변수로 설정하는 것이 바람직함. 
    👉 귀찮아서 a,b 이렇게 변수를 설정하지말고, 남이 내 코드를 봤을 때 직관적으로 이해할 수 있 변수이름을 잘 지어주자.
           띄어쓰기가 필요한 경우 _ 언더스코어로 대체

 

📌 기본 자료형 및 연산자 

1. 기본 자료형

  •  Data type마다 차지하는 메모리의 크기가 달라진다. 
  • 파이썬의 가장 큰 장점 : 동적 타이핑!
    : 코드 실행시점에 따라 daya type을 결정
    컴파일러 언어와 다르게 인터프리터 언어는 변수형을 미리 설정해주지 않아도 되기때문에 실행하는 순간 메모리를 잡기때문에 컴파일러 언어보다 느릴 수 밖에 없다.

2. 기본 연산자

  • a = a + 1 해석해보기
    좌변의 a는 저장되는 공간 , 우변의 a는 변수의 값을 가져오는 역할
    같은 변수 a여도 위치한 곳에 따라 역할이 달라짐
  •  int()와 같은 데이터의 형변환 

      float()를 통해서 잠시! 소수형으로 출력될 뿐 a자체의 변수형이 바뀌는 것은 아니다. 

  • 단순한 실수도 이진수로 변환하면 무한 소수가 되는 문제점 때문에 컴퓨터는 float를 힘들어한다 

 

📌 list  (인덱싱, 슬라이싱, 리스트연산, 추가삭제 , 메모리 저장 방식, 패킹과 언패킹, 이차원리스트 )

1. 인덱싱(indexing)

  • list에 있는 값들은 주소 (offset) 들을 가짐

2. 슬라이싱(slicing)

  • 주소 값을 기반으로 부분값 반환 (진짜로 리스트가 잘리는 게 아님)
  • 리스트의 길이보다 더 크게 슬라이싱을 하더라도 문제 없이 돌아간다! 그냥 끝까지 출력해줄 뿐 
    범위를 넘어갈 경우 자동으로 최대범위를 지정해준다. 
ls = ['a','b','c','d','e']
ls[4: 8]
// 결과 값 ['e']
  • 리스트[시작인덱스(포함o) : 끝 인덱스(포함x) :  step(음수도 가능 )] 
ls = ['a','b','c','d','e']
ls[::2]
// 결과 값 ['a' , 'c' , 'e']

3. 리스트의 연산

  • 리스트끼리 덧셈 연산 가능 

4. 리스트의 추가 및 삭제 

  • append와 extend 의 차이 
  • remove와 del 차이 

5. 메모리 저장 방식 ✨✨✨👀

  • 다양한 data type이 하나의 list에 들어감 (C++에서는 불가능했던 거 같다.)
    위의 사진처럼 리스트 안에 리스트도 들어갈 수 있음. 
  • "="의 의미는 같다가 아닌 메모리 주소에 해당 값을 할당한다는 의미 
    b = a 선언시 b는 a가 가르키는 메모리를 가르키게 됨. (메모리 주소 참조)
    a와 b의 리스트 원소들이 모두 같을 떄, 이런 현상이 일어나는 것이 아니라 a = b 와 같이 선언을 해줘야 메모리 주소가 바뀜.
a = [5,4,3,2,1]
b = [1,2,3,4,5]
// 이때는 a와 b 둘 다 서로 다른 메모리를 가지고 있다. 
b = a 
//선언하는 순간!!!!!!!!!!!!! b는 a의 메모리를 가르키게 된다. 
// a가 변하면 이제 b도 같이 변함 
a.sort()
print(b)
//[1,2,3,4,5]
// b가 다른 메모리를 가르키게 만드려면? 재할당해줄 수 밖에! 
b = [1,2,100,4,5]

a,b의 원소가 같아도 a,b는 각각 다른 메모리 할당

  • b에 a를 복사해오고 싶지만, 메모리는 따로 가지고싶다? -> b = a[:] 

6. 패킹과 언패킹 

7. 이차원 리스트 ✨✨✨👀

  • 이차원 리스트를 복사하는 방법은 ? 
    일차원 리스트와 같이 list[:] 방식으로는 copy ❌ , 그냥 메모리가 참조됨
  • 그럼 how? 
    copy 모듈을 불러와 deepcopy를 해준다.

 

Function and Console I/0

📌 Function

  • 코드를 논리적인 단위로 분리 
    코드 = 하나의 보고서 그렇기 때문에 코드를 잘 나눠놔야 보는 사람이 잘 이해할 수 있다. 
  • 이걸 캡슐화! 라고 함 인터페이스만 알면 타인의 코드를 잘 이해하고 사용할 수 있다. 
  • 함수 수행 순서 
     - 함수 부분을 제외한 메인 프로그램부터 시작하기때문에 함수는 상단에 적어주는 게 좋다. 
     - 함수 호출 시 함수 부분을 수행한 후 되돌아온다. 
  • parameter : 함수의 입력 값 인터페이스 def f(x) 에서 x같은 거 
    argument : 실제 parameter에 대입된 값 f(2) 에서 2 같은 거 
  • parameter 유무 & 반환 값 유무에 따라 함수의 형태가 다름  
      parameter 없음  parameter 있음 
    반환 값 없음  함수 내의 수행문만 수행  parameter를 사용, 수행문 수행
    반환 값 존재 parameter 없이, 수행 후 결과값 반환 parameter를 사용해 수행문 수행 후 결과값 반환 
  • 출력된 값과 반환된 값을 착각하지 말자! 
    아래 함수는 반환 값이 없다. 그냥 출력만 해줄 뿐 
    c = 20이라고 출력은 되지만, c값에 20이 할당 된 것은 아니다. 

 

📌 Console I/O

어떻게 프로그램과 데이터를 주고 받을 것인가?

  • print 
     - type 이 다른 값들을 연속해서 출력하고싶다? -> , 콤마를 사용 (대신 한 칸 씩 띄어지며 출력됨)
    - 한칸 씩 띄어지는 게 마음에 안들면 ? 형변환 해서 type을 통일한 후 + 사용 

print formatting : 형식에 맞춰 출력을 해보자. 

  • %string , format 함수 , fstring 
#1. %f- format
number = 3 
day = 5 
print("I eat %d apples for %d days"%(number , day))

#2.str.format()
print('I am {} and {} years old'.format('hyerin', 23))
print('I am {1} and {0} years old'.format('hyerin', 23))
print('I am {0} and {1:10.2f} years old'.format('hyerin', 23))
## {1:10.2f} 같은 경우 1 뒤에 띄어쓰기 후 : 를 쓰면 안됨 
print('I am {0:<10s} and {1:10.2f} years old'.format('hyerin', 23))

#3.fstring
name = 'Hyerin'
age = 23
print(f'hello {name}. are you {age}?')
print(f'{name:*>20}')
### 20자리에 name을 쓰고 왼쪽은 *로 채우라는 뜻 

 

📌 Lab 화씨 변환기 

- 어렵지 않더라도 파이썬에 익숙해지기 위해서 Lab 실습해보자. 

def cal(t):
    return 9 * t / 5 + 32
print("본 프로그램은 섭씨를 화씨로 변환해주는 프로그램입니다.\n변환하고 싶은 섭씨 온도를 입력해주세요.")
temp = float(input())
print(f"섭씨온도 : {temp}")
print(f"화씨온도 : {cal(temp):.2f}")

 

 Conditionals and Loops

📌 Lab 조건문 

print("당신이 태어난 년도를 입력하세요")
years = int(input())
age = 2021 - years + 1 
if (age >=20) : print("대학생")
elif (age >= 17) :print("고등학생")
elif (age>= 14 ): print("중학생")
elif (age >=8) :print("초등학생")
else : print("학생이 아닙니다.")
  • 삼항연산자 
    : 참인 경우 값 if 조건 else 거짓인 경우의 값 
    c++과 달라서 한참 애먹은 부분,,,, 조건 ? true :  false와 다르다 ㅜㅜ

 

📌 Lab 반복문 

print("구구단 몇 단을 계산할까요?")
num = int(input())
print(f"구구단 {num}단을 계산합니다.")
for i in range(1,10):
    print(f"{num} X {i} = {num* i}")
    
  • loop을 review하며 잘돌아가고 있는지 확인해주면 더 용이하다.

 

📌loop & control lab 

import random
answer = random.randint(1,100)
print("숫자를 맞춰보세요(1~100)")
while(True) : 
    num = int(input())
    if (num > answer) : print("숫자가 너무 큽니다.")
    elif (num < answer) : print("숫자가 너무 작습니다.")
    else : 
        print(f"정답입니다. 입력한 숫자는 {answer}입니다.")
        break
print("구구단 몇 단을 계산할까요(1~9)?")
num = int(input())
while num >0 and num < 10 :
    print(f"구구단 {num}단을 계산합니다.")
    for i in range(1,10):
        print(f"{num} X {i} = {num*i}")
    print("구구단 몇 단을 계산할까요(1~9)?")
    num = int(input())   
if (num < 1 or num > 9) :
    print("0 \n구구단 게임을 종료합니다.")

👉 while True로 쓸 경우 무한 루프에 빠질 위험이 있기때문에 권장하지않음.

 

📌 Debugging

문법적 에러와 논리적 에러 두가지 

  • 문법적 에러 : 인터프리터를 잘 해석해보면 보인다. 직접 디버깅을 해보며 메세지를 접해보고 해결해보자. 
  • 논리적 에러 : loop review 처럼 중간중간 print를 하며 코드를 확인 

❓ if __ name__  == "__main__" : main() 왜 써?

 이게 없다면 py를 불러오지 않고 import를 하기만 해도 실행이 됨. 이런 일을 방지하고자 if__name__사용 

 

 

 String and advanced function concept 

📌 문자형 (string)

  • 시퀀스 데이터로 글자 하나당 1byte를 차지 
  • 리스트와 같은 형태로 데이터를 처리 
  • .split() : 띄어쓰기 기준으로 문자를 잘라서 리스트 형태로 반환
  • isdigit : 정수인지 확인해 T/F로 반환
  • 작은 따옴표를 출력하고싶으면 \' 표시 
  • raw_string = 앞에 r을 쓰면 \n이 출력됨

 

📌 함수 호출 방식 개요 

1. call by value

  • 함수에 인자를 넘길 때 값만 넘김
  • 인자 값 변경 시, 호출자에게 영향 x 

2. call by reference

  • 함수에 인자를 넘길 때, 메모리 주소를 넘김  -> C의 포인터 같ㅌ은 느낌
  • 함수 내에 인자 값 변경 시 , 호출자의 값도 변경

3. call by object reference (파이썬 함수 호출 방식 ) 👀✨

  • 객체의 주소가 함수로 전달되는 방식 
  • 전달 된 객체를 참조 및 변경 -> 영향  BUT 새로운 객체를 만든 경우 ->   영향X
def spam(eggs)  : 
    eggs.append(1)
    eggs = [2,3]
    print(f"changed eggs : {eggs}")

ham = [0]
spam(ham)
print(ham)

# 결과값
# changed eggs : [2, 3]
# [0, 1]

 

  • call by object reference의 대표적인 예 : swap
def swap_offset(x,y):
    temp = ex[x]
    ex[x] = ex[y]
    ex[y] = temp

def swap_reference(lst,x,y):
    temp = lst[x]
    lst[x] = lst[y] 
    lst[y] = temp


ex = [1,2,3,4,5]
ex1 = [1,2,3,4,5]

swap_offset(1,2)
print(ex)
#[1, 3, 2, 4, 5]
swap_reference(ex1 , 1 , 2)
print(ex1)
#[1, 3, 2, 4, 5]
  • swap_offset : 리스트의 전역 변수 값을 직접 변경 
  • swap_reference : 리스트 객체의 주소 값을 받아 값을 변경 -> 권장 또한 리스트를 복사해서 사용하는 것 권장 

 

📌 scoping rules 

  • 함수 내에서 재할당 해주면 새로운 주소값을 가지게 됨 
  • 전역변수는 함수에서 사용가능 , 전역변수와 같은 이름을 가진 변수를 함수내에 작성 -> 둘은 메모리주소부터가 다름 
  • 함수 내에서 전역변수 사용 시 global 키워드 사용 
    * global 키워드 사용 후 재할당 해주면 주소값 동일 

 

📌 function type hints & docstring 

사용자 (타인) 가 interface를 쉽게 알게 해줌 -> 남이 내 코드를 읽을 때 더욱 잘 이해할 수 있도록 도와줌 (필요!)

  • function type hints : 파라미터의 변수형과 반환값의 data type을 미리 써주면 사용자가 나의 코드를 더 쉽게 읽을 수 있다. 

  • docstring : 세개의 따옴표로 함수에 대한 상세스펙을 사전에 작성 
  • 목적 , 파라미터 설명 , return값 설명 
  • DOCSTRING GENERATOR 설치 -> 함수 내에서 ctrl + shift + p + docstring 저절로 description 의 큰 틀이 생성됨. 

 

📌 함수 작성 가이드라인 

  • 최대한 짧게! 여러 개! 목적에 맞게 쪼개자!
  • 함수 명은 함수의 역할, 의도가 잘 드러나게 보통 (00을 00한다와 같이 목적어와 동사가 들어감 )
  • 하나의 함수에는 유사한 것들로만 구성 
  • 인자로 받은 값 자체를 바꾸지 말 것 -> 복사를 통해 임시변수 생성
  • 공통 코드는 함수로 ! 
  • 복잡한 수식과 조건은 함수로!
  • 코딩은 팀플이다! 사람이 이해할 수 있는 코드를 짜자! 
  • black 이라는 모듈 사용 ->알아서 적절히 수정해줌

 

 

피어세션 정리 

수업내용에 대한 질의응답. 

  • if __name__ == main 은 왜 쓰는가?
     - 교수님께서 말씀해주신 거 외에 다른 기능이 있는지 궁금했는데 별도의 기능은 없는 거 같다. 
        위의 문구가 없으면 파일을 import 해오는 거 만으로도 py파일을 실행시켜버린다. 
        실행하지 않고 py파일을 import만 해오고 싶은 경우가 있을 수도 있기에 관례처럼 적어주자!
  • global 말고 nonlocal ! 
    - 함수 내 함수가 존재하는 경우 상위함수의 변수를 사용하고싶은 경우 nonlocal을 사용해보자. 

 

과제를 하면서 느낀 점 

  • 오랜 기간 c++만 했더니 파이썬이 익숙하지가 않다. 최대한 많이 익히고, 내장함수 잘 사용해보기 
  • 리스트는 값 자체를 바꾸지 않고 복사 또는 sorted를 새로운 변수로 할당하여 사용!
    -> 했더니 자꾸 지저분하게 길어진다.... 남의 코드를 참고해보자. 
  • 함수명은 함수의 특징이 잘 드러나도록 no_blank_list 처럼 짜기
  • baseball 같은 경우 예외처리? 다시 반복문으로 돌아가야하는 경우가 많아서 짜는데 오래걸렸다 
    -> 처음부터 알고리즘?설계도? 등을 크게 그려보고 코드를 짜는 건 어떨까
  • split 과 join  : 특정 공백을 지우고 다시 문장으로 만들 때 " ". join(str.split()) 유용