그래프

가장 구현하거나 이해하기 막막한 자료구조인데

각 노드를 정점 vertex

노드간 연결을 에지라고 하는데

이번에는 미국 지도를 그래프로 만들어서 다뤄보자.

 

그래프를 파이썬으로 처리하기 위해서

그래프 프레임워크부터 만들면..

 

일단 그래프는 에지에 가중치가 있거나 없는경우, 방향이 있거나 없는 경우가 있는데

일단 가중치가 없는 무향 그래프부터 만들자.

 

에지 구현하기

우선 가중치 없는 에지부터 구현

@dataclass는 타입힌트랑 같이 파이썬 3.7에 추가된 기능인데 이 데커레이터를 쓰면 아래의 코드 기준

아래의 초기화 구문을 자동으로 생성해준다고 보면 되나보다. 편해지긴 편해졌다.

class Edge:
	def __init__(self, u: int, v: int):
    	self.u: int = u
        self.v: int = v

그런데 코드보면 f"{self.u} -> {self.v}"가 있는데

문자열에 변수를 집어넣을때 앞에 f붙이고 넣을 변수를 {}로 감싸주면 되나보다.

잠깐보니 이걸 f-string이라고 하는거같다.

https://www.daleseo.com/python-f-strings/

 

파이썬의 f-string 사용법

Engineering Blog by Dale Seo

www.daleseo.com

무가중 에지를 만들었으니

이번에는 무가중 그래프를 만들자.

 

그래프 구현

그래프를 만들땐 정점들의 리스트를 받고,

그래프 자료구조를 만들땐 정점 행렬 혹은 인접 리스트를 쓰는데 여기서는 인접 리스트를 사용해서 만드는거같다.

https://sarah950716.tistory.com/12

 

[그래프] 인접 행렬과 인접 리스트

그래프 관련 문제를 풀 때는, 문제 상황을 그래프로 모델링한 후에 푸는 것이 보편적입니다. 이 때, 모델링한 그래프의 연결관계를 나타내는 두 가지 방식이 있습니다. 1. 인접 행렬 2. 인접 리스

sarah950716.tistory.com

 

 

 

 

 

나머지 부분은 좀 긴데

vertex_count야 이름 그대로 정점 개수 반환해주고.

edge_count는 edge 수를

add_vertex는 새 정점을 버택스 리스트에 추가하고, 에지에는 빈 리스트 추가.   반환값은 추가된 정점 인덱스

add_edge는 이해하기 좀 햇갈리개 생겼는데 edge.u 와 .v가 정점의 인덱스니 해당 정점 리스트에서 에지를 append 시킨단소리 같다.

add_edge_by_indices는 정점의 인덱스로 에지 추가를

add_edge_by_vertices()는 정점인덱스가 아니라 정점 자체로 인덱스를 찾아 에지 추가

vertex_at은 정점의 인덱스로 정점 가져오기.

index_of야 정점을 줘서 그 정점의 인덱스 가져오기

neighbors_for_index는 정점의 인덱스를 줬을때 _edges[index]로  에지들의 e.v  즉, 정점 인덱스 가져오고 그걸 vertex_at으로 정점을 가져와 리스트로 만들어버린다. index 인근 정점 리스트 반환

neighbors for vertex는 버텍스로 인덱스를 구해서 위 함수에  대입

edges for index는 해당 정점 인덱스의 에지들을

edges for vertex는 정점의 인덱스를 얻어서 위 함수에 대입.

__str__은 정점 수만큼 루프를 돌면서 "정점값 - 해당 정점 인근리스트 \n" 한 것을 반환.

 

bfs로 경로탐색

가중치 없는 그래프 구조를 잡았고,

이걸 이전에 구현한 너비 우선 탐색을 쓸수 있는데

미국 대도시 그래프를 만들고 돌려보자.

 

 

 

보스턴에서 마이애미까지  bfs로 찾은 경로는 보스턴-디트로이트-워싱턴-마이애미가 된다.

 

왜 이렇게 될까..

지역이 많아서 그리기는 싫은데..

엉성하게 그려서 보니 경로는 대강 맞는거같다.

 

가중화된 에지 구현

 

위 bfs에서는 무가중치 그러니 거리는 고려없이 정점의 개수만으로 경로를 찾았는데

실제는 거리, 가중치를 고려할수 있도록 가중화된 그래프를 만들어야 한다.

가중화 에지는

기존의 에지를 상속받고, weight 추가. 비교할수 있게 lt도 구현.

 

가중화 된 그래프 구현

기본적으로 그래프 상속받고

에드 에지 바이 인덱시스와 버텍시스는  기존 그래프 함수를 오버라이드 시켰고,

네이버스 포 인덱스 위드 웨이트는 [(가중화된 에지, 가중치)] 리스트를 반환해준다.

__str__이야 그래프랑 큰 차이없고. 

 

 

한번 미국 대도시 그래프에 가중치(거리)를 넣어서 출력하면

 

시애틀은 시카고까지 1737, 샌프란시스코까진 678 이면서

다른 지역들도 블라블라 나온다.

최소 신장트리 구하기

트리는 정점 사이 경로가 하나뿐인 그래프(사이클이 없다)인데,

신장 트리 spanning tree는 모든 정점을 연결하는 트리이고

최소 신장 트리 minimum spanning tree는 가중치 그래프 모든 정점을 가장 짝게 최소 비용으로 연결한 신장 트리가 된다.

 

최소 신장 트리를 만들기 위해서 프림 알고리즘을 쓰는데 우선순위 큐이 필요하니 구현하자.

 

그리고 가중치를 가진 에지들의 모임 가중화된 경로는 모든 에지 가중치를 단순 합하면 되니 이렇게 구현하면 되고..

mst를 구하기 위한 프림 알고리즘은  다음의 순서로 동작된다고 한다.

1. mst에 포함할 정점 선정

2. mst에 포함되지 않은 정점 중 가중치 가장 에지 낮은거 찾아 mst 추가

3. 모든 정점으로 mst를 만들때까지 2 반복.

 

mst 함수 내용을 보면

가중화된 그래프와 시작 정점 인덱스를 줘서 가중화된 경로를 반환하는 내용인데

처음 조건문에서 시작 인덱스가 음수거나 너무 크다. 즉 없는 거면 None 반환.

 

15-17내용은 처음 가중화된 경로와, 우선순위 큐, 정점 방문 여부 리스트 초기화

내부에 visit 함수가 있는데 정점 인덱스를 받아 방문했다고 True 표시하고.

해당 정점 주위 에지들을 받아 방문하지 않은곳을 골라 우선순위 큐에 집어넣는 형태로 정의되었다.

 

그 뒤의 루틴이야 스타트 인덱스로 비짓 함수 시작.

우선순위 큐가 텅빌때까지 계속 루프를 돈다.

우선순위가 가장 높은? 에지를 꺼내고 heappop은 가장 작은 원소 꺼낸다고 한다.

불리언 리스트인 visited[edge.v]로 해당 정점 방문했는지도 체크.

방문한데가 아니면 가중화된경로 리스트에 추가.

우선순위 큐에서 우선순위 고려해서 꺼낸거니 바로 그 정점에서 비짓 함수 반복.

 

 

이 가중화된 경로를 출력할수 있는 함수도 구현하고

 

 

 

mst에 시작 정점 인덱스를 따로 안줘서 기본값 0(시애틀)에서 출발한 결과 아래의 경로로 mst가 만들어졌다.

왜이렇게 되었을까

 

결국 그래프를 그렸는데 여기서 다시보면.

 

대강 맞게 간거 같다. 근대 마지막 애틀렌타-마이애미는 잘못된거같은데..? 그냥 pass

 

 

다익스트라 알고리즘으로 길찾기

다익스트라 알고리즘도 최단경로 찾는데 쓰이는 알고리즘으로 최소 가중치 경로를 반환받는데

다익스트라 노드를 사용한다. 이 노드는 정점 인덱스와 현재 위치까지의 거리(비용)을 가지며

이 비용으로  lt, eq 연산이 수행된다.

 

다익스트라 알고리즘 과정은

- 시작 정점을 우선순위 큐에다가 넣고

- 가장 가까운 접점(현재 정점)을 팝, 그리고 연결된 모든 이웃 정점을 확인하여 방문하지 않았거나 한 에지가 최단경로시 시작점에서 그 정점까지의 거리와 에지를 기록하고 그 최단거리 방향 정점을 우선순위 큐에 추가

- 위 과정을 계속 반복하여 시작점에서 다른 모든 정점까지 최단거리 반환.

이라는데 일단 코드를 봐야알거같다.

 

구현한 다익스트라 함수는 가중화 그래프와 정점 루트를 받아서 (거리 리스트, 딕트(정점, 에지)) 튜플을 반환받는데

처음에는 루트 인덱스를 first에다 담고, 모든 정점들 거리 리스트 distances 초기화, 루트에서의 거리는 0

경로 딕트와 다익스트라 노드를 담는 우선순위 큐를 만들어 첫 정점에 대한 다익스트라 노드(인덱스와 거리 0) 푸시

 

우선순위 큐가 텅빌떄까지 반복

u에다간 노드 정점 인덱스를, dist_ut에는 거리 담고

정점 인덱스로 인근 에지 가져와 루프

해당 에지 정점 거리를 가져와 dist_v에 담긴한데

이전 거리 dist_v가 없거나 최단거리( dist_u 현재까지 거리 + we.weight 에지 거리가  dist_v 보다 작다면)있으면

새로 구한 거리로 덮어씌우고 distances[we.v]

이 에지로 경로 딕트 갱신 path_dict[we.v] = we

짧은 경로 정점에 대한 다익스트라 노드를 만들어 우선순위 큐에 추가.

 

지금까지 내용보면 astar에서 휴리스틱 함수가 빠진게 차이인거같다.

일단 실행하기전에 필요한 함수 구현하고

 

다음 코드를 실행하면..

 

시작점을 로스앤잴래스로 했을때

모든 정점에 대한 거리와

LA에서 보스턴까지 최단경로가 나온다.

 

 

 

우선 디스턴스 어레이 투 버텍스 딕트를 보면.

가중화된 그래프와 거리 리스트를 받아서 딕셔너리(정점, 거리)를 반환하니

각 정점별 거리를 쉽게 구할수 있겠고.

 

패스 딕트 투 패스는

시작 정점 인덱스, 도착지 인덱스와 경로딕트(인덱스, 가중화된 에지)를 인자로 받아 가중화된 경로(에지 리스트)를 반환한다.ㅍ 근데 패스 딕트가 어떻게 만들어지는지 잘 이해가지는 않는데.

 

 

 

 

 

잠깐 LA에서 보스턴 가는 경로를 그림판으로 보면

LA  기준 샌프란, 리버사이드, 피닉스에 대해서 루프를 다돌긴하겠지만.

우선 리버가 가까우니 리버부터 보면 아래와 같이 넣을것이고,

pq에 리버에 대한 다익스트라 노드가 들어갔으니 이번엔 이걸 보겠다.

 

이번에는 리버에서 가장 가까운데가 피닉스인데 내가 원하는데서 좀 멀어지고 있다..

지금 이해된건데 다익스트라 알고리즘은 시작점에서 모든 정점까지 가장 가까운 거리를 찾는다는게 이소리구나.

LA-리버-피닉스나 LA-피닉스 거리가 동일하니 다른 얘로보자면

 

LA에서 시애틀 가는 경우 거꾸로 놓고보면

전자 : 시애틀-시카고-리버-LA보다

후자 : 시애틀-샌프란-LA가 거리가 가까우므로

dist[시애틀] = 전자가 dist[시애틀] = 후자로 덮어씌워지고

path_dict[시애틀] = 시애틀-시카고 가 아닌 path_dict[시애틀] = 시애틀-샌프란으로 갱신된다는 소린거 같다.

완전히 이해는 안되지만 대강 이런식으로 이전 거리와 경로를 덮어씌운다는게 이 의미로 보인다.

 

 

 

 

그래서 path_dict_to_path는

이미 시작점에 가장 가까운 경로로 path_dict가 만들어 져있으니

목적지에서 에지를 꺼내 리스트 만드는 과정이고,

경로가 거꾸로되어있으니 마지막에 리버스를 시켜주는거같다.

 

 

 

DNA 탐색하기

어제 글에서 DNA는 뉴클레오타이드로 구성되고 A, C, G, T가 있다고 했는데

뉴클레오 3개를 모은걸 코돈이라하고 이 코돈찾는걸 하는 내용

 

뉴클레오타이드 - 인트이넘

코돈 - 이넘3개 튜플

유전자 - 코돈 리스트

 

 

한번 출력하면 잘 나온다.

 

코돈 선형탐색

선형탐색 처음부터 끝까지 존재하는지 순서대로 매칭

ACG 코돈은 있지만 GAT 코돈은 없댄다

 

 

코돈 이진 탐색

이진탐색

1. 이진탐색 일단 탐색할 요소가 이미 정렬되어있는 상태여야하고,

2. 구성 요소의 중간과 탐색 값을 비교 탐색값이 작으면 중간 왼쪽들과, 크면 오른쪽들과 다시 수행

3. 왼쪽 혹은 오른쪽 녀석들의 중간값과 탐색 요소 크기 비교 쭉쭉죽..

 

 

 

 

 

미로를 이용한 탐색

이번에는 깊이/너비우선 탐색, A* 등 탐색 알고리즘을 다루는데,

우선 미로부터 만들자.

미로 한칸 한칸인 셀을 Enum으로 만들고

미로 상 위치를 나타내는 메이즈 로케이션 클래스를 네임드 튜플로 만들자.

 

미로 클래스를 만들고

한번 출력시켜보면 이쁘게 나온다.

 

 

추가로 미로의 골인지, 현재 위치에서 이동가능한 곳을 반환하는 메서드를 만들자

 

 

 

깊이우선 탐색

아래로 쭉쭉 가다가 막히면 한칸 올라와서 다시 탐색하는 방법. 스택을 쓴덴다.

 

 

잠깐 파일을 바꿔서 generic_search.py에 스택 구현

 

위 코드를 보면 @property 데코레이터가 있는데 개념은

자바에서 배운적있는 게터 세터같은거라고 한다.

@property를 쓰면  get_empty 대신 그냥 empty로 개터 역활을 하는거란다.

 

여기 블로그 내용이 좀 이해하기 쉬웠다.

https://cocook.tistory.com/103

 

[Python] @property 너 누구야? 후아유

이번 포스트에서는 파이썬 클래스에서 종종 보이는 @property에 대해 알아보겠다. 결론부터 이야기하자면 @property 데코레이터는 객체의 프로퍼티를 보호해주는 함수라고 할 수 있다. 먼저 본격적

cocook.tistory.com

 

 

 

스택에 이어서 노드 클래스도 구현하자.

Optional은 매개변수가 있으면 해당 타입 값을 쓰고 없으면 None이 들어갈수도 있다? 라고한다.

여기서 노드는 메이즈 로케이션을 감싸는 레퍼인데, 코스트와 휴리스틱 값을 가지고 있으며

상태 변화를 추적하기 위해서 필요하다는데 아직은 잘 모르겠다.

 

 

잠깐 찾아봤는데

Optional, Callable 등 타이핑 모듈에 있는 메서드들 잘 설명한 글이 있어서 링크 가져왔다.

https://www.daleseo.com/python-typing/

 

[파이썬] typing 모듈로 타입 표시하기

Engineering Blog by Dale Seo

www.daleseo.com

 

 

 

중간에 자꾸 에러나서 왜그런가 찾아보다가

from __future__ import annotations을 빠트린게 문제였다.

그와 관련된 내용을 여기서 잘 설명해주고 있다.

 

https://ryanking13.github.io/2018/07/12/python-37-whats-new.html

 

파이썬 3.7의 새로운 기능들

파이썬 3.7에 새로 등장한 기능들을 소개하는 글입니다.

ryanking13.github.io

 

dfs 함수와 node_to_path 함수 정의하고

 

 

 

 

 

maze 클래스에 mark, clear 함수와

메인 루틴 구현, 오타 고치고 돌리면

 

결과가 잘나오긴 한데 경로가 조금 이상한거같다.

 

dfs 함수부터 보면.. 시작점 위치(MazeLocation)와 메이즈로케이션을 인자로받아 불리언을 반환하는 goal_test(), 메이즈로케이션 인자로받아 이 자료구조의 리스트를 반환하는 석세서 함수를 인자로받아. 노드를 리턴해준다고하는데..

 

방문한 장소 frontier 스택을 만들어 초기 장소 노드 푸시

스택이 안비워져 있으니 프론티어 팝으로 노드 꺼내고,

현재 노드 상태도 가져오고 current_state 

골테스트도 하고

아니면 현재 상태에서 석세서스로 가능한 곳있나 보고

-이미 방문한곳은 pass

-explored는 쓸때없어 보이긴한데 추가하고.

-프론티어에 자식(메이즈 로케이션)과 현재 노드 상태(지금 메이즈로케이션)  푸시

다시 와일문으로 돌아가서 쭉쭉하면 지금 결과가 나오는거같다.

 

 

 

다시 왜 이런 결과가 나왔는지 생각해보니

 

 

 

석세서스에서 아래-위-우-좌 순으로 리스트가 만들어져서

스택에 넣으면 좌-우-위-아래 순이 되어 이렇게 팝 시켜서 탐색하다보니

G 까지 빠른 경로가 아니라 자꾸 좌측으로 끝까지 갔다가 아래로 내려가는 모습을 보인거같다.

 

잠깐 보면 최대한 우측이나 왼쪽 끝에 갔다가 내려가는 모습을 보이는데, 내가 석세서스를 잘못이해한거같기도하고..

 

 

 

 

 

 

너비우선 탐색

dfs에선 스택을 썻지만 bfs에선 큐를 사용한다고 한다.

 

bfs 함수도 dfs의 stack 대신 Queue로만 바꾸면 된다.

 

dfs 돌릴떄와 마찬가지로 구현해서 돌리면

 

 

생각해보니까 옆으로 돌려서 봤어야 했더라.

dfs는 이름그대로 깊이방향으로 계속 가고,

dfs도 이름 그대로 너비(옆)방향으로 가면서 경로를 찾아내었다.

그렇다고 아까 dfs한거를 옆으로봐도

이 결과는 이해되질 않는다.

가아니라..

깊이 방향 우선이니 이럴수도 있겠다 싶네.

 

 

 

이번에는 astar 알고리즘

- 비용함수 g(n)와 휴리스틱 함수 h(n)로 가장 가능성 있는 경로 중심으로 탐색한다.

- 비용함수 g(n)는 특정지점까지 도달하는데 걸리는 비용

- 휴리스틱 함수 h(n)는 해당 위치에서 목표지까지 비용

=> 총 비용 f(n) = g(n) + h(n)

인데 현재 위치까지 오는데 비용이랑 목표까지 비용을 합친게 f(n)이 되겠다.

그리고 다음 경로 석세서스를 선정할때 f(n)이 가장 낮은걸 고른다.

 

 

astar 알고리즘 구현하기 위해 우선순위 큐 사용.

큐다보니 순서데로 가긴하는데.

우선순위 큐라 순서가 같은 경우 우선순위가 높은것 부터 꺼내서 쓴다.

 

이 우선순위 큐를 리스트와 힙큐로 만드는데..

힙큐 링크

 

https://littlefoxdiary.tistory.com/3

 

[Python] 힙 자료구조 / 힙큐(heapq) / 파이썬에서 heapq 모듈 사용하기

힙은 특정한 규칙을 가지는 트리로, 최댓값과 최솟값을 찾는 연산을 빠르게 하기 위해 고안된 완전이진트리를 기본으로 한다. 힙 property : A가 B의 부모노드이면 A의 키값과 B의 키값 사이에는 대

littlefoxdiary.tistory.com

힙큐 푸시와 힙큐 팝을 할때

Node 클래스의 __lt__() 메서드로 비교해서 푸시, 팝이 이뤄진다고한다.

 

 

이번에는 휴리스틱 함수 만드는데

비용 함수는 현재 지점까지 비용

휴리스틱은 현재지점에서 목표지까지 비용.

미로 찾기 예제에서 휴리스틱 함수로 맨해탄거리랑 유클리드 거리를 쓰는데 여기선 맨해탄 거리 쓴다.

 

이제 에이스타 함수를 보자

dfs, bfs랑 거의 동일한데 아직 방문하지 않은 곳, 탐색하려는 곳을 담는 변수 프론티어를 우선순위 큐로 쓰는데..

프론티어 팝으로 가장 우선순위가 높은 곳을 꺼낼것이고.

석세서스로 우선순위 높은 곳에서 갈 곳을 루프 돌며 보는데.. 

다음 장소 비용은 현재 장소 + 1하고,

탐색하지 않은 장소 child가 있거나 이미 탐색했더라도 갈수있는 장소의 새 코스트가 크다면(?)

익스플로드 추가하고,

다음 으로 갈 노드(자식 노드, 현재 노드, 새 비용, 자식노드기준 휴리스틱함수)를 프론티어에 푸시한다. 

우선순위 큐 프론티어가 비워질때까지 계속 반복하다가 목적지 오면 끝

 

 

잠깐 Node 클래스를 다시보면

lt에서 총 비용 = 비용 + 휴리스틱 값을 기준으로

우선순위 큐에서 푸시 팝 한다.

총 비용함수를 이용한 우선순위 큐 자료구조를 써서 a* 알고리즘을 구현한 결과

dfs처럼 깊이방향으로 오르락 내리락도

bfs로 쭉 좌우 하지도 않고,

가장 적당하게 빠른길을 찾아간다.

 

분량은 길지 않은데

진짜 진행하기 힘드네

어재는 작은 파이썬 프로젝트 인가 하는 책을 공부하려고 했는데

막상 어제 공부한것들을 오늘 돌아와서 하자니 급 하기 싫어졌다.

 

딥러닝이든 배포같은거든 공부하긴 해야되는데

그전에 고전 알고리즘들을 쭉 정리해봐야할거 같아 이번에는 '고전 컴퓨터 알고리즘 인 파이썬' 책을 진행하고자한다.

 

근데 보다보니 이거 2년전에 원서로 보다가 뉴클레오타이드인가 꾸역꾸역하다가 포기했던 그책인거같다.

 

 

재귀를 이용한 피보나치 수 계산

5번째 피보나치수는 5인데

 

 

재귀적으로 이런식으로 계산된다.

fib2(3)이 2번, fib2(2)가 3번. fib2(1)이 5번? 호출된다.

결과가 똑같은걸 계속 계산하니 비용이 크다.

일단 피보나치수는 11235라 5번째 값이 맞게 계산되긴 했다.

 

이번에는

메모이제이션을 이용한 피보나치 계산.

왜 메모라이제이션이 아니라 메모이제이션인지는 모르겠지만 처음 쓴사람이 이렇게 불러서 하는거같은데

이름 그대로 이미 계산한걸 또 계산하지 않고 저장해둿다가 가져와서 쓰는 방법이라한다.

 

 

7번째 피보나치 수는 13

 

 

새로 계산한 결과가 있으면 dict에 저장했다가 필요할때 꺼내서 쓰니

재귀때보다 계산량이 훨씬 줄어들었다.

 

 

뉴클레오타이드 정보 압축하여 저장하기.

 

전에 원서로 이 내용공부하려다가 식겁했었는데, 번역서라 좋긴좋다.

뉴클레오타이드는 유전자를 형성하는건데 A, C, G, T 네 가지 중 하나의 경우만 있다고 한다.

'A', 'C', 'G', 'T'는 아스키로 한 글자 저장하는데 1바이트, 8비트가 필요하겠지만

4 경우 뿐이므로 2비트로 저장하면 공간을 아낄수 있단다.

 

"AGGGGTCTA" 같은 문자열 대신 

 

A  : 00

C : 01

G : 10

T : 11

 

로 해서 비트 문자열로 바꾸면 공간을 훨씬 절약.

 

 

_(언더스코어 1개)로 시작하는 변수나 메소드는 private

__(언더스코어 2개)로 시작하는 것들은 네임 맹글링이며, 다른 클래스에서 접근하지 못하게 함. 

 

 

 

실행하면 엄청 긴 문자열 오리지날 데이타가

비트스트링으로 압축해서 크기가 많이 줄어들었다.

압축 해제 후에 결과도 동일하다.

 

 

 

 

하노이탑 

EBS에서도 나오고, 정말 자주 듣긴 들었는데 한번도 구현해보거나 풀어본적은 없었지만 하기 싫어도 해야지.

 

여기선 하노이탑, 스택을 재내릭을 사용해서 구현한다.

제네릭.. 6,7년 전쯤에 웹 개발 학원에서 자바 배울때 처음 배운 개념인데

뭐라 하나 여러 데이터를 보관하는 자료 구조에서 보관할 데이터 타입을 정의했던 내용으로 기억하고 있지만 가물가물하다.

 

잠깐 검색해보니 내가 알고 있던 개념이 맞는거같다. 파이썬에선 안써도 되지만 이책에서는 타입 힌트를 쓰다보니 타입 자리에 int, str 넣던거 대신 T를 넣어서 구현하네.

https://velog.io/@sawol/%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-with-Python 

 

제네릭 프로그래밍

어떤 함수의 파라미터에 대한 타입을 지정하지 않고 상황에 따라 다양한 타입을 파라미터로 사용하는 기법이다.처음엔 '이게 무슨 말인가' 싶었는데 아래 예제를 통해 이해했다.

velog.io

 

일단 스택 만들고, 첫번째 탑에다가 디스크를 3개 끼워넣자.

 

나는 하노이탑 푸는 방법에 크게 관심이 없다보니.

대충 동작 구현하고 보면 a타워에서 c 타워로 잘 옮겨졌다.

 

오랜만에 다시 파이썬을 해야되서 공부 시작.

 

파이썬 기초 문법은 알다보니 완전 기본서보다는 조금 더 난이도 있는 

21개의 작고 재미난 파이썬 프로젝트 책을 보고 공부하려고 한다.

 

원래는 윈도우에다가 파이썬 가상환경 만들고 바로 쓰려고했지만

책에 셔뱅 얘기가 나오는데, 윈도우 환경에서 셔뱅을 어떻게 하나 싶어

그냥 WSL을 깔고 다시 진행하려고하는데,

 

vscode wsl 연동 내용이 이곳에 설명이 잘되있는거같아 참고.

https://blog.fotogrammer.com/python-%EA%B0%9C%EB%B0%9C-%ED%99%98%EA%B2%BD-%EA%B5%AC%EC%B6%95%EA%B8%B0-on-wsl2/

 

Python 개발 환경 구축기 on WSL2 > Fotogrammer

Windows 11 에서 WSL2 + Ubuntu20.04 + Python 개발 환경 구축기 입니다. 간단하게 윈도우즈에서 리눅스 개발 환경을 만들어 봅시다.

blog.fotogrammer.com

 

 

 

 

위 내용 참고해서 가상환경 만들고

vscode 상에 가상환경 활성화되도록

.bashrc에다가 source .myenv/bin/activate 추가해서 터미널 실행시 가상환경 활성화.

 

 

가상 환경에 설치된 모듈들이 없으니 

현재 프로젝트에 필요한 모듈 설치하고,

 

 

핼로월드 예제에 셔뱅 넣고 pytest 돌리니 잘된다.

 

 

 

 

셔뱅이 있던 없던 python hello.py로 실행하면 잘되긴하지만

pytest에선 셔뱅없인 잘 안된다.

 

화면크기에 비해서 폰트가 너무 커서

폰트사이즈도 조절

https://hianna.tistory.com/350

 

[VSCode] 터미널 폰트, 글자 크기 변경하기

VSCode에서 사용하는 터미널의 폰트를 변경하는 방법입니다. 터미널 폰트설정은 VSCode의 설정 메뉴에서 할 수 있습니다. 1. 설정 메뉴에 들어갑니다. 설정 메뉴에 접근하는 방법은 여러가지가 있습

hianna.tistory.com

 

 

 

 

지금까지 파서를 제대로 만져본적이 없었는데

argparse를 쓰니 help 옵션이 이쁘게 만들어졌다.

 

사용 방법, 동작 내용, 매개변수 등 ..

 

 

사용 방법대로 위치매개변수를 주면 잘나온다.

 

 

매개변수 디폴트값을 준다면..

 

 

add_argument에 default를 줫더니 옵션 매개변수가 되어 없어도 헬로 월드가 나온다.

-n과 --name에서 -는 축약형앞에 --은 일반 옵션명 앞에온다.

 

 

매개변수 처리 하니 테스트도 통과 굳

 

 

메인함수도 만들고, 매개변수 처리 루틴을 따로 빼주니 더 깔끔해졌다.

 

 

 

코딩 스타일 점검하는 프로그램 린터인 flake8을 돌려보니

잔뜩 에러가나온다.

 

두줄 간격도 뛰워주고, 콤마 뒤에 한칸씩 뛰우고 EOF에 빈줄 만들고, 블라블라 뭐가많은데

고쳐주면 이쁘게 된다.

 

 

이번엔 다른 린터 프로그램인 pylint를 돌려보니

독스트링이 없다고 뭐라그런다.

 

 

저자분이 한걸 참고해서 엉성하게라도 독스트링을 추가해주고

 

다시 파이린트 돌리면 ok

 

 

 

 

와 이렇게 헬로월드 예제 가지고

셔뱅, 매개변수 인자, 린트 등 이렇게 힘들게 다뤄본건 처음인데

유익하긴 유익하다.

+ Recent posts