학습정리
Variables & Memory
변수는 잘 알지만 변수가 저장되는 메모리 를 잘 모르므로 여기에 집중해서 학습
- 변수 : 값을 저장하는 장소
변수는 메모리 주소를 가지고 있고, 값은 메모리 주소(물리적인 주소)에 할당됨.
app에서 a=3 이런 식으로 입력을 한다면 cpu 메모리 어딘가 (변수 a의 메모리 주소에 해당하는 곳 ) 에 3이 할당됨 - " a = 8 " 이라고 선언 되는 순간 메모리 특정영역에 물리적인 공간이 할당됨.
"a는 8이다" 라고 이해하지말고 a라는 이름을 가진 메모리 주소에 8을 저장하라 라는 뜻
파이썬(앱)이 os에 a라는 메모리 공간을 잡아달라 요청했고, os가 a라는 메모리에 8을 저장해주었다.
👉 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]
- 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()) 유용
'Naver Ai Boostcamp' 카테고리의 다른 글
[DAY 6] Numpy / 벡터 / 행렬 (0) | 2021.01.26 |
---|---|
[DAY 5] 파이썬으로 데이터 다루기 (0) | 2021.01.23 |
[DAY 4] 파이썬 기초 문법 III (1) | 2021.01.21 |
[DAY 3] 파이썬 기초 문법 II (0) | 2021.01.20 |
[DAY 1] 파이썬/AI 개발환경 준비하기 (0) | 2021.01.18 |