루나의 TIL 기술 블로그

프로그래머스 level 2 기능개발, 스택/큐

|

걸린 시간 : 3시간?

문제 설명

프로그래머스 팀에서는 기능 개선 작업을 수행 중입니다. 각 기능은 진도가 100%일 때 서비스에 반영할 수 있습니다. 각 기능의 개발속도는 모두 다르기 때문에 뒤에 있는 기능이 앞에 있는 기능보다 먼저 개발될 수 있고, 이때 뒤에 있는 기능은 앞에 있는 기능이 배포될 때 함께 배포됩니다.

먼저 배포되어야 하는 순서대로 작업의 진도가 적힌 정수 배열 progresses와 각 작업의 개발 속도가 적힌 정수 배열 speeds가 주어질 때 각 배포마다 몇 개의 기능이 배포되는지를 return 하도록 solution 함수를 완성하세요.

입출력 예 #1 첫 번째 기능은 93% 완료되어 있고 하루에 1%씩 작업이 가능하므로 7일간 작업 후 배포가 가능합니다. 두 번째 기능은 30%가 완료되어 있고 하루에 30%씩 작업이 가능하므로 3일간 작업 후 배포가 가능합니다. 하지만 이전 첫 번째 기능이 아직 완성된 상태가 아니기 때문에 첫 번째 기능이 배포되는 7일째 배포됩니다. 세 번째 기능은 55%가 완료되어 있고 하루에 5%씩 작업이 가능하므로 9일간 작업 후 배포가 가능합니다.

따라서 7일째에 2개의 기능, 9일째에 1개의 기능이 배포됩니다.

입출력 예 #2 모든 기능이 하루에 1%씩 작업이 가능하므로, 작업이 끝나기까지 남은 일수는 각각 5일, 10일, 1일, 1일, 20일, 1일입니다. 어떤 기능이 먼저 완성되었더라도 앞에 있는 모든 기능이 완성되지 않으면 배포가 불가능합니다.

따라서 5일째에 1개의 기능, 10일째에 3개의 기능, 20일째에 2개의 기능이 배포됩니다.

입출력 예

progresses speeds result
[93, 30, 55] [1, 30, 5] [2, 1]
[95, 90, 99, 99, 80, 99] [1, 1, 1, 1, 1, 1] [1, 3, 2]

사고 과정

for문을 돌려서 progresses[i] +speeds[i]을 실행하고, progresses[0]이 100을 넘으면 pop해서 리스트에서 꺼낸다. for문에 count를 증가시켜서 count를 출력한다.
100%가 넘어서 배포되는 것들을 어떻게 나누어서 리스트로 출력할지는 잘 모르겠다.

def solution(progresses, speed):
    count = 0

    while len(progresses)>0: #프로그래스 리스트가 텅 빌때까지
        for i in range(0,len(progresses)): #len(progresses)는 3
            a = progresses[i]+speed[i]
            progresses.pop(0)
            progresses.insert(0, a) 
            #프로그레스에 스피드를 더한 값을 프로그레스 앞에 넣는다
            print(progresses)
            if progresses[0]>=100: #100이상이면 
                progresses.pop(0) #리스트에서 제거한다
                speed.pop(0)            
            count += 1
            #100%가 넘어서 배포되는 것들을 어떻게 나누어서 리스트를 출력할지 잘 모르겠다.
    print(count)
    return count

solution([93,30,55],[1,30,5])

처음에는 progresses[i] = progresses[i]+speed[i]했는데 인트형=인트형이라 그런지 작동하지 않았다.
progresses.insert(0, progresses[i]+speed[i]) 이렇게 인서트를 써도
IndexError: list index out of range 에러가 난다.
리스트에서 인덱스가 없는걸 찾으면 나는 에러라고 하는데 왜 나는건지 잘 모르겠다.

그래서 이렇게 바꿔보았더니

a = progresses[i]+speed[i] # a = 94 
progresses.pop(0) # progresses = [30,55]
progresses.insert(0, a) # progresses = [94,30,55]

print(a)를 했더니 계속 60이 나왔다. i에 0이 아닌 1이 들어가서 그런줄 알았는데 그게 아니고 while루프가 무한반복되는걸 내가 중간에 멈춰서 콘솔창의 결과값이 맨 앞부터 안 보이는 것 같았다. 디버깅할 때 무한루프를 돌지 않도록 해놓고 봐야겠다.

def solution(progresses, speed):
    count1 = 1
    count2 = 0
    while len(progresses)>0: #프로그래스 리스트가 텅 빌때까지
    #for i in range(len(progresses)): #i에 0,1,2대입
        a = progresses[0]+speed[0]*count1
        progresses.pop(0)
        progresses.insert(0,a)
        print(progresses)

        if progresses[0]>= 100:
            progresses.pop(0)
            speed.pop(0)
            count1 += 1
            count2 += 1
        else:
            count1 += 1
    
    print(count1)
    print(count2)
    return count2

solution([93,30,55],[1,30,5])

이것저것 해보다가 결국 for문에서 i를 이용해서 풀지 못할 것 같아서 for문은 지웠다. 모범답안에서 나온대로 progresses[0]을 사용해서 풀어보려고 했다. 위 코드를 돌리면 콘솔 창에 아래와 같이 나온다.

[94, 30, 55]
[96, 30, 55]
[99, 30, 55]
[103, 30, 55]
[180, 55]
[85]
[120]
8
3

시간이 너무 오래걸려서 이정도에서 포기했다!

모범 답안

def solution(progresses, speeds):
    answer = []
    time = 0
    count = 0
    while len(progresses)>0:
        if(progresses[0]+time*speeds[0]) >= 100:
            #완료된 퍼센트 + 작업일수*하루작업량이 100이 넘으면
            progresses.pop(0) #리스트[0]제거
            speeds.pop(0)
            count+=1 #카운트 올라감
        else: #100이 넘지 않으면 타임+1한 뒤 다시 돌아감
            if count >0: #100이 넘지 않았는데 카운트가 있으면
                answer.append(count) #카운트를 리스트에 추가
                count = 0 #카운트를 리셋
            time+=1
    answer.append(count)
    #카운트를 리스트에 추가
    return answer

time을 while문 안에 돌려서 날짜가 더해지면 %가 올라가는 것을 구현해준 것이 좋았다.
if else로 나누어서 100이 넘지 않으면 time이 하나 더해지는 것이 좋다.

while 조건
    if 조건 
        반복하고싶은 내용
        count+=1 
    else
        count를 답에 추가하고 리셋
        time+=1
count를 답에 추가

이런 구조를 생각하지 못했다!

주요 포인트 및 생각해볼 점

level2가 되면서 난이도가 급격하게 어려워지는 것 같은건 내 실력이 부족한 탓이겠지?

파이썬 - 데코레이터(decorator), 쿼리디버거

|

Decorator

Decorator를 한마디로 얘기하자면, 대상 함수를 wrapping 하고, 이 wrapping 된 함수의 앞 뒤에 추가적으로 꾸며질 구문 들을 정의해서 손쉽게 가능하게 해주는 것이다. 재사용, 분리를 위해서 함수를 따로 떼어서 원하는 곳에 붙여넣는 것이라고 생각하면 된다.

출처: https://bluese05.tistory.com/30 [ㅍㅍㅋㄷ]

함수의 내부를 수정하지 않고 기능에 변화를 주고 싶을 때 사용한다.
일반적으로 함수의 전처리나 후처리에 대한 필요가 있을때 사용을 한다.
또한 데코레이터를 이용해, 반복을 줄이고 메소드나 함수의 책임을 확장한다.

출처: https://hckcksrl.medium.com/

예를 들어서 로그인이 되었으면 아래 함수를 실행시키고 싶다고할 때 원하는 함수 위에 로그인 데코레이터를 넣어주면 된다. 마찬가지로 권한관리도 할 수 있다. 로그인 데코레이터 예시
어드민 데코레이터(권한관리) 예시

#뷰에서 아래와 같이 사용

@login_decorator
def ViewUserInfoView

혹은 쿼리의 성능을 측정하고 싶을 때 쿼리 디버거 데코레이터를 만들어준 뒤에 함수 위에 넣어서 쿼리가 얼마나 걸리는지 측정할 수 있다.

#뷰에서 아래와 같이 사용

@query_debugger  
def SearchView
#쿼리 디버거 함수 예시
import time
import functools
from django.db import connection, reset_queries

def query_debugger(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        reset_queries()
        number_of_start_queries = len(connection.queries)
        start  = time.perf_counter()
        result = func(*args, **kwargs)
        end    = time.perf_counter()
        number_of_end_queries = len(connection.queries)
        print(f"-------------------------------------------------------------------")
        print(f"Function : {func.__name__}")
        print(f"Number of Queries : {number_of_end_queries-number_of_start_queries}")
        print(f"Finished in : {(end - start):.2f}s")
        print(f"-------------------------------------------------------------------")
        return result
    return wrapper

예시1

def welcome_decorator(self):
  def wrapper():
    return self() + "welcome to WECODE!"
  return wrapper


@welcome_decorator
def greeting():
    return "Hello, "

print(greeting())

예시2

class Decorator:

    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        print('전처리')
        print(self.function(*args, **kwargs))
        print('후처리')

@Decorator
def example():
    return '클래스'

#example() 실행
'''''''''
전처리
클래스
후처리
'''''''''

장고에서의 예시3

from django.http import HttpResponse

def only_admin(f):
    def check(request, *args, **kwargs):
        try:
            if request.user.admin is not True:
                return JsonResponse({
                    'status': False,
                    'message': 'admin permission is required'
                })
        except:
            return JsonResponse({
                'status': False,
                'message': '\'sign in\' is required'
            })
        return f(request, *args, **kwargs)
    return check


@only_admin
def add_target(request):
    return HttpResponse('')

프로그래머스 level 2 멀쩡한 사각형

|

걸린 시간 : 1시간 30분

문제 설명

가로 길이가 Wcm, 세로 길이가 Hcm인 직사각형 종이가 있습니다. 종이에는 가로, 세로 방향과 평행하게 격자 형태로 선이 그어져 있으며, 모든 격자칸은 1cm x 1cm 크기입니다. 이 종이를 격자 선을 따라 1cm × 1cm의 정사각형으로 잘라 사용할 예정이었는데, 누군가가 이 종이를 대각선 꼭지점 2개를 잇는 방향으로 잘라 놓았습니다. 그러므로 현재 직사각형 종이는 크기가 같은 직각삼각형 2개로 나누어진 상태입니다. 새로운 종이를 구할 수 없는 상태이기 때문에, 이 종이에서 원래 종이의 가로, 세로 방향과 평행하게 1cm × 1cm로 잘라 사용할 수 있는 만큼만 사용하기로 하였습니다. 가로의 길이 W와 세로의 길이 H가 주어질 때, 사용할 수 있는 정사각형의 개수를 구하는 solution 함수를 완성해 주세요.

찢어진 사각형

입출력 예

W H result
8 12 80

사고 과정

사고 과정

직사각형의 비율이 2:3일때 2+3-1인 4가 지나가면서 거치는 부분의 최소단위가 된다. 그래서 비율의 합-1 한 뒤에 최소공배수을 다시 곱해주면 거치는 직사각형을 구할 수 있다.

제출 답안

from math import gcd
def solution(w,h):
    return w * h - (w/gcd(w, h) + h/gcd(w, h) - 1) * gcd(w, h)

명예의 전당

아무것도 안 보고 써서 제출했는데 한 번에 통과하고 좋아요도 받았다!!

모범 답안

def gcd(a,b): return b if (a==0) else gcd(b%a,a)    
def solution(w,h): return w*h-w-h+gcd(w,h)

최소공배수를 내장함수를 안 쓰고 이렇게 구할 수가 있구나.. 새삼 대단하다.

프로그래머스 level 2 더 맵게, heap

|

걸린 시간 : 1시간

문제 설명

매운 것을 좋아하는 Leo는 모든 음식의 스코빌 지수를 K 이상으로 만들고 싶습니다. 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 Leo는 스코빌 지수가 가장 낮은 두 개의 음식을 아래와 같이 특별한 방법으로 섞어 새로운 음식을 만듭니다.

섞은 음식의 스코빌 지수 = 가장 맵지 않은 음식의 스코빌 지수 + (두 번째로 맵지 않은 음식의 스코빌 지수 * 2)
Leo는 모든 음식의 스코빌 지수가 K 이상이 될 때까지 반복하여 섞습니다. Leo가 가진 음식의 스코빌 지수를 담은 배열 scoville과 원하는 스코빌 지수 K가 주어질 때, 모든 음식의 스코빌 지수를 K 이상으로 만들기 위해 섞어야 하는 최소 횟수를 return 하도록 solution 함수를 작성해주세요.

입출력 예

scoville K return
[1, 2, 3, 9, 10, 12] 7 2

사고과정

가장 작은 수를 a에 저장하고 배열을 내림차순으로 정렬한 뒤에 맨 마지막 요소를 제거한다. 그 다음 작은 수 b도 같은 방식으로 구하고 a+b*2 를 리스트에 더해준다. 이걸 scoville 리스트의 가장 작은 수가 K보다 커지기 전까지 반복하고 카운트를 출력한다.

def solution(scoville, K):
    count = 0
    while min(scoville) < K: 
        a = min(scoville)
        scoville = sorted(scoville, reverse=True)
        scoville.pop()

        b = min(scoville)
        scoville = sorted(scoville, reverse=True)
        scoville.pop()
        
        scoville.append(a+2*b)
        count += 1

    return count

답은 잘 나오는데 1,3,8,14번이 런타임 에러로 실패했고 효율성 테스트를 다 실패했다.

최대 scoville 길이만큼 반복하는 코드의 시간 복잡도는 O(N * Nlog(N))입니다. 왜냐하면 매 반복시 정렬을 해주어야하기 때문입니다. 힙의 저장과 삭제 연산은 O(log(N))의 시간 복잡도를 가집니다. 출처 : 구르미의 개발 이야기

힙이란?

힙은 특정한 규칙을 가지는 트리로, 최댓값과 최솟값을 찾는 연산을 빠르게 하기 위해 고안된 완전이진트리를 기본으로 한다.

파이썬 힙 자료구조

파이썬 heapq 모듈은 heapq (priority queue) 알고리즘을 제공한다.

모든 부모 노드는 그의 자식 노드보다 값이 작거나 큰 이진트리(binary tree) 구조인데, 내부적으로는 인덱스 0에서 시작해 k번째 원소가 항상 자식 원소들(2k+1, 2k+2) 보다 작거나 같은 최소 힙의 형태로 정렬된다.

heapq는 내장 모듈로 별도의 설치 작업 없이 바로 사용할 수 있다.

힙 함수 활용하기

  • heapq.heappush(heap, item) : item을 heap에 추가
  • heapq.heappop(heap) : heap에서 가장 작은 원소를 pop & 리턴. 비어 있는 경우 IndexError가 호출됨.
  • heapq.heapify(x) : 리스트 x를 즉각적으로 heap으로 변환함 (in linear time, O(N) )

출처: 아기여우의 자기계발로그

제출 코드

import heapq
def solution(scoville, K):
    cnt = 0
    heapq.heapify(scoville)

    while scoville[0] < K:
        if len(scoville) == 1 and scoville[0] < K:
            return -1
        
        heapq.heappush(scoville, heapq.heappop(scoville)+heapq.heappop(scoville) * 2)
        cnt += 1
    
    return cnt

주요 포인트 및 생각해볼 점

레벨1을 하면서 시간을 너무 많이 보낸 것 같다. 이번 주말에는 레벨2를 되도록 많이 다루면서 새로운 개념에 대해서 알아봐야겠다.

그래프 탐색 알고리즘 BFS/DFS

|

BFS, DFS의 5분 설명 및 코드화

DFS 코드

__author__ = 'Minsuk Heo'

vertexList = ['0', '1', '2', '3', '4', '5', '6']
edgeList = [(0,1), (0,2), (1,0) , (1,3) , (2,0) , (2,4) , (2,5) , (3,1), (4,2) , (4,6), (5,2), (6,4)]
#각 번호별로 인접한 번호가 무엇이 있는지 리스트로 저장
graphs = (vertexList, edgeList)


def dfs(graph, start):
    vertexList, edgeList = graph
    visitedVertex = []
    stack = [start]
    #스택을 하나 준비해주세요, stack에 0을 집어넣으면 while 루프가 실행이 됩니다..?
    adjacencyList = [[] for vertex in vertexList]
    #인접 리스트 생성
    for edge in edgeList:
        adjacencyList[edge[0]].append(edge[1])
    # adjacencyList : 
    #[
    #   [1,2] // vertex 0
    #   [0,3] // vertex 1
    #   [0,4,5] // vertex 2
    #   [1] // vertex 3
    #   [2,6] // vertex 4
    #   [2] // vertex 5
    #   [4] // vertex 6
    #]  
    while stack:
        current = stack.pop()
        # 0이 스택을 거쳐 커렌트에 들어간다
        for neighbor in adjacencyList[current]:
            # 커렌트에 들어있는 0의 이웃들 중에서
            if not neighbor in visitedVertex:
                # 이미방문한숫자 리스트에 들어있지 않다면 
                stack.append(neighbor)
                # 0의 이웃인 1과 2가 스택에 들어간다 
        visitedVertex.append(current)
        #이미방문한숫자 리스트에 커렌트에 있는 0을 넣어준다
    return visitedVertex

print(dfs(graphs, 0))

BFS(너비우선탐색)와 DFS(깊이우선탐색)의 차이

dfs bfs의 차이

BFS 코드

__author__ = 'Minsuk Heo'

vertexList = ['A', 'B', 'C', 'D', 'E', 'F', 'G']
edgeList = [(0,1), (1,2), (1,3), (3,4), (4,5), (1,6)]
graphs = (vertexList, edgeList)

def bfs(graph, start):
    vertexList, edgeList = graph
    visitedList = []
    queue = [start]
    adjacencyList = [[] for vertex in vertexList]

    # fill adjacencyList from graph
    for edge in edgeList:
        adjacencyList[edge[0]].append(edge[1])

    # bfs
    while queue:
        current = queue.pop()
        for neighbor in adjacencyList[current]:
            if not neighbor in visitedList:
                queue.insert(0,neighbor)
        visitedList.append(current)
    return visitedList

print(bfs(graphs, 0))

주요 포인트 및 생각해볼 점

자료구조의 개요

1)선형 구조

  • 배열, 연결 리스트, 스택, 큐

2)비선형 구조

  • 트리, 그래프

트리와 그래프에 대해서 더 공부해봐야겠다! - 2021.10.21

자료구조 인강을 다시 들어봐야겠다. 초보몽키 블로그 - 강의노트 17. 알고리즘, 자료구조 개요

sys.argv를 이용해 숫자맞추기 게임 만들기

|

sys.argv

파이썬으로 작성된 파일을 실행할 때 인수(argument, 인자값)를 받아서 처리를 해야 되는 경우가 있다. 예를 들어, 로컬과 개발 등의 환경이 서로 달라서 인자값을 줘야 한다던지 같은 파일을 다른 목적으로 처리를 해야 할 때 인자값을 줄 수가 있을 것이다. 이럴때 파이썬에서는 sys.argv에 값을 담아 처리를 할 수 있게 된다.

#커맨드를 통해 hello.py 파일에 neo값을 주고 실행한다.
python3 hello.py neo

hello.py파일에서 sys를 임포트한다.

import sys
print(sys.argv)

hello.py파일에서 sys.argv를 출력해보면 아래와 같이 나온다.

(base) C:\python>python hello.py neo ['hello.py', 'neo']

첫번째는 파일 이름, 두번째부터 입력된 인수값들이 나온다.

출처: https://needneo.tistory.com/95 [네오가 필요해]

sys.argv 를 이용한 숫자맞추기 게임을 만들어보자

유데미 - complete python developer zero to mastery 과정에서 만들었다.

from random import randint
#random모듈에서 임의의 수를 뽑아주는 randint함수를 임포트한다
import sys
#sys모듈을 임포트한다
answer = randint(int(sys.argv[1]), int(sys.argv[2]))
#1번째 수와 2번째 수 사이의 임의의 수를 뽑아서 answer변수에 저장한다.
#sys.argv를 사용함으로서 1번째 수와 2번째 수 매개변수를 다른 파일에서 가져올 수 있다.
while True:
    try: # 예외처리 try, except
        guess = int(input(f'guess a number {sys.argv[1]}~{sys.argv[2]}:  '))
        #1번째 수와 2번째 수 사이의 수를 추측하세요 : 수를 입력받아서 guess변수에 저장
        if  0 < guess < 11:
            if guess == answer:
                print('you are a genius!')
                break
        else:
            #0에서 11사이의 정수가 아닌 다른 것을 입력한 경우
            print('hey bozo, I said 1~10')
    except ValueError:
        #정수가 아닌 다른 것을 입력한 경우
        print('please enter a number')
        continue

주의 할 점은 guess의 위치가 while문 안에 들어있다는 것이다.
sys.argv를 사용함으로서 인수값을 받거나 다른 파일에서 가져올 수 있었다.

파이썬 - 모듈(Module)과 패키지(Package)

|

모듈

모듈이란 함수나 변수 또는 클래스를 모아 놓은 파일이다.

파이썬과 모듈

파이썬 안에는 여러가지 모듈이 있는데, os모듈을 이용하면 운영체제에서 파일을 생성하거나 경로를 변경하는 등의 작업을 할 수 있다.

sys 모듈

sys : System-specific parameters and functions.
sys 모듈은 파이썬 인터프리터가 제공하는 변수와 함수를 직접 제어할 수 있게 해주는 모듈이다.

파이썬 공식문서

sys.module

import된 모듈과 패키지들을 딕셔너리 형태로 저장하고 있고 파이썬이 모듈이나 package를 찾기위해 가장 먼저 확인하는 곳이다.
한 번 import된 모듈과 package들은 파이썬이 또 다시 찾지 않아도 되도록 하는 기능을 가지고 있다.

sys.path

모듈을 찾을 때 참조하는 경로를 문자열 요소를 가진 리스트 형태로 저장한 것이다. 파이썬이 모듈과 패키지를 찾을 때 가장 마지막으로 보는 곳이다.

파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까?

  1. 전에 import했던 정보들을 저장해놓는 sys.modu.les를 확인하고
  2. 파이썬에서 제공하는 공식 라이브러리들(built-in modules)을 확인한 뒤
  3. 각 경로들을 포함하고 있는 sys.path(list)에서 하나 하나 확인 과정을 거친다.

Absolute path와 relative path

절대 위치는 최상위 디렉토리에서 시작해서 모듈 및 패키지의 시작부터 끝까지 생략, 축약되지 않고 명확히 명시된 경로를 표현해주는 것이고 상대 위치는 현재 파일의 위치를 기준으로 경로를 표현해주는 것이다.

calculator 패키지 만들기

주어진 코드대로 패키지를 만들고 실행하면 다음과 같은 에러가 나온다.

계산기 패키지 경로 에러

ImportError: attempted relative import with no known parent package

상위패키지를 못 찾아서 발생하는 에러다. main은 항상 절대경로를 이용해야한다.

add_and_multiply.py에서 multiply함수를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력해 보세요.

add_and_multiply.py 는 패키지 안에 들어있는 모듈이기 때문에 절대경로와 상대경로 모두 실행되며, main.py는 패키지 안에 들어있지 않기 때문에 상대경로는 실행이 안되고 절대경로만 실행이 된다.

init.py의 역할

해당 디렉토리가 패키지의 일부임을 알려주는 역할을 한다. python3.3 버전부터는 init.py 가 없어도 패키지로 인식한다. 하지만 하위호환을 위해 생성하는 것이 안전하다.

파이썬 - 튜플, 리스트, 셋, 딕셔너리(tuple, list, set, dictionary)

|

튜플 (1,2,3)

튜플은 변경이 불가능한 인자의 나열이고 메모리를 아끼거나 실수로 오염시키지 않기 위해 사용하는 원형의 데이터 타입이다.

a = 1,2,3
print(a)
#(1,2,3)

리스트 [1,2,2,3]

리스트는 튜플과 같지만 변형이 되는 자료형이다.

셋 {1,2,3}

셋은 중복되지 않은 유니크한 값들만 들어있는 집합의 자료형이다.

딕셔너리 {1:’일’}

딕셔너리는 키와 값이 한 쌍으로 이루어진 자료형이다.

파이썬에서 (), {}, []의 차이점

  arr = [] # 빈 배열을 만들 때 []사용  
  arr = [1,2,3,4] #원소가 있는 배열을 만들 때 []사용  
  arr[3] #배열의 3번째 원소에 접근할 때 []사용  

  mytuple = () #빈 튜플 생성할 때 ()사용  
  mytuple = (1,2,3,4) # 원소가 있는 튜플을 만들 때 ()사용  
  mytuple[3] # 튜플의 원소에 접근할 때 []사용  

  mydictionary = {} #빈 딕셔너리 생성 시 {}사용  
  mydictionary = {"mouse":3, "penguin":5}  
  mydictionary["mouse"] # key("mouse")에 대응하는 value(3)에 접근할 때 사용  
  mydictionary["cat"] = 1 # key("cat")에 대한 value(1) 생성  

출처: 해시코드 - () [] {}의 차이와 사용해야 할 곳

적용 예시

-리스트
JSON 포맷에서 사용된다
배열을 변형할 때 유용한다
데이터베이스에서 사용된다

-튜플
SQL쿼리로 데이터베이스에 값을 넣을 때 사용된다
예: (1.’sravan’, 34).(2.’geek’, 35)
괄호 체커에서 사용된다. -> ?

-셋
유니크한 값을 찾을 때 사용한다
오퍼레이션끼리 더할 때 사용한다 -> ? 교집합 합집합할 떄?

-딕셔너리
리스트로부터 데이터 프레임을 만들어낼때 사용
JSON에서 사용된다

출처1: 코리팁스
출처2: 긱스포긱스

파이썬 - 데이터베이스 클래스 구현

|

Database 라는 이름의 class를 구현해 주세요.

Database 클래스 내부에 다음의 속성(attribute)들을 선언해주세요.

name : database의 이름
size : 저장할 수 있는 데이터의 max 사이즈. Size를 넘어서는 데이터를 저장할 수 없다.
Database 클래스 내부에 다음의 메소드들을 구현해주세요.

insert, select, update, delete
각 메소드들에 대한 설명은 아래와 같습니다.

Insert

insert 메소드는 self 외에 2개의 parameter를 받습니다.

field와 value 입니다.

Field 는 저장하고자 하는 데이터의 필드명이고 value는 값입니다.

Field 와 value는 내부적으로 dictionary에 저장되어야 합니다.

insert 메소드는 다음 처럼 호출 할 수 있습니다.

객체 이름이 db 라는 가정하에 db.insert(“name”, “정우성”)
insert 메소드는 특별한 return 값은 없습니다.

단, 만일 내부 dictionary의 총 사이즈가 Database 클래스의 size 속성보다 크면 더이상 새로운 값들을 저장하지 말아야 합니다.

Select

select 메소드는 self 외에 1개의 parameter를 받습니다.

바로 field 입니다.

field 는 읽고자 하는 데이터의 필드명 입니다.

내부적으로 데이터를 저장하고 있는 dictionary에서 해당 field에 해당하는 키와 연결되어 있는 값을 return 해주어야 합니다.

예를 들어, 이미 name이라는 필드명으로 “정우성” 이라는 값을 저장했다고 한다면:

객체 이름이 db 라는 가정하에 db.select(“name”)

“정우성” 이 되어야 합니다.

만일 해당 필드값으로 저정되어 있는 값이 없다면 None 을 return 해주세요.

Update

self 외에 2개의 parameter를 받습니다.

field와 value 입니다.

이름 그대로 이미 저장되어 있는 값을 수정하는 메소드 입니다.

객체 이름이 db 라는 가정하에 db.update(“name”, “아이유”)

만일 field값에 해당하는 데이터가 저장되어 있지 않으면 아무것도 하지 않습니다.

그리고 특별한 return 값은 없습니다.

Delete

delete 메소드는 self 외에 1개의 parameter를 받습니다.

field 입니다.

field 는 지우고자 하는 데이터의 필드명 입니다.

객체 이름이 db 라는 가정하에
db.delete(“name”)
만일 field값에 해당하는 데이터가 저장되어 있지 않으면 아무것도 하지 않습니다.

그리고 특별한 return 값은 없습니다.

class Database:
  def __init__(self, name, size):
    self.name = name
    self.size = size
    self.db = {} #db라는 빈 리스트를 생성한다
  
  def insert(self, field, value):
    if len(self.db) < self.size:
      self.db[field] = value 
      #db의 해당 필드값에 값을 넣는다

  def select(self, field):
    if field in self.db:
      return self.db[field]
    else:
      return None

  def update(self, field, value):
    if field in self.db:
      self.db[field] = value

  def delete(self, field):
    if field in self.db:
      del self.db[field]

파이썬 - 인수의 순서 및 위치

|

위치 인수와 가변 인수

아래의 함수를 실행하면 TypeError: func() missing 1 required keyword-only argument: ‘age’ 에러가 나게된다.

def func_param_with_var_args(name, *args, age):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
 
func_param_with_var_args("정우성", "01012341234", "seoul", 20)

메소드를 호출할 때, 가변인수 이후 모든 인수를 가변인수로 인식하여 age인수에 아무 값도 들어오지 않았기 때문이다. 메소드를 호출할 때 인자 이름을 명시적으로 표기해주면 문제를 해결할 수 있다.

func_param_with_var_args("정우성", "01012341234", "seoul", age = 20)

아니면 아래와 같이 가변인수를 위치인수 뒤에 위치해야한다.

def func_param_with_var_args(name, age, *args):

출처 : 우공이산 블로그

위치 인수와 키워드 가변 인수

키워드 가변인수를 키워드 인수 앞에 쓰면 이렇게 신택스 에러가 난다. 키워드 가변 인수의 위치 에러

그래서 키워드 인수 address =0을 쓰고 그 뒤에 키워드 가변인수를 써줘야한다.

인수의 올바를 위치 예시

위치 인수 > 디폴트 인수 > 가변인수 > 키워드 인수 > 키워드 가변인수

인수의 위치와 순서

모든 인수의 위치는 정리하자면 위와 같다.
받게될 위치와 값이 정확한 인수들이 앞에 오고 가변적인 인수가 뒤에 온다.

주요 포인트 및 생각해볼 점

디폴트 인수와 키워드 인수는 똑같이 생겼다. 함수를 직접 작성하다보면 이 개념들을 더 잘 이해할 수 있지 않을까?