오늘 하루도 힘내서 하루를 시작해 보자
GIT교육을 마저 진행을 해보도록 하겠습니다.
엇갈린 작업
rebase
merge
git pull --rebase
그냥 pull만 썼을 때는?
원격저장소 거부! (Remote Rejected!)
규모가 큰 개발팀에서 일하는 경우, 보통 원격저장소의 main 브랜치는 잠겨있습니다(locked). 그래서 변경사항을 적용하려면 pull request 과정을 거쳐야 하죠. 만약에 여러분이 로컬 저장소의 main브랜치에서 커밋을 한 후 push하려고 시도한다면, 다음과 같은 오류를 받게 될 겁니다. :
! [remote rejected] main -> main (TF402455: Pushes to this branch are not permitted; you must use a pull request to update this branch.)
리모트 거부 대부분의 main은 잠금이 걸려 있기 때문에 로컬로 가져와서 한다.
왜 거부 되었나?
원격 저장소는 자신의 main 브랜치에 대한 직접적인 커밋을 제한합니다. 왜냐하면 push 대신에 pull request가 쓰여야 한다는 규칙이 원격 저장소의 main 브랜치에는 적용되어 있기 때문이죠.
여러분은 브랜치를 따로 만들어 작업한 다음, 그것을 push하고 pull request를 하려 했습니다. 하지만 그걸 잊고 실수로 main 브랜치에서 직접 커밋을 해버렸네요! 이제 변경 사항을 push 하지도 못하고 옴짝달싹 못하는 상황이 되어버렸습니다.
해결방법은?
feature라는 이름의 다른 브랜치를 만들어 원격 저장소에 push 하세요. 그리고 원격 저장소와 동기화될 수 있도록 로컬 저장소의 main 브랜치를 reset 하세요. 그렇지 않으면 여러분이 다음에 pull을 시도할 때 문제가 발생하거나, 다른 협업자들의 커밋이 여러분의 커밋과 충돌할 수도 있습니다.
순서에 맞추어 알맞은 명령문을 사용해서 만들어 주면!
짜잔 하고 나옵니다^^
feature 브랜치 병합하기
문제를 풀어 봅시다!
목표를 봤을 때 먼저 원격에 있는 c8을 가져와야 할 것 같고
그 밑으로 side1을 rebase 하고 그 밑에 side2.... side3을 순서대로 rebase 해주고
main 브랜치를 c7'로 이동을 시켜준 다음에 push를 해주면 될 것 같다.
짠 내 생각대로 만들어졌다
하지만 뭔가 단축할 만한 방법이 있다고 하는데..
정답은 여기였다
굳이 git branch를 할 필요 없이 rebase를 main에 해주면 checkout이 main에 붙으므로
2번 작업을 하나로 줄일 수 있다.
왜 merge 하지 않는 거죠?
merge와 rebase의 기능은 서로 비슷하지만 왜 rebase를 선호하는가?
문장을 이해 보자면
커밋트리가 깔끔하게 정리되었으면 하는 사람들은 rebase를 선호하고
만들어진 이력을 중요시하는 사람들은 merge를 사용하는 것을 선호한다고 볼 수 있다.
문제 풀이
rebase를 했던 들을 merge으로 만들어 보자
먼저 fetch로 원격에서 받아온 다음에
각 side와 merge를 해준다
그다음에 push를 해주면 된다고 생각했다.
merge의 단점이 checkout이 따라오지 않아서 마지막에 main을 가져오는 것에 손이 갔다.
해설지를 보면?
pull이 fatch와 merge인 것을 이용하여 main에 checkout을 하여 한번에 할 수 있다는 것을 알았다.
이렇게 배우면 배울수록 느껴지는 것이
checkout이 어디에 되어 있는지가 엄청 중요하다는 것을 알 수 있다.
원격-추적 브랜치
체크아웃을 만들 때 뒤에 원격 브랜치 위치를 추가로 넣어주면 추적하는 브랜치를 만들 수 있다.
위 두 가지를 보았을 때 기존에 방식대로만 push 또는 pull을 하면 그 사용하는 브랜치 명(현재:foo)으로
원격 브랜치가 생성이 되어서 원격저장소에 만들어질 것인데
checkout를 o/main에 추적시켜 주었기 때문에 foo의 작업을 원격에서는 main이 받아들여서 할 수 있게 된다고
보면 될 것 같다.
방법 #2
checkout이 아닌 branch에서도 이렇게 추적을 할 수 있는 방법이 있다.
checkout이랑 적는 순서가 다르니 잘 기억을 해두어야 한다.
문제 풀이
브랜치를 만들고 o/main이랑 추적을 시킨 다음에 커밋을 만들고
fetch를 해서 원격에서 받아 온다음
그 밑으로 rebase를 해서 다시 push를 해서 넣어주면 끝~!
정답은 맞혔지만 조금 더 간단한 방법이 있다,..
pull --rebase를 하게 되면 원해는 fatch 후에 merge를 하지만 --rebase를 붙여줌으로써
merge대신 rebase를 실행시켜 주는 것이다.
다른 방법으로 branch -u를 사용하는 방법이다.
git branch -u를 사용하려면 기본에 브랜치가 존재를 해야 하므로
기본에 브랜치가 존재를 했다면 branch -u
새로운 브랜치를 만들어서 추적을 하려면? checkout -b을 사용하는 것이 좋아 보인다.
Push의 인자들
이 말인즉슨 내가 지금 체크아웃하고 있는 위치에 상관없이 어디든지 내가 원하는 브랜치의 push를 해줄 수 있다는 것이다.
만약 그냥 push를 한다면??
문제 풀이
쉽게 풀 수 있었다.
<place> 인자에 대한 세부사항들
그러니깐 다시 보면 git push origin 다음에 오는 게 내가 옮기고 싶은 위치 까지를 정하고
그다음에 원격으로 밀어 넣고 싶은 브랜치를 넣어주는 것인 거 같다.
원격에서 새로운 브랜치를 만들고 main이 있는 위치까지 push를 시켜준다.
문제풀이
어렵게 생각할 필요 없이 목표를 보면 main의 위치는 c4에 있고 foo의 위치는 c5에 있으므로
git push origin c4:main
git push origin c5:foo
라고 해주면 간단하게 끝이 난다.
Git fetch 인자들
앞에서 했던 방법을 반대로 원격에서 위치를 맘대로 정하여서 로컬에 반영을 시키는 법이다.
기존에 있는 나의 로컬은 가만히 두고 원격에서 foo의 위치만 그대로 가져오는 것이라고 보면 될 것 같다.
원격은 변화가 없이 c2번만 가져오고 가져온 곳에 bar브랜치를 옮겨준다.
bar 브랜치가 없는 경우에도??
생성하고 만들어준다.
지정을 해주지 않는다면??
모든 브랜치를 가져오게 된다
문제풀이
파이썬 심화 교육
가상 환경(virtual environment)
가상 환경 구축하기
가상 환경 활성화 하기
가상환경 구축하기
내 컴퓨터상에 문제가 있는지 강의 상에서는
-m venv venv로 폴더를 생성하고
venv\Scripts\acrtivate로 바로 실행이 가능했는데
내 컴퓨터에서는 실행이 되지 않았습니다.
매니전님께 문제를 해결 받은 결과
경로 앞에 source를 넣어주니 가상환경이 작동을 하는 것을 확인할 수 있었습니다.
※ 명령어 없이 추가 설정 팁 ※
코드 컨벤션
코드 컨벤션이란 우리가 글을 쓸 때 가독성이 좋기 위해서 글 적는 방법으로 원고지를 써서
적어야 할부분에 맞추어 글을 적고 띄워야 할 부분을 띄워서 같은 작업을 하는 사람들이
다른 사람의 작업을 볼 때 이해 하기 쉽게 하기 위해서 만든 것이랑 비슷하다고 볼 수 있다.
이처럼 파이썬에서도 글을 적는 방법을 공통으로 맞추기 위한 일종의 형식을 배포해 주는데
그중 하나가 pep8이다
https://peps.python.org/pep-0008/
이렇게 사이트도 있으니 한번 확인해 보는 것도 좋은 방법이다.
파이썬 네이밍 컨벤션
클래스의 명을 정할 때는 띄어 쓰는 것보다는 아래의 방식을 이용하는데.
pascal은 모든 단어의 첫 글자는 대문자.
Camel은 맨 첫 글자만 소문자 나머지는 pascal이랑 동일하다
변수나 함수의 명을 설정할 때 이름 짓는 법은
Snake는 띄어쓰기를 _로 표기한다.
기본 중에 기본이라 맞춤법을 맞춘다고 생각하고 하자
예외도 있다
※좋은 확장 프로그램
파이썬 코드 컨밴션에 맞추어 띄어쓰기 들여 쓰기를 자동으로 해준다.
기능을 이용하기 위해서 설정에 들어가서
format save를 검색하여 나온 빨간 박스에 체크를 해주면
항상 저장할 때 컨밴션에 맞추어주도록 할 수 있다.
변수 유효 범위
지역 변수, 전역 변수
변수 a는 함수 안에서만 사용가능하기 때문에 함수밖을 벗어나면 변수가 사라진다.
자주 사용되는 모듈 및 패턴
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'>
split() / string을 list로 변환하기
# split은 string.split("구분자")로 구성되어 있습니다.
string = "hello/python/world!!"
string_list = string.split("/") # split() 안에 들어간 값을 기준으로 문자를 나눈다.
print(string_list) # ['hello', 'python', 'world!!']
join() / list를 string으로 변환하기
# 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() / 코드 예쁘게 출력하기 (from pprint import pprint 입력 필수)
# pprint는 pretty print의 약자이며, 데이터를 더 예쁘게 출력해 줍니다.
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"}
]
}
pprint(sample_data) # print로 출력했을 때와 결과 비교해 보기!!
random / 랜덤 한 로직이 필요할 때 (import 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 입력 필수)
import time
start_time = time.time() # 현재 시간 저장
time.sleep(1) # 1초간 대기
end_time = time.time()
# 코드가 종료된 시간 - 코드가 시작된 시간으로 실행 시간 구하기 (단위 : 초)
print(f"코드 실행 시간 : {end_time-start_time:.5f}") # 코드 실행 시간 : 1.00100
{end_time-start_time:. 5f}. 5f는 소수점 다섯째 자리 까지라는 뜻
datetime / 날짜 다루기 (from datetime import datetime, timedelta 입력 필수)
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
조건문 심화
조건문 부등호
'''== : 값이 일치하는지 비교'''
"a" == "a" # True
"a" == "b" # False
1 == "1" # False, 값은 동일하지만 자료형이 다르기 때문
'''!= : 값이 일치하지 않는지 비교'''
0 != 1 # True
0 != 0 # False
'''>, < : 값이 큰지 작은지 비교'''
5 > 2 # True
1 < 0 # False
1 > 1 # False
'''>=, <= : 값이 크거나 같은지, 작거나 같은지 비교'''
1 >= 1 # True
'''in : 특정 값이 list / tuple / set에 포함되어 있는지 확인'''
4 in [1, 2, 3] # False
1 in (1, 2, 3) # True
# 모든 비교 연산자의 결과는 print()로 확인할 수 있습니다.
print(1 == 1) # 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
비어있는 string, list 등은 분기문에서 False로 판단합니다.
empty_string = ""
empty_list = []
if not empty_string:
print("string is empty!!")
if not empty_list:
print("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
"""
any() 혹은 all() 함수를 사용해 여러 값들에 대한 조건을 판단할 수 있습니다.
# all() : 요소들이 모두 True일 경우 True 리턴
if all([True, True, True, False, True]):
print("통과!") # False가 존재하기 때문에 분기문을 통과하지 못함
# any() : 요소들 중 하나라도 True일 경우 True 리턴
if any([False, False, False, True, False]):
print("통과!") # True가 1개 이상 존재하기 때문에 분기문을 통과함
리턴 타입에 따른 활용 방법
# sort
sample_list = [3, 2, 4, 1, 5]
sample_list.sort() # return data 없이 list 자체를 정렬
print(sample_list) # [1, 2, 3, 4, 5]
# sorted
sample_list = [3, 2, 4, 1, 5]
sorted_list = sorted(sample_list) # 정렬 된 list를 return
print(sorted_list) # [1, 2, 3, 4, 5]
# 잘못된 방법
sample_list = [3, 2, 4, 1, 5]
sorted_list = sample_list.sort() # .sort()의 return data는 None 입니다.
print(sorted_list) # None
sort()와 sorted의 차이는 변수를 그대로 쓰냐 아니면 새로운 변수를 사용하냐의 차이로 볼 수 있다.
내가 모르는 함수를 사용하는 방법을 찾아보는 법
( 내가 사용하는 코드의 리턴 타입을 확인하는 방법)
1. 검색
google에 python 함수명과 같은 형태로 검색해서 해당 기능을 어떻게 사용해야 하는지 확인합니다.
단순하게 검색하려는 함수를 어떻게 사용하는지에 대한 내용은 한글로 검색해도 되지만 더 많은 정보를 얻고 싶다면 영어로 검색하시는 것을 권장드립니다.
2. docstring 확인 (함수를 만든 사람이 적은 설명 보기)
함수를 작성할 때 docstring을 활용하면 사용하려는 함수가 어떤 역할을 하는지, 어떤 값을 인자로 받는지, 어떤 값을 리턴해주는지 확인할 수 있습니다.
3. 함수 구현 코드 확인 (import 함수로 직접 찾아가서 어떻게 만들어졌는지 알여주는 걸)
내장함수의 경우 c언어로 컴파일되어 있는 경우가 많아 때문에 해당하지 않을 수 있지만, 특히 외부 라이브러리를 import 해서 사용할 때는 구현부의 코드를 보고 사용 방법을 익히는 것도 좋은 방법입니다.
vscode에서 사용하는 함수를 ctrl + click 하면 구현 코드를 확인할 수 있습니다.
에러상황시 조치방법
python에서는 try / except 문법을 사용해 에러가 발생했을 때 처리를 해줄 수 있습니다.
number = "num"
try: # try 구문 안에서 에러가 발생할 경우 except로 넘어감
number = int(number) # "num"을 숫자로 바꾸는 과정에서 에러 발생
except: # 에러가 발생했을 때 처리
print(f"{number}은(는) 숫자가 아닙니다.")
에러 종류에 따라 다른 로직 처리
number = input()
try:
int(number)
10 / number
except ValueError: # int로 변환하는 과정에서 에러가 발생했을 떄
print(f"{number}은(는) 숫자가 아닙니다.")
except ZeroDivisionError: # 0으로 나누면서 에러가 발생했을 때
print("0으로는 나눌수 없습니다.")
except Exception as e: # 위에서 정의하지 않은 에러가 발생했을 때(권장하지 않음)
print(f"예상하지 못한 에러가 발생했습니다. error : {e}")
# except 문법 또한 if / elif와 같이 연달아서 작성할 수 있습니다.
except 뒤에 붙여 주어야 하는 오류 명이 무엇인지 모를 때에는 실행했을 때 오류 명을 자세히 보면 된다.
빨간 박스처럼 오류의 명이 나오는데 그걸 복사해서 붙여 넣어주면 조건이 완성된다.
그 외에 오류
패킹과 언패킹
패킹(packing)과 언패킹(unpacking)은 단어의 뜻 그대로
요소들을 묶어주거나 풀어주는 것을 의미합니다.
list 혹은 dictionary의 값을 함수에 입력할 때 주로 사용됩니다.
*args와 **kwargs이 그것들이다.
list에서의 활용
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))
"""
# result output
"""
10
"""
list인 numbers를 함수에 넣을 때 리스트가 아니 하나의 숫자씩 풀어서 넣기 위해 *을 붙여 *numbers로 입력을 하면
괄호가 없는 숫자가 전부 1, 2, 3, 4의 값으로 들어간다.
이 3가지가 전부 동일한 값을 가지게 된다는 것이다.
dictionary에서의 활용
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))
""" 아래 코드와 동일
profile = set_profile(
name="lee",
gender="man",
age=32,
birthday="01/01",
email="python@sparta.com",
)
"""
# result print
"""
{
'name': 'lee',
'gender': 'man',
'birthday': '01/01',
'age': 32,
'phone': '-',
'email': 'python@sparta.com'
}
"""
딕셔너리 또한 안에 내용을 따로따로 풀어서 표시하는 것이 가능하다.
kwargs.get = kwargs라는 딕셔너리에서
name 키의 value값이 있다면 value값을 넣어주고
없다면 '-'으로 출력값을 넣어주고
그 값을 profile의 name키 값에 넣어준다.
args와 kwargs 전부 넣어 줄 수 있다.
특강 내용
DRF? 프로젝트를 빠르게 진행시켜 준다.
웹 개발과 AI를 동시에 배워나가야 한다.
알고리즘 시험을 준비하는 이유?
일반 웹 개발자와는 다른 AI기술을 사용하는 웹개발자가 되기 위해
딥러닝 & 머신러닝
딥러닝 : 학습을 하기 전에 가장 중심이 되는 알고리즘
머신러닝 : 딥러닝을 통해서 학습을 시키는 것 - 지도학습, 비지도학습, 강화학습
지도학습 - 정답을 알려주고 가르치기
비지도학습 - 정답을 알려주지 않고
강화학습 - 보상체계를 가지고 학습을 한다 목표로를 이룰 때 보상을 주는 식으로 학습을 한다.
내가 하고 있는 작업에서 내가 뭘 알고 모르는지 명확하게 알게 해 준다.
오늘의 소감
이제 본 수업이 들어간 지 일주일이 지났는데 수업의 진도가 점점 나아가고 있다는 것이 느껴진다.
파이썬, html, css, javascript, sql 여러 가지 언어들을 한 번씩 접하면서 이런 언어들이 이러한 경우에
사용이 되고 있구나라는 것을 보면서 이것들을 어디에 사용을 하면 유용하게 사용을 할 수 있을까 고민을
해야겠다는 생각을 하였습니다
한 주 한 주를 하다 보면 내가 배워가는 것들이 많아질 것이며 많이 배우는 것도 중요하지만 배운 것들을 잊지 않는 것도
중요하다는 생각이 들었습니다.
'코딩 교육 TIL' 카테고리의 다른 글
2024-02-22 AI 코딩 TIL (0) | 2024.02.22 |
---|---|
2024-02-21 AI 코딩 TIL (1) | 2024.02.21 |
2024-02-19 AI 코딩 TIL (0) | 2024.02.19 |
2024-02-08 AI 코딩 TIL (0) | 2024.02.16 |
2024-02-07 AI 코딩 TIL (0) | 2024.02.16 |