<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>choich_0807.log</title>
        <link>https://velog.io/</link>
        <description>chch_oi </description>
        <lastBuildDate>Mon, 07 Mar 2022 06:32:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>choich_0807.log</title>
            <url>https://images.velog.io/images/choich_0807/profile/086fc64e-2280-4e5c-a968-cf5233cce30b/KakaoTalk_20211115_204541018.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. choich_0807.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/choich_0807" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[MY-JEJU-STAY PROJECT 회고]]></title>
            <link>https://velog.io/@choich_0807/MY-JEJU-STAY-PROJECT-%ED%9A%8C%EA%B3%A0</link>
            <guid>https://velog.io/@choich_0807/MY-JEJU-STAY-PROJECT-%ED%9A%8C%EA%B3%A0</guid>
            <pubDate>Mon, 07 Mar 2022 06:32:30 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>프로젝트가 끝난 후 바로 회고를 작성하려했지만 
심각한 체력고갈로 휴식을 취한 후 바로 기업협업이 시작되어서 
회고작성이 늦어졌다. 그래도 나에게는 어떻게 보면 JU-LABO 프로젝트보다
의미있는 프로젝트였기 때문에 틈틈히 회고를 써보려한다.</p>
<hr>
<h1 id="overview">OVERVIEW</h1>
<ul>
<li>클론 사이트 </li>
</ul>
<blockquote>
<p>마이리얼트립 <a href="https://www.myrealtrip.com/?utm_source=google&amp;utm_medium=search_pc&amp;utm_campaign=44443142579&amp;utm_term=%EB%A7%88%EC%9D%B4%EB%A6%AC%EC%96%BC%ED%8A%B8%EB%A6%BD&amp;gclid=CjwKCAiAjoeRBhAJEiwAYY3nDLcfCANyxmilDiwyi18ydINRHY-_uqMJOoH78YqbbZjp95K1tNIomxoC-TIQAvD_BwE">https://www.myrealtrip.com/?utm_source=google&amp;utm_medium=search_pc&amp;utm_campaign=44443142579&amp;utm_term=%EB%A7%88%EC%9D%B4%EB%A6%AC%EC%96%BC%ED%8A%B8%EB%A6%BD&amp;gclid=CjwKCAiAjoeRBhAJEiwAYY3nDLcfCANyxmilDiwyi18ydINRHY-_uqMJOoH78YqbbZjp95K1tNIomxoC-TIQAvD_BwE</a></p>
</blockquote>
<ul>
<li>사이트 소개</li>
</ul>
<blockquote>
<ul>
<li>마이리얼트립은 여행을 떠나기 위해 필요한 모든 것을 한 곳에서 검색하고 예약할 수 있는 국내 최고의 Travel Super App 이다.</li>
</ul>
</blockquote>
<ul>
<li><p>여행 준비, 항공, 숙박, 현지 교통, 현지 경험 (투어, 티켓, 특가 여행, 패키지) 등 모든 여행 경험을 연결하여 새로운 여행 방식을 만들어간다.</p>
</li>
<li><p>프로젝트 기간</p>
</li>
</ul>
<blockquote>
<p>2022/02/14 ~ 2022/02/25 </p>
</blockquote>
<hr>
<h1 id="introduce-team팀-소개">INTRODUCE TEAM(팀 소개)</h1>
<ul>
<li>팀명</li>
</ul>
<blockquote>
<p>MY-JEJU-STAY (마이제주스테이)</p>
</blockquote>
<ul>
<li>팀원들</li>
</ul>
<blockquote>
<ul>
<li>Frontend - 정수진, 석정도, 임채현, 김지윤</li>
</ul>
</blockquote>
<ul>
<li>Backend - 최창현, 모휘정</li>
</ul>
<hr>
<h1 id="my-jeju-stay-goals목표">MY-JEJU-STAY GOALS(목표)</h1>
<ul>
<li>단순히 숙소 예약 서비스를 제공하는 사이트는 많기 때문에
회의를 통해 “제주한달살기”라는 기획 아이디어를 내었다.</li>
</ul>
<blockquote>
<p>핵심 서비스</p>
</blockquote>
<ul>
<li>제주 한달살기에 적합한 숙소(&amp;체험) 예약 및 결제를 도와주는 서비스를 제공한다.</li>
</ul>
<blockquote>
<p>제공하는 메인 서비스</p>
</blockquote>
<ul>
<li><p>로그인, 회원가입 (소셜 로그인)</p>
</li>
<li><p>메인 페이지</p>
</li>
<li><p>숙소 리스트&amp;지도</p>
</li>
<li><p>숙소 디테일 </p>
</li>
<li><p>숙소 예약</p>
</li>
<li><p>숙소 예약정보 확인</p>
</li>
</ul>
<blockquote>
<p>필수 구현 사항(구현 완료)</p>
</blockquote>
<ol>
<li>회원가입&amp;로그인</li>
<li>소셜로그인</li>
<li>숙소 리스트&amp;지도 페이지 </li>
<li>숙소 리스트&amp;지도 페이지 필터링 적용</li>
<li>숙소 상세 페이지</li>
<li>예약 기능</li>
<li>UNITTEST</li>
</ol>
<blockquote>
<p>추가 구현 사항(구현 완료)</p>
</blockquote>
<ol>
<li>마이 페이지</li>
<li>예약 정보 확인</li>
<li>AWS S3 버킷을 활용한 이미지&amp;영상 업로드</li>
<li>AWS&amp;DOCKER 배포</li>
</ol>
<hr>
<h1 id="used-stack사용된-기술">USED STACK(사용된 기술)</h1>
<blockquote>
<p>Backend</p>
</blockquote>
<ul>
<li>Python , Django , MySQL , CORS Header, Bcrypt, pyJWT</li>
</ul>
<blockquote>
<p>Frontend</p>
</blockquote>
<ul>
<li>HTML/CSS, JavaScript(ES6+), React, SASS</li>
</ul>
<blockquote>
<p>Communication Tool</p>
</blockquote>
<ul>
<li>Trello, Slack, Git, Github</li>
</ul>
<blockquote>
<p>Arcitecture</p>
</blockquote>
<ul>
<li>Docker, AWS EC2, AWS RDS, AWS S3, Postman, dbdiagram.io, httppi</li>
</ul>
<hr>
<h1 id="introduce-my-jeju-stay">INTRODUCE MY-JEJU-STAY</h1>
<blockquote>
<p>Database Modeling</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/3ee81018-e14d-48d6-bdba-c690e8002201/myjejustay%20dbdiagram.jpg" alt=""></p>
<blockquote>
<p>초기 세팅</p>
</blockquote>
<ol>
<li>가상환경, DATABASE 생성    </li>
<li>git repository clone</li>
<li>django install</li>
<li>django cors-headers install</li>
<li>mysqlclient install</li>
<li>git branch 생성</li>
<li>django project 생성</li>
<li>settings.py 생성</li>
<li>requirement.txt 생성</li>
<li>gitignore 생성</li>
<li>runserver 동작 확인</li>
</ol>
<blockquote>
<p>내가 작성한 API 목록</p>
</blockquote>
<ul>
<li><p>users/LoginView</p>
</li>
<li><p>users/KakaoLoginView</p>
</li>
<li><p>users/SignUpView</p>
</li>
<li><p>users/ReservationInfoView</p>
</li>
</ul>
<blockquote>
<p>KakaoLogin</p>
</blockquote>
<ul>
<li>인기 상품과 카테고리 메뉴 반환 </li>
<li></li>
</ul>
<blockquote>
<p>Search &amp; Filter(창현)</p>
</blockquote>
<ul>
<li><p>상품 검색 기능 ( 키워드가 포함된 상품) 
icontains를 사용하여 키워드와 상품의 이름을 비교하여 검색 기능을 구현했다.</p>
</li>
<li><p>Type(ml)을 통한 상품 리스트 필터
상품 리스트 페이지에서 ml별로 상품을 필터할 수 있도록 기능을 구현했다.</p>
</li>
</ul>
<blockquote>
<p>Popular Product(창현)</p>
</blockquote>
<ul>
<li>인기상품을 구별하기 위한 기능
user테이블과 product 테이블 사이에 중간 테이블을 만들어서
user가 product를 조회(클릭)했을 때 테이블에 user_id와 product_id를 저장하도록 구현했다.
get_or_create를 사용해 user의 중복클릭을 방지 했다.</li>
</ul>
<hr>
<h1 id="좋았던-점">좋았던 점</h1>
<p> &#39;첫 번째 팀 프로젝트&#39; 라는게 나에게 가장 좋았던 점이였다.
 혼자 알고리즘 문제를 푸는것도 재미있지만 팀 프로젝트를 경험해보니
 나에게는 사람들과 함께 개발하는 환경이 더 즐겁다는걸 느꼈다.
 물론 우리 팀원들이 좋은 사람이였던것도 있지만 목적지를 항해 함께 달려가는
 동료가 있어서 프로젝트를 별탈없이 마무리할 수 있었던 것 같다.</p>
<p> 또한 피어리뷰또한 색다른 즐거움이였다.
 다른사람의 코드를 보는것이 익숙하진 않았지만 코드를 살펴보는 것만으로도
 배우는게 많다는 것을 느꼈다.</p>
<h1 id="아쉬운-점">아쉬운 점</h1>
<p>돌이켜보면 좋았던 점보다 아쉬운 점이 많았다.
주라보 프로젝트는 PM이 없이 진행됐다. PM이 필요하다는것도 거의 마지막에 알게되었다. 첫 프로젝트이다보니 서로 기능 개발하기 바빠서도 이유 중 하나일것이다.
나도 팀에게 도움이되고 싶어서 열심히 기능개발에만 몰두했었다.
하지만 좋은기능을 빨리 만든다고 팀에게 큰 도움이 되는것만은 아니다.
백엔드가 api를 미리 만들어두어도 함께 일하는 프론트가 준비되지 않았다면 의미가 없는것처럼 말이다. </p>
<h1 id="마무리">마무리</h1>
<p>정말 좋은 기억으로 남는 1차 프로젝트였다. 추가 기능 구현도 성공적으로 해내서 정말 만족스럽다고 생각한다. 하지만 좋은 기억보단 아쉬웠던 점들을 상기하며 2차 프로젝트를 준비하려한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[docker compose를 활용한 서버 구현 ]]></title>
            <link>https://velog.io/@choich_0807/docker-compose%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@choich_0807/docker-compose%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%84%9C%EB%B2%84-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Mon, 28 Feb 2022 09:12:35 GMT</pubDate>
            <description><![CDATA[<h1 id="docker-compose">docker compose?</h1>
<p>Docker compose란, 여러 개의 컨테이너로부터 이루어진 서비스를 구축, 실행하는 순서를 자동으로 하여, 관리는 간단히하는 기능이다.</p>
<p>Docker compose에서는 compose 파일을 준비하여 커맨드를 1회 실행하는 것으로, 그 파일로부터
설정을 읽어들여 모든 컨테이너 서비스를 실행시키는 것이 가능하다.</p>
<h1 id="docker-compose-사용-단계">docker compose 사용 단계</h1>
<p>docker compose를 사용하기 위해서는, 크게 나눠 아래의 세 가지 순서로 이루어진다.</p>
<blockquote>
<ol>
<li>각각의 컨테이너의 dockerfile을 작성한다(기존에 있는 이미지를 사용하는 경우는 불필요)</li>
<li>docker-compose.yml를 작성하고, 각각 독립된 컨테이너의 실행 정의를 실시한다(경우에 따라 구축 정의도 포함).</li>
<li>&#39;docker-compose up&#39; 커맨드를 실행하여 docker-compose.yml으로 정의한 컨테이너를 개시한다.</li>
</ol>
</blockquote>
<p>docker compose는 start,stop,status, 실행 중의 컨테이너의 로그 출력, 약간의 커맨드의 
실행 같은 기능도 가지고 있다.</p>
<h1 id="docker-composeyml-파일">docker-compose.yml 파일?</h1>
<p>coker compose.yml 파일은 아래와 같이 yaml으로 docker 컨테이너에 관한 실행 옵션(build 옵션도 포함되어 있는 경우도 있다)를 기재한 파일이 된다.</p>
<p><img src="https://images.velog.io/images/choich_0807/post/9789c31b-2aea-4bf5-8bd6-883ab42e8c92/image.png" alt=""></p>
<p>이 파일에 기재되어 있는 내용은 기본적으로 docker build, docker run 커맨드 지정하는 것이 가능한 옵션이 되지만, Docker compose의 yaml 파일로써 기술하는 것으로 여러 개의 컨테이너로부터 만들어진 서비스를 조감하여 보는 것도 가능해져, 보존성의 수고를 가볍게 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Fast API 기본 사용법]]></title>
            <link>https://velog.io/@choich_0807/Fast-API-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95</link>
            <guid>https://velog.io/@choich_0807/Fast-API-%EA%B8%B0%EB%B3%B8-%EC%82%AC%EC%9A%A9%EB%B2%95</guid>
            <pubDate>Mon, 28 Feb 2022 08:56:46 GMT</pubDate>
            <description><![CDATA[<p>오늘부터 시작된 기업협업에서 Django 대신 FastAPI를 사용하게되었다.
Django와 비슷한 프레임워크인데, 공식문서를 살펴보면 알겠지만 사용법이 훨씬 간단하다. </p>
<h1 id="fast-api">Fast API?</h1>
<p><img src="https://images.velog.io/images/choich_0807/post/62ad5259-73dd-42d2-899e-3d5d966d2af9/image.png" alt=""></p>
<h1 id="fast-api-설치">Fast API 설치</h1>
<blockquote>
<pre><code>pip install fastapi
pip install uvicorn[standard]</code></pre></blockquote>
<pre><code>
위 두가지 패키지 설치가 필요하다.

# Fast API 서버 구현

일단 예제로 main.py를 만들어보자!
코드는 다음과 같이 작성해주면 된다.

&gt;```
from typing import Optional
&gt;
from fastapi import FastAPI
&gt;
app = FastAPI()
&gt;
@app.get(&quot;/&quot;)
def read_root():
    return {&quot;Hello&quot;: &quot;World&quot;}
&gt;
@app.get(&quot;/items/{item_id}&quot;)
def read_item(item_id: int, q: Optional[str] = None):
    return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}</code></pre><p>작성했다면 바로 서버를 실행해보자!</p>
<blockquote>
<pre><code>uvicorn main:app --reload</code></pre></blockquote>
<pre><code>
위의 명령어를 실행하면 서버가 실행된다.
서버가 제대로 켜졌는지 확인하기 위해 127.0.0.1:8000 주소로 들어가보자.

# 대화형 API 문서
http://127.0.0.1:8000/docs 로 들어가면 자동 대화형 API 문서를 확인할 수 있다.

http://127.0.0.1:8000/redoc 로 들어가면 다른 자동 문서도 확인할 수 있다.</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[JU-LABO Project 회고]]></title>
            <link>https://velog.io/@choich_0807/1st-Project-JU-LABO-%ED%9A%8C%EA%B3%A0%EC%9E%91%EC%84%B1%EC%A4%91</link>
            <guid>https://velog.io/@choich_0807/1st-Project-JU-LABO-%ED%9A%8C%EA%B3%A0%EC%9E%91%EC%84%B1%EC%A4%91</guid>
            <pubDate>Sun, 13 Feb 2022 07:36:06 GMT</pubDate>
            <description><![CDATA[<h1 id="서론">서론</h1>
<p>정신없이 몰두했던 첫번째 프로젝트가 끝난 후 회고를 해보려한다.
너무 좋은 팀원들을 만났지만, 서로 협업이 어색한 상황에서
기능구현과 처음보는 에러와 복합적인 여러가지 일들이 벌어졌었다.
하지만 우리는 포기하지 않았고 좋은 결과물을 만들어냈다고 생각한다. (주라보 팀원들 사랑해)
서론은 길면 안되니까 바로 회고를 시작해보자!</p>
<hr>
<h1 id="overview">OVERVIEW</h1>
<ul>
<li>클론 사이트 </li>
</ul>
<blockquote>
<p>LE LABO <a href="https://www.lelabofragrances.com/">https://www.lelabofragrances.com/</a></p>
</blockquote>
<ul>
<li>사이트 소개</li>
</ul>
<blockquote>
<ul>
<li>2006년 프랑스 출신의 두 창립자 에디 로시와 파브리스 페노가 뉴욕 놀리타에서 시작한 니치 향수 브랜드이다. </li>
</ul>
</blockquote>
<ul>
<li><p>브랜드 명은 프랑스어로 ‘실험실’이라는 단어를 그대로 따온 이름으로 조향사의 연구실에서 일어나는 다양한 일에서 영감을 얻어 만든 컬트 향수 브랜드 명이다. </p>
</li>
<li><p>원재료에 대한 존중을 기반으로 르라보의 이름을 알린 ‘상탈 33’, 머스크와 살냄새의 조화를 이룬 ‘어나더 13’ 등 매력적이고 유니크하며 매니악한 향수 스펙트럼을 눈여겨 볼 수 있다.</p>
</li>
<li><p>특히 구매자가 라벨에 원하는 이름, 문구를 새길 수 있는 ‘라벨링 서비스’를 이용 할 수 있다. </p>
</li>
<li><p>프로젝트 기간</p>
</li>
</ul>
<blockquote>
<p>2022/02/24 ~ 2022/02/11 (설날 연휴 포함)</p>
</blockquote>
<hr>
<h1 id="introduce-team팀-소개">INTRODUCE TEAM(팀 소개)</h1>
<ul>
<li>팀명</li>
</ul>
<blockquote>
<p>JU-LABO(주라보) 
술 주(酒) 를 사용해서 주라보라고 이름을 지었다.</p>
</blockquote>
<ul>
<li>사랑하는 팀원들</li>
</ul>
<blockquote>
<ul>
<li>Frontend - 윤남주, 김지연, 석정도</li>
</ul>
</blockquote>
<ul>
<li>Backend - 최창현, 최형택, 김지연</li>
</ul>
<p><img src="https://images.velog.io/images/choich_0807/post/2f5d27a5-a4d9-4430-b89b-c8b1118d9420/%EC%82%AC%EB%9E%91%ED%95%B4.jpg" alt=""></p>
<hr>
<h1 id="ju-labo-goals목표">JU LABO GOALS(목표)</h1>
<ul>
<li>우리팀은 르 라보의 웹 페이지의 디자인과 기능을 최대한 비슷하게 개발하거나 개선하는것을 목표로 삼았다.</li>
</ul>
<blockquote>
<p>핵심 서비스</p>
</blockquote>
<ul>
<li>계절 별 술 큐레이션</li>
</ul>
<blockquote>
<p>제공하는 메인 서비스</p>
</blockquote>
<p>👉 로그인, 회원가입을 활용한 쇼핑 기능(장바구니 기능 포함)</p>
<p>상품 리스트 페이지(카테고리별)</p>
<p>상품 상세정보 페이지</p>
<p>계절에 맞는 주류 추천</p>
<p>상품별 필터</p>
<p>인기 상품 추천</p>
<p>검색기능 추천</p>
<blockquote>
<p>필수 구현 사항(구현 완료)</p>
</blockquote>
<ol>
<li>회원가입</li>
<li>로그인</li>
<li>상품 리스트 페이지, 상품 목록 </li>
<li>상품 리스트 페이지, 상품 목록 필터링 적용</li>
<li>상품 상세 페이지</li>
<li>장바구니 기능</li>
<li>주문 기능</li>
<li>프로젝트 배포</li>
</ol>
<blockquote>
<p>추가 구현 사항(구현 완료)</p>
</blockquote>
<ol>
<li>메인 페이지</li>
<li>상품 검색 - 검색결과/인기순</li>
<li>제품 추천</li>
<li>어바웃 페이지 (<a href="http://www.elcakorea.com/brand/le_labo">http://www.elcakorea.com/brand/le_labo</a>)</li>
<li>AWS 배포</li>
</ol>
<hr>
<h1 id="used-stack사용된-기술">USED STACK(사용된 기술)</h1>
<blockquote>
<p>Backend</p>
</blockquote>
<ul>
<li>Python , Django , MySQL , CORS Header, Bcrypt, pyJWT</li>
</ul>
<blockquote>
<p>Frontend</p>
</blockquote>
<ul>
<li>HTML/CSS, JavaScript(ES6+), React, SASS</li>
</ul>
<blockquote>
<p>Communication Tool</p>
</blockquote>
<ul>
<li>Trello, Slack, git, github</li>
</ul>
<blockquote>
<p>Arcitecture</p>
</blockquote>
<ul>
<li>AWS EC2, AWS RDS, Postman, dbdiagram.io, httppi</li>
</ul>
<hr>
<h1 id="introduce-ju-labo">INTRODUCE JU LABO</h1>
<blockquote>
<p>Database Modeling</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/67a8b538-26c2-4c3b-8f6a-646d6a93eb1f/image.png" alt=""></p>
<blockquote>
<p>초기 세팅</p>
</blockquote>
<ol>
<li>가상환경, DATABASE 생성    </li>
<li>git repository clone</li>
<li>django install</li>
<li>django cors-headers install</li>
<li>mysqlclient install</li>
<li>git branch 생성</li>
<li>django project 생성</li>
<li>settings.py 생성</li>
<li>requirement.txt 생성</li>
<li>gitignore 생성</li>
<li>runserver 동작 확인</li>
</ol>
<blockquote>
<p>JU LABO 메인 화면 소개</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/07a9bcb6-a316-46eb-bf8a-d4d6fe98fb39/main.gif" alt=""></p>
<ul>
<li>(우리팀 프론트엔드 자랑ㅎㅎ) </li>
</ul>
<blockquote>
<p>내가 작성한 API 목록</p>
</blockquote>
<ul>
<li><p>categories/SubcategoriesView</p>
</li>
<li><p>products/ProductListView</p>
</li>
<li><p>users/PopularProductView</p>
</li>
</ul>
<p>url 엔드포인트/코드/ </p>
<blockquote>
<p>Header &amp; Product List(창현)</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/e849afa4-023e-4d06-82ed-59b2dfd1973e/header.gif" alt=""></p>
<ul>
<li>인기 상품과 카테고리 메뉴 반환 </li>
<li>상품 리스트 반환 </li>
</ul>
<blockquote>
<p>Search &amp; Filter(창현)</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/601f3c81-ab5c-4cdb-8d47-0f46a1ce5609/filterItemList.gif" alt=""></p>
<ul>
<li><p>상품 검색 기능 ( 키워드가 포함된 상품) 
icontains를 사용하여 키워드와 상품의 이름을 비교하여 검색 기능을 구현했다.</p>
</li>
<li><p>Type(ml)을 통한 상품 리스트 필터
상품 리스트 페이지에서 ml별로 상품을 필터할 수 있도록 기능을 구현했다.</p>
</li>
</ul>
<blockquote>
<p>Popular Product(창현)</p>
</blockquote>
<ul>
<li>인기상품을 구별하기 위한 기능
user테이블과 product 테이블 사이에 중간 테이블을 만들어서
user가 product를 조회(클릭)했을 때 테이블에 user_id와 product_id를 저장하도록 구현했다.
get_or_create를 사용해 user의 중복클릭을 방지 했다.</li>
</ul>
<hr>
<h1 id="기억에-남는-코드--어려웠던-점">기억에 남는 코드 &amp; 어려웠던 점</h1>
<p>소개하고 싶은 코드가 너무 많지만 가장 기억에 남는 두가지 코드를 소개해 볼까한다.</p>
<blockquote>
<p>productlist API</p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/7642ed09-0c27-479b-a5bb-1f26eb6610e3/image.png" alt=""></p>
<p>원래 productlistview/typeview/productsearchview/productorderingview 와 같이 4가지 뷰로 위 사진의 기능이 나눠져 있었는데 멘토님이 비슷한 결과를 리턴하는것 같다고 하셔서 뷰를 하나로 합치게 되었다. 기능들이 합쳐지면서 if문을 통한 분기점이 생기긴 했지만 개인적으로 만족스런 로직이였다.</p>
<blockquote>
<p>popularproduct API </p>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/b98c4ae8-bdd1-408f-9771-a319edbaf293/image.png" alt=""></p>
<p>르 라보 홈페이지에서는 인기 상품이 노출되어있는데, 어떤식으로 인기 상품을 구현할까 고민하다가 생각하게된 코드이다. 유저가 상품을 클릭하면 유저 id와 상품 id가 데이터베이스에 쌓이고 중복 클릭을 막기위해 get_or_create를 사용하였다.</p>
<h1 id="좋았던-점">좋았던 점</h1>
<p> &#39;첫 번째 팀 프로젝트&#39; 라는게 나에게 가장 좋았던 점이였다.
 혼자 알고리즘 문제를 푸는것도 재미있지만 팀 프로젝트를 경험해보니
 나에게는 사람들과 함께 개발하는 환경이 더 즐겁다는걸 느꼈다.
 물론 우리 팀원들이 좋은 사람이였던것도 있지만 목적지를 항해 함께 달려가는
 동료가 있어서 프로젝트를 별탈없이 마무리할 수 있었던 것 같다.</p>
<p> 또한 피어리뷰또한 색다른 즐거움이였다.
 다른사람의 코드를 보는것이 익숙하진 않았지만 코드를 살펴보는 것만으로도
 배우는게 많다는 것을 느꼈다.</p>
<h1 id="아쉬운-점">아쉬운 점</h1>
<p>돌이켜보면 좋았던 점보다 아쉬운 점이 많았다.
주라보 프로젝트는 PM이 없이 진행됐다. PM이 필요하다는것도 거의 마지막에 알게되었다. 첫 프로젝트이다보니 서로 기능 개발하기 바빠서도 이유 중 하나일것이다.
나도 팀에게 도움이되고 싶어서 열심히 기능개발에만 몰두했었다.
하지만 좋은기능을 빨리 만든다고 팀에게 큰 도움이 되는것만은 아니다.
백엔드가 api를 미리 만들어두어도 함께 일하는 프론트가 준비되지 않았다면 의미가 없는것처럼 말이다. </p>
<h1 id="마무리">마무리</h1>
<p>정말 좋은 기억으로 남는 1차 프로젝트였다. 추가 기능 구현도 성공적으로 해내서 정말 만족스럽다고 생각한다. 하지만 좋은 기억보단 아쉬웠던 점들을 상기하며 2차 프로젝트를 준비하려한다. </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Stacks]]></title>
            <link>https://velog.io/@choich_0807/Python-Stacks</link>
            <guid>https://velog.io/@choich_0807/Python-Stacks</guid>
            <pubDate>Sat, 05 Feb 2022 10:47:42 GMT</pubDate>
            <description><![CDATA[<ul>
<li>스택의 구조</li>
</ul>
<p>기본적으로 스택은 넣을 때는 한쪽 끝에서 밀어넣어야 하고(push), 꺼낼 때에는
같은 쪽으로 뽑아 꺼내야한다.(pop) 간단히 그림으로 나타내면 다음과 같다.</p>
<blockquote>
<p>이와 비슷한 선형 자료구조 큐(Queue)는 좀 다르다. 큐는 &#39;선입선출&#39;의 구조로서,
먼저 들어간 요소가 가장 먼저 나오는 구조이다. 기본적으로 스택은 한쪽에서 꺼내고
빼고를 하는 반면, 큐는 한쪽으로 들어가면 다른쪽에서 나온다! 그리고 스택은 가장
마지막에 들어간 가장 먼저 나온다. (후입선출)</p>
</blockquote>
<p>스택에는 정해진 저장 공간이 있다. 따라서 비어있는 스택에서 원소를 꺼내려 하거나,
꽉찬 스택에 데이터 원소를 넣으려고 할 때 문제가 발생한다. 이러한 문제들을 각각
Stack underflow, Stack overflow라고 칭한다. </p>
<ul>
<li>스택의 연산 및 구현</li>
</ul>
<p>스택의 연산에는 총 5가지가 있다. 각각은 다음과 같다.</p>
<blockquote>
<ul>
<li>Size: 현재 스택에 들어있는 원소의 수를 반환</li>
</ul>
</blockquote>
<ul>
<li>isEmpty(): 현재 스택이 비어있는지를 판단</li>
<li>push(x): 데이터 원소 x를 스택에 추가</li>
<li>pop(): 스택의 맨 위에 저장된 원소를 제거 (맨 마지막에 들어온게 맨 먼저 나옴)</li>
<li>peek(): 스택의 꼭대기(맨 마지막으로 push된, 앞으로 pop의 대상이 되는) 원소를 반환</li>
</ul>
<p>이들은 각각 Python의 배열과 양방향 연결리스트로 구현될 수 있다.</p>
<p>#python의 리스트로 스택 구현하기</p>
<blockquote>
</blockquote>
<pre><code>class ArrayStack:
&gt;
    def size(self):
        return len(self.data)
&gt;
    def isEmpty(self):
        return self.size==0
&gt;
    def push(self, item):
        self.data.append(item)
&gt;
    def pop(self):
        return self.data.pop()
&gt;
    def peek(self):
        return self.data[-1]</code></pre><p>양방향 연결리스트로도 동일한 작업을 수행할 수 있다.</p>
<blockquote>
</blockquote>
<pre><code># 양방향 연결리스트 정의
class Node:
    def __init__(self, item):
        self.data = item
        self.prev = None
        self.next = None # 양방향으로 연결된 모습
&gt;
class DoublyLinkedList:
    def __init__(self, item):
        self.nodeCount = 0
        self.head = None(None)
        self.tail = None(None)
&gt;
        self.head.prev = None
        self.head.next = self.tail
        self.tail.prev = self.head
        self.tail.next = None
&gt;
# 양방향 연결리스트로 스택 구현
class LinkedListStack:
    def __init__(self):
        self.data = DoublyLinkedList()
&gt;
    def size(self):
        return self.data.getLength()
&gt;
    def isEmpty(self):
        return self.size() == 0
&gt;
    def push(self, item):
        node = None(item)
        self.data.insertAt(self, size() +1, node)
&gt;
    def pop(self):
        return self.data.popAt(self.size())
&gt;
    def peek(self):
        return self.data.getAt(self.size()).data</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Linked List]]></title>
            <link>https://velog.io/@choich_0807/Python-Linked-List</link>
            <guid>https://velog.io/@choich_0807/Python-Linked-List</guid>
            <pubDate>Sat, 05 Feb 2022 09:52:40 GMT</pubDate>
            <description><![CDATA[<h1 id="연결리스트">연결리스트</h1>
<p><img src="https://images.velog.io/images/choich_0807/post/9b04b255-f868-4a35-ac4b-2a8944e09ee6/image.png" alt=""></p>
<p>Linked 리스트의 기본구조에 대해서 알아보자!</p>
<p>각 연결리스트는 Node로 구성되어있고, Node안에는 data와 link로 구성되어있다.
안에 들어있는 data는 그림에 나와있는 정수형 말고도 문자, 레코드 등 여러 구조가 가능하다.</p>
<p>Node를 코드로 구성해보면 다음과 같다.</p>
<blockquote>
<pre><code>class Node:
    def __init__(self, item):
        self.data = item # data
        self.next = None # next link (다음 인자를 가리킨다.)</code></pre></blockquote>
<pre><code>
여기서 next는 다음 노드에 접근하는 방법이다.

&gt;```
P.head == a
a.next == b
b.next == c</code></pre><p>또한, 연결리스트에서 중요한 속성은 크게 셋으로 나뉜다.</p>
<p>*Head
*Tail
*Number of Nodes</p>
<blockquote>
<pre><code>class LinkedList:
    def __init__(self):
        self.nodeCount = 0
        self.head = None
        self.tail = None</code></pre></blockquote>
<pre><code>
# 연결리스트의 연산 정의
연결리스트의 연산은 크게 특정 원소 참조, 순회, 원소 삽입, 삭제, 연결이 있다.

* 특정 원소를 참조할 때
pos번째의 node를 가리키고 싶을 때 쓰는 메서드이다.

&gt;```
def getAt(set, pos):
    if pos &lt;= 0 or pos &gt; self.nodeCount:
        return None  #특정 경우 제외
    i = 1
    curr =  self.head # 연결리스트의 첫번째 노드
&gt;
    # 앞에서부터 하나하나 탐색하기 때문에 선형탐색과 유사
    while i&lt;pos:
        curr = curr.next
        i += 1
    return curr</code></pre><p>단, pos의 예외 범위를 if로 지정해줘야한다!</p>
<ul>
<li>리스트를 순회할 때</li>
</ul>
<p>연결리스트에 들어있는 data를 리스트의 요소로 하나하나 append하고, 최정 리스트를 반환한다. 주의해야 할 점은, 리스트 안에 append 되어야 할 것이 node 자체가 아니라 node안의
data라는 것이다!</p>
<blockquote>
<pre><code>def traverse(self):
    t_list = []
    curr_node = self.head # 첫 노드에 접근
</code></pre></blockquote>
<pre><code>while curr_node != None # tail이 되면 none이 됨
    t_list.append(curr_node.data) # 노드가 아니라 item을 넣음
    curr_node = curr_node.next # 다음 노드에 접근</code></pre><blockquote>
</blockquote>
<pre><code>return t_list </code></pre><pre><code>

* 원소 삽입

연결리스트의 pos 위치에 원소를 삽입하는 기본 코드는 다음과 같다.
마지막에 nodeCount는 1을 더해준다!

&gt;```
def insertAt(self, pos, newNode):
    prev = self.getAt(pos-1) # post 이전의 노드를 prev로 설정
       newNode.Next = prev.next
    prev.next = nextNode
    self.nodeCount += 1</code></pre><p>근데 위 코드에는 예외 처리가 필요하다. 왜냐하면 삽입 위치가 맨 앞, 맨 끝일대를 처리하지 못하기 때문이다. 그래서 head와 tail을 따로 조정해주는 코드가 필요하다!</p>
<blockquote>
<pre><code>def insertAt(self, pos, newNode):
    # pos 예외 범위 지정
    if pos&lt;1 or pos&gt;self,nodeCount:
        return False
</code></pre></blockquote>
<pre><code># 리스트 맨 앞 삽입할 때
if pos==1:
    newNode.next = self.head # 기존 head가 newNode의 next로 밀려남
    self.head = newNode
else:
    prev = self.getAt(pos-1) # post 이전의 노드를 prev로 설정
    newNode.next = prev.next
    prev.next = nextNode</code></pre><blockquote>
</blockquote>
<pre><code># 리스트 맨 뒤 삽입할 때
if pos==self.nodeCount +1:
    self.tail = newNode</code></pre><blockquote>
</blockquote>
<pre><code>self.nodeCount += 1
return True</code></pre><pre><code>
하지만 여기서 tail을 찾으려면 앞에서부터 차근차근 찾아야한다.
그럼 선형 배열과 비슷한 복잡도가 발생하므로, 비효율적일 수 있다!
따라서 다음과 같이 코드를 수정해볼 수 있다.

&gt;```
def insertAt(self, pos, newNode):
    if pos&lt;1 or pos&gt;self.nodeCount:
        return False
&gt;
    if pos==1:
        newNode.next = self.head
        self.head = newNode
&gt;
    # prev를 미리 지정
    else:
        if pos == self.nodeCount +1:
            prev = self.tail
        else:
            prev = self.getAt(pos-1)
&gt;
        newNode.next = prev.next
        prev.next = newNode
&gt;
&gt;
    if pos == self.nodeCount + 1:
        self.tail = newNode
&gt;
    self.nodeCount += 1
    return True   </code></pre><p>이전 코드의 else: 부분을 tail일때와 tail이 아닐때로 나누어 tail연산이 구분되어 일어나도록 한다.</p>
<ul>
<li>이때 연결리스트의 원소 삽입 복잡도는 다음과 같다.
  맨 앞 삽입 : O(1)
  중간 삽입  : O(n)
  맨 끝 삽입 : O(1) # tail 포인터 때문</li>
</ul>
<ul>
<li>원소 삭제</li>
</ul>
<p>pos 위치에서 pop을 하면, 그 데이터를 리턴하게 한다.
기본 코드는 다음과 같다.</p>
<blockquote>
<pre><code>def popAt(self, pos):
    if pos&lt;1 or pos&gt;self.nodeCount:
        raise IndexError
</code></pre></blockquote>
<pre><code>curr = self.getAt(pos) #제거할 node
prev = self.getAt(pos-1) #이전 node</code></pre><blockquote>
</blockquote>
<pre><code>prev.next = self.getAt(pos+1)
self.nodeCount -= 1
return curr.data</code></pre><pre><code>
하지만 위 코드에도 예외 처리를 해줘야한다.
역시 맨 앞, 맨 뒤를 제거할 때 유일한 리스트 원소를 제거할 때를 처리하지 못한다!
해결 방법은 다음과 같다.

&gt;```
def popAt(self, pos):
    if pos&lt;1 or pos&gt;self.nodeCount:
        raise IndexError
&gt;
    curr = self.nodeCount == 1 &amp; pos ==1: # 유일한 리스트
        self.head = None
        self.tail = None
&gt;
    elif pos == 1: # 유일하지 않지만 맨 앞 삭제
        self.head = self.getAt(pos+1)
&gt;
    else:
        prev = self.getAt(pos-1)

        if self.nodeCount != pos: # 맨 뒤가 아닐 때
            prev.next = self.getAt(pos+1)
        else:
            self.tail = prev
            prev.next = None
&gt;
    self.nodeCount -= 1
    return curr.data</code></pre><ul>
<li>두 리스트 연결</li>
</ul>
<blockquote>
<pre><code>#L : 이어붙일 리스트
def concat(self. L):
    self.tail.next = L.head # 원래 리스트의 맨 끝이 이어붙일 리스트의 처음
</code></pre></blockquote>
<pre><code># L에 주어진 리스트가 빈 리스트일 때 예외처리</code></pre><blockquote>
</blockquote>
<pre><code>if L.tail:
    self.tail = L.tail # 내 원래 tail을 이어붙인 리스트의 tail로 가게함</code></pre><blockquote>
</blockquote>
<pre><code>self.nodeCount += L.nodeCount # count 두개를 합한 만큼</code></pre><pre><code>


</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Hash Table]]></title>
            <link>https://velog.io/@choich_0807/Python-Hash-Table</link>
            <guid>https://velog.io/@choich_0807/Python-Hash-Table</guid>
            <pubDate>Sat, 05 Feb 2022 05:57:55 GMT</pubDate>
            <description><![CDATA[<h1 id="해쉬-테이블hash-table">해쉬 테이블(Hash Table)</h1>
<ul>
<li>Hash Table이란 키(key)에 데이터(value)를 저장하는 데이터 구조다.</li>
<li>key를 통해 데이터를 바로 받아올 수 있어 속도가 빠르다.</li>
<li>파이썬 딕셔너리(dictionary) 타입이 해쉬 테이블의 예이다.</li>
<li>보통 배열로 미리 Hash Table 사이즈만큼 생성 후 사용한다. (공간과 탐색 시간을 맞바꾸는 기법)</li>
<li>파이썬에서는 딕셔너리가 있기 때문에 해쉬를 별도로 구현할 필요가 없다.</li>
</ul>
<p><img src="https://images.velog.io/images/choich_0807/post/3e2e8429-8758-4d5b-838d-338280a3aff3/image.png" alt=""></p>
<h1 id="해쉬-테이블-용어설명">해쉬 테이블 용어설명</h1>
<ul>
<li>해쉬(Hash) : 임의 값을 고정 길이로 변환하는 것</li>
<li>해쉬 테이블(Hash Table) : 키값의 연산에 의해 직접 접근이 가능한 데이터 구조</li>
<li>해싱 함수(Hashing Function) : Key에 대해 산술 연산을 이용해 데이터 위치를 찾을 수 있는 함수</li>
<li>해쉬 값(Hash Value) 또는 해쉬 주소(Hash Address) : Key를 해싱 함수로 연산해서 해쉬 값을 알아내고, 이를 기반으로 해쉬 테이블에서 해당 Key에 대한
데이터 위치를 일관성 있게 찾을 수 있음</li>
<li>슬롯(slot): 한 개의 데이터를 저장할 수 있는 공간</li>
<li>저장할 데이터에 대해 Key를 추출할 수 있는 별도 함수도 존재할 수 있음</li>
</ul>
<h1 id="해쉬-테이블-만들기">해쉬 테이블 만들기</h1>
<p>직접 코드로 구현해보자!</p>
<blockquote>
<pre><code>hash_table = list([i for i in range(10)])
print(hash_table) # [0,1,2,3,4,5,6,7,8,9]</code></pre></blockquote>
<pre><code>
# 해쉬 함수
* 다양한 해쉬 함수 고안 기법 중, 가장 간단한 방식은 Division 법(나누기를 통한 나머지 값을 사용하는 기법)

&gt;```
def hash_func(key):
    return key % 5</code></pre><p>이제 해쉬 테이블에 저장해보자.</p>
<ul>
<li>데이터에 따라 필요시 key 생성 방법 정의가 필요하다.</li>
</ul>
<blockquote>
<pre><code>data1 = &#39;changhyeon&#39;
data2 = &#39;choi&#39;
data3 = &#39;star&#39;
data4 = &#39;bucks&#39;
</code></pre></blockquote>
<p>print(ord(data1[0]), ord(data2[0]), ord(data3[0])) # 99 99 115
print(ord(data1[0]), hash_func(ord(data1[0]))) # 99 4
print(ord(data1[0]), ord(data4[0])) # 99 98</p>
<pre><code>
!해쉬 테이블 값 저장 예시
* data: value와 같이 data와 value를 넣으면, 해당 data에 대한 
key를 찾아서, 해당 key에 대응하는 해쉬주소에 value를 저장하는 예

&gt;```
def storage_data(data, value):
    key = ord(data[0])
    hash_address = hash_func(key)
    hash_table[hash_address] = value
&gt;
storage_data(&#39;changhyeon&#39;, &#39;19950807&#39;)</code></pre><p>!데이터 읽어보기</p>
<blockquote>
<pre><code>def get_data(data):
    key = ord(data[0])
    hash_address = hash_func(key)
    print(hash_table[hash_address])
</code></pre></blockquote>
<p>get_data(&#39;changhyeon&#39;) # 19950807</p>
<pre><code>
# 해쉬 테이블의 장단점
* 장점
데이터 저장/읽기 속도가 빠름(검색 속도 빠름!)
해쉬는 키에 대한 데이터가 있는지(중복) 확인이 쉬움
* 단점
일반적으로 저장공간이 좀 더 많이 필요함
여러 키에 해당하는 주소가 동일할 경우, 충동을 해결하기 위한 별도 자료구조가 필요
* 주요 용도s
검색이 많이 필요한 경우
저장, 삭제, 읽기가 빈번한 경우
캐쉬 구현시(중복 확인이 쉽기 때문)

# 해쉬 테이블의 시간 복잡도
* 일반적인 경우(Collision이 없는 경우)
O(1)
* 최악의 경우(Collision이 모두 발생하는 경우)
O(n)

# 해쉬 테이블 구현해보기
리스트 변수를 활용해서 해쉬 테이블을 구현해보자!
* 해쉬 함수: key ^% 8
* 해쉬 키 생성: hash(data)

&gt;</code></pre><p>hash_table = list([0 for i in range(8)])
print(hash_table) #[0, 0, 0, 0, 0, 0, 0, 0]</p>
<blockquote>
</blockquote>
<p>def get_key(data):
    return hash(data)</p>
<blockquote>
</blockquote>
<p>get_key(&#39;changhyeon&#39;) # -470506737412036400</p>
<blockquote>
</blockquote>
<p>def hash_func(key):
    return key % 8</p>
<blockquote>
</blockquote>
<p>def save_data(data, value):
    hash_address = hash_func(get_key(data))
    hash_table[hash_address] = value</p>
<blockquote>
</blockquote>
<p>def read_data(data):
    hash_address = hash_func(get_key(data))
    print(hash_address)
    print(hash_table[hash_address])</p>
<blockquote>
</blockquote>
<p>save_data(&#39;changhyeon&#39;, &#39;01091616424&#39;)
save_data(&#39;ch&#39;, &#39;01012345678&#39;)</p>
<blockquote>
</blockquote>
<p>read_data(&#39;changhyeon&#39;) #4 #01012345678
read_data(&#39;ch&#39;) #4 # 01012345678</p>
<blockquote>
</blockquote>
<p>print(hash_table) #[0, 0, 0, 0, &#39;01012345678&#39;, 0, 0, 0]</p>
<pre><code>

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] Comprehension]]></title>
            <link>https://velog.io/@choich_0807/Python-Comprehension</link>
            <guid>https://velog.io/@choich_0807/Python-Comprehension</guid>
            <pubDate>Thu, 03 Feb 2022 07:26:46 GMT</pubDate>
            <description><![CDATA[<h1 id="list-comprehension">List Comprehension</h1>
<p>list comprehension은 리스트를 쉽게 생성하기 위한 방법이다. 
python에서 보편적으로 사용되는 기능으로 다양한 응용이 가능하다.</p>
<p>일반적인 리스트 작성방식을 코드로 살펴보자!</p>
<blockquote>
<pre><code>list = []
for i in range(10):
    list.append(i)
print(list)
#[0,1,2,3,4,5,6,7,8,9]</code></pre></blockquote>
<pre><code>
## list comprehension의 기본형
list comprehension을 사용한다면 append 메서드를 사용하지 않고 한줄의 코드로
같은 위와 동일한 리스트를 작성할 수 있다. list comprehension의 기본적인 형태는 다음과 같다.

&gt; [식 for 변수명 in iterable객체]

리스트나 튜플 등 iterable한 객체의 각 요소를 임의의 변수로 꺼내 식을 적용하여 그 결과가 요소가 되는 새로운 리스트가 리턴되는 방식이다.

처음 살펴봤던 리스트 작성코드를 list comprehension 을 활용해서 다시 작성해보자!

&gt;```
list = [i for i in range(10)]
print(list)
#[0,1,2,3,4,5,6,7,8,9]</code></pre><h2 id="if로-조건분기하는-list-comprehension">if로 조건분기하는 list comprehension</h2>
<p>같은 줄에 조건(if)을 설정하여 원하는 결과를 가진 list를 만들 수 있다.</p>
<blockquote>
<pre><code>list = [i for i in range(10) if i % 2 == 0]
print(list)
#[0,2,4,6,8]</code></pre></blockquote>
<pre><code>
## 삼항 연산자의 활용 (if else등의 처리)

if로만 조건을 처리하면 조건을 만족하는 요소만 리스트에 포함되어 반환되고
조건을 만족하지 못한 요소는 삭제된다. 그러나 if else와 같이 조건을 만족하지 않은 요소에 대해서도 별도의 처리가 필요한 경우 삼항 연산자를 이용하여 if else와 같은 처리를 할수 있다.

삼항 연산자를 활용한 list comprehension의 예시는 다음과 같다.

&gt; [조건과 일치했을 때의 값 if 조건식 else 불일치시의 값 for 변수명 in iterable객체]

&gt;```
list = [&#39;odd&#39; if i %2 == 1 else&#39;even&#39; for i in range(10)]
#[&#39;even&#39;, &#39;odd, &#39;even&#39;, &#39;odd, &#39;even&#39;, &#39;odd, &#39;even&#39;, &#39;odd, &#39;even&#39;, &#39;odd,]</code></pre><h2 id="중첩-for문의-활용">중첩 for문의 활용</h2>
<p>중첩된 for문을 한 줄로 정의하는 것도 가능하다. for 루프를 중첩하여 복수의 iterable 객체를 결합할 수 있다.</p>
<p>중첩 for문을 활용한 list comprehension의 예시는 다음과 같다.</p>
<blockquote>
<p>[식 for 변수명1 in iterable객체1 for 변수명2 in iterable객체2]</p>
</blockquote>
<blockquote>
<pre><code>list = [(i,j) for i in range(10) for j in range(i, 10)]
print(list)
#[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 6), (6, 7), (6, 8), (6, 9), (7, 7), (7, 8), (7, 9), (8, 8), (8, 9), (9, 9)]</code></pre></blockquote>
<pre><code>
## zip(), enumerate()와의 결합

for 문에서 자주 사용되는 편리한 함수로 복수의 reternal을 모아주는 zip()이나 인덱스와 값을 return하는 enumerate()가 있다.

zip()이나 enumerate()를 list comprehension에 사용하는 것도 물론 가능하다. 특수한 문법을 사용하는 것이 아니므로 for 문과의 대응을 생각하면 그렇게 어렵지 않다.

먼저 zip()의 활용방법을 살펴보자!

&gt;```
list1 = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;]
list2 = [&#39;x&#39;,&#39;y&#39;,&#39;z&#39;]

list_zip = [(l1,l2) l1,l2 in zip(list1, list2)]
print(list_zip)
#[(&#39;a&#39;,&#39;x&#39;), (&#39;b&#39;,&#39;y&#39;), (&#39;c&#39;,&#39;z&#39;)]</code></pre><p>다음으로 enumerate()의 활용방법을 살펴보자!</p>
<blockquote>
<pre><code>list = [&#39;a&#39;,&#39;b&#39;,&#39;c&#39;]
list_enumerate = [(i, j) for i, j in enumerate(list)]
print(list_enumerate)
#[(0,&#39;a&#39;),(1,&#39;b&#39;),(2,&#39;c&#39;)]</code></pre></blockquote>
<pre><code>
## Dict Comprehension

dict 객체도 comperhension으로 생성할 수 있다.
{} 안에 식의 부분에 키와 값 2개를 &#39;키:값&#39; 형태로 지정하여 작성하면 된다.

&gt; {키:값 for 변수명 in iterable객체}

키와 값에는 임의의 식을 지정할 수 있다.

&gt;```
list = [&#39;aa&#39;, &#39;bbb&#39;, &#39;cccc&#39;]
dict = {i: len(i) for i in list}
print(dict)
#{&#39;aa&#39;: 2 , &#39;bbb&#39; : 3, &#39;cccc&#39;: 4}</code></pre><p>키와 값 각각의 리스트로부터 새로운 사전을 만들고 싶은 경우는 zip()를 사용하면 된다.</p>
<blockquote>
<pre><code>keys = [&#39;a&#39;, &#39;b&#39;, &#39;c&#39;]
values = [1,2,3]
dict = {k: v for k,v in zip(keys,values)}
print(dict)
#{&#39;a&#39;:1, &#39;b&#39;:2, &#39;c&#39;:3}</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[python] Decorator]]></title>
            <link>https://velog.io/@choich_0807/python-Decorator</link>
            <guid>https://velog.io/@choich_0807/python-Decorator</guid>
            <pubDate>Thu, 03 Feb 2022 05:43:10 GMT</pubDate>
            <description><![CDATA[<h1 id="decorator">Decorator?</h1>
<p>실행하려는 method 데코레이터는 사용자가 구조를 수정하지 않고 기존 객체에
새로운 기능을 추가 할 수 있도록하는 python의 디자인 패턴이다.</p>
<p>먼저 간단한 예제로 이해해보자!</p>
<blockquote>
</blockquote>
<pre><code>def decorator(func):
    def wrapper(*args, **kwargs):
        print(&#39;Hello!&#39;) # 전처리
        print(func(*args, **kwargs))
        print(&#39;GoodBye~&#39;) #후처리
    return wrapper
&gt;&gt;&gt;
@decorator
def myFunc():
    return &#39;What is your name?&#39;</code></pre><p>위 코드의 실행 결과는 다음과 같다.</p>
<blockquote>
<pre><code>Hello!
What is your name?
GoodBye~</code></pre></blockquote>
<p>```
코드에 작성한 주석을 살펴보면 decorator를 왜 쓰는지 가볍게 이해 할 수 있다.</p>
<h1 id="전처리와-후처리">전처리와 후처리</h1>
<p>예를 들어보자! 
내가 만드는 서버에서 insertUser, deleteUser, updateUser라는 메소드가 있다고 했을 때
처리 순서는 다음과 같을 것이다.</p>
<blockquote>
<ol>
<li>(전처리) 권한체크</li>
<li>(본 로직) 요청에 대한 처리</li>
<li>(후처리) 로그나 오류등등 처리</li>
</ol>
</blockquote>
<p><img src="https://images.velog.io/images/choich_0807/post/5ad3342c-0bb7-4f66-aeb0-ebfeb28318b6/image.png" alt=""></p>
<p>위와 같은 작업이 전,후로 반복된다. 
이걸 데코레이터를 사용한다면 다음과 같다.</p>
<p><img src="https://images.velog.io/images/choich_0807/post/36cfde50-fe98-4d42-97c9-e7ed75b2bb38/image.png" alt=""></p>
<h1 id="사용하는-이유">사용하는 이유</h1>
<p>사실 성능이 나아지거나 하는건 없다.
하지만 시스템이 커질수록 관리하기 편하고, 런타임에 validation 하기 좋고(로깅 시)
소스코드 또한 주요 로직만 보게되니 가독성도 좋아진다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] iterable과 iterator의 의미]]></title>
            <link>https://velog.io/@choich_0807/Python-iterable%EA%B3%BC-iterator%EC%9D%98-%EC%9D%98%EB%AF%B8</link>
            <guid>https://velog.io/@choich_0807/Python-iterable%EA%B3%BC-iterator%EC%9D%98-%EC%9D%98%EB%AF%B8</guid>
            <pubDate>Thu, 03 Feb 2022 04:46:16 GMT</pubDate>
            <description><![CDATA[<h1 id="iterable이터러블">iterable(이터러블)</h1>
<p>iterable는 member를 하나씩 차례로 반환 가능한 object를 의미한다.
iterable의 예로는 sequence type인 list,str,tuple이 대표적이다.</p>
<blockquote>
<pre><code>for i in range(5):
    print i</code></pre></blockquote>
<hr>
<p>0
1
2
3
4</p>
<pre><code>
당연하게 사용했던 위와 같은 for 문도 사실 range()로 생성된 list가 iterable하기 때문에 순차적으로 member들을 불러서 사용이 가능했던 것이다.

non-sequence type인 dict나 file도 iterable 하다고 할 수 있다.
dict 또한 for 문을 이용해 순차적으로 접근이 가능하다.

&gt;```
&gt;&gt;&gt; x = {&#39;a&#39;:1, &#39;b&#39;:2, &#39;c&#39;:3}
&gt;&gt;&gt;
&gt;&gt;&gt; for i in x:
    print(i)
a
b
c</code></pre><p>또한 <strong>iter</strong>() 나 <strong>getitem</strong>() 메소드로 정의된 class는 모두 iterable 하다고 할 수 있다.
iterable 은 for loop 말고도 zip(), map()과 같이 sequence 한 특징을 필요로 하는 작업에 유용하게 사용된다.
zip() 이나 map() 함수의 경우 iterable을 argument로 받는 것으로 정의되어 있다.</p>
<hr>
<h1 id="iterator이터레이터">iterator(이터레이터)</h1>
<p>iterator는 next() 메소드로 데이터를 순차적으로 호출 가능한 object이다. 만약 next()로
다음 데이터를 불러올 수 없을 경우(가장 마지막 데이터인 경우) StopIteration exception을 발생시킨다. 
그렇다면 iterable한 object들은 iterator일까?
결론부터 말하자면, iterable 이라고 해서 반드시 iterator인 것은 아니다.</p>
<blockquote>
</blockquote>
<pre><code>&gt;&gt;&gt; x = [1,2,3]
&gt;&gt;&gt; next(x)
Traceback (most recent call last)
file&quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
TypeError: list object is not an iterator</code></pre><p>iterator 가 아니라는 에러 메시지가 출력되는것을 확인할 수 있다.
list 는 iterable 이지만, 위와 같이 next() 메소드로 호출해도 동작하지 않는다. </p>
<p>만약, iterable 을 iterator로 변환하고 싶다면, iter() 라는 built-in function을 사용하면 된다.</p>
<blockquote>
</blockquote>
<pre><code>&gt;&gt;&gt; x = [1,2,3]
&gt;&gt;&gt; type(x)
&lt;type &#39;list&#39;&gt;
&gt;&gt;&gt; y = iter(x)
&gt;&gt;&gt; type(y)
&lt;type &#39;listiterator&#39;&gt;</code></pre><p>위와 같이 iter() 함수를 사용하여 list를 listiterator 타입으로 변경할 수 있다.</p>
<blockquote>
</blockquote>
<pre><code>&gt;&gt;&gt; next(y)
1
&gt;&gt;&gt; next(y)
2
&gt;&gt;&gt; next(y)
3
&gt;&gt;&gt; next(y)
Traceback (most recent call last):
    File &quot;&lt;stdin&gt;&quot;,line 1, in &lt;module&gt;
StopIteration</code></pre><p>이제 next()를 이용해 list의 정보를 하나씩 꺼낼 수 있다. 그리고 마지막 정보를 호출 한 이후에 next()를 호출하면 StopIteration 이라는 exception 이 발생됨을 볼 수 있다.</p>
<p>하지만, 우리가 list 나 tuple같은 iterable한 object를 사용할 때 굳이 iter() 함수를 사용하지 않아도 for 문을 이용하여 순차적으로 접근이 가능했다.
이것은 for 문으로 looping 하는 동안, python 내부에서 임시로 list를 iterator로 자동 변환해주었기 때문이다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Python] generators]]></title>
            <link>https://velog.io/@choich_0807/Python-generators</link>
            <guid>https://velog.io/@choich_0807/Python-generators</guid>
            <pubDate>Tue, 01 Feb 2022 08:17:19 GMT</pubDate>
            <description><![CDATA[<h1 id="generators">generators</h1>
<p>파이썬에서 보통의 함수는 값을 반환하고 종료하지만 제네레이터 함수는 
값을 반환하기는 하지만 산출(yield)한다는 차이점이 있다. 그리고 제네레이터는
쉽게 얘기하면 이터레이터를 생성해주는 함수라고도 볼 수 있다.</p>
<p>다음 코드를 보면 함수안에서 yield를 사용하여 리스트의 제곱을 산출하는 함수가 있고, 이 함수를 print문으로 확인해보면 generator object임을 확인할 수 있다.</p>
<blockquote>
<pre><code>def generator_squares():
    for i in range(3):
        yield i ** 2
print(&quot;gen object=&quot;, end=&quot;&quot;), print(generator_squares())
&gt;&gt;gen object=&lt;generator object generator_squares at 0x000001BA64555AC0&gt;</code></pre></blockquote>
<pre><code>
---

# Yield?
yield는 제네레이터 함수에서 값을 반환할 때 사용되며 yield 호출후에 다시
next가 호출될때 까지 현재의 상태에서 머물고 있다가 next 함수가 호출되면
이전의 상태에 이어서 다음 연산을 수행한다.
generator를 dir로 함수종류를 확인해보면 이터레이터와는 다르게 __iter__와 __next__함수가 둘다 들어있는 것을 확인할 수 있다.

&gt;```
print(&quot;dir gen=&quot;, end=&quot;&quot;), print(dir(generator_squares()))
&gt;&gt;&gt;dir gen=[&#39;__class__&#39;, &#39;__del__&#39;, &#39;__delattr__&#39;, &#39;__dir__&#39;, &#39;__doc__&#39;, &#39;__eq__&#39;, &#39;__format__&#39;, &#39;__ge__&#39;, &#39;__getattribute__&#39;, &#39;__gt__&#39;, &#39;__hash__&#39;, &#39;__init__&#39;, &#39;__init_subclass__&#39;, &#39;__iter__&#39;, &#39;__le__&#39;, &#39;__lt__&#39;, &#39;__name__&#39;, &#39;__ne__&#39;, &#39;__new__&#39;, &#39;__next__&#39;, &#39;__qualname__&#39;, &#39;__reduce__&#39;, &#39;__reduce_ex__&#39;, &#39;__repr__&#39;, &#39;__setattr__&#39;, &#39;__sizeof__&#39;, &#39;__str__&#39;, &#39;__subclasshook__&#39;, &#39;close&#39;, &#39;gi_code&#39;, &#39;gi_frame&#39;, &#39;gi_running&#39;, &#39;gi_yieldfrom&#39;, &#39;send&#39;, &#39;throw&#39;]</code></pre><p>그래서 이터레이터에서 처럼 <strong>iter</strong>를 호출한 후에 <strong>next</strong> 함수를 호출하지 않아도 
<strong>next</strong> 를 바로 호출할 수 도 있다.</p>
<blockquote>
<pre><code>gen = generator_squares()
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
&gt;&gt;0
1
4
Traceback (most recent call last):
File &quot;C:\Users\Choi\AppData\Local\Programs\Python\Python39\practice.py&quot;, line 17, in &lt;module&gt;
print(gen.__next__())
StopIteration</code></pre></blockquote>
<pre><code>
이터레이터와 마찬가지로 __next__함수로 값을 꺼내올 수 있고 for 문이 끝나게 되면
StopIteration 이 발생한다. 그리고 제너레이터 함수는 실행중에 send 함수를 통해서
값을 전달받을 수 있다.

send함수로 값을 전달하는 코드는 다음과 같다.

&gt;```
def generator_send():
    received_value = 0
    while True:
        received_value = yield
        print(&quot;received_value = &quot;, end=&quot;&quot;), print(received_value)
        yield received_value * 2
gen = generator_send()
next(gen)
print(gen)
print(gen.send(2))
next(gen)
print(gen.send(3))
&gt;&gt;&gt;
&lt;generator object generator_send at 0x000001FE12B4BC10&gt;
received_value = 2
4
received_value = 3
6</code></pre><p>generator_send 함수는 yield로 send를 통해서 받은 값을 received_value에 할당하고
그 값의 2배 수를 리턴받고 있다. 제네레이터에서는 이처럼 yield를 이용해서 제네레이터 함수
실행중 값을 전달할 수 있고, 응용하면 제네레이터 함수를 사용해서 main 실행 루프에서 연산결과에
따라 호출도 제어할 수 있다. </p>
<hr>
<h1 id="제네레이터-표현식generator-expression">제네레이터 표현식(generator expression)</h1>
<p>제네레이터 함수 외에도 제네레이터 표현식이 있다. 제너레이터 표현식은 Lazy evalution을 위해 사용될 수 있다. Lazy evaluation은 말그대로 실행을 지연시킨다는 의미이다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day15]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day15</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day15</guid>
            <pubDate>Tue, 01 Feb 2022 08:11:14 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/5edcdc97-9cb3-4251-be3e-700fb13cff47/image.png" alt=""></p>
<blockquote>
<pre><code>def factorial(n):
    # 여기에 코드를 작성해주세요.
    result = 1
    for i in range(1,n+1):
        result *= i
    return result</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day14]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day14</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day14</guid>
            <pubDate>Tue, 01 Feb 2022 07:35:40 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/a3203546-6f8f-4e9c-894e-41ae3ffab88f/image.png" alt=""></p>
<blockquote>
<pre><code>def move_zeroes(nums):
    for i in range(len(nums)):
        if 0 in nums: # 만약 0 이 nums 리스트에 있다면
            nums.remove(0) # 리스트에서 0을 삭제
            nums.append(0) # 리스트에서 0을 추가
    return nums</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day13]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day13</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day13</guid>
            <pubDate>Tue, 01 Feb 2022 07:15:28 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/7af9d3ab-e51c-4563-a421-88bcdf705a43/image.png" alt=""></p>
<blockquote>
<pre><code>def min_path_sum(grid):
    for i in range(1,len(grid)): 
        grid[0][i] += grid[0][i-1] 
        grid[i][0] += grid[i-1][0]
    for i in range(1, len(grid)):
        for j in range(1, len(grid)):
            grid[i][j] += min(grid[i][j-1], grid[i-1][j])             
    return grid[-1][-1]</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day12]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day12</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day12</guid>
            <pubDate>Tue, 01 Feb 2022 06:48:51 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/d7ade67e-6010-4a24-b1f7-107ef7a2c2d5/image.png" alt=""></p>
<blockquote>
<pre><code>def reverse_string(s):
    s.reverse() #인자로 넘겨받은 리스트 문자열을 뒤집기
    return s</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day11]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day11</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day11</guid>
            <pubDate>Tue, 01 Feb 2022 06:44:26 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/5234edc8-ea8e-438a-8a88-21be3127798b/image.png" alt="">
<img src="https://images.velog.io/images/choich_0807/post/a9bdb96f-4e62-4c73-8249-97934e9a1697/image.png" alt=""></p>
<blockquote>
<pre><code>def complex_number_multiply(a, b):
  a1 = int(a.split(&#39;+&#39;)[0])# 인자 a를 +기준으로 split해서 인덱스 0 값을 정수형으로 변환하여 a1에 저장
  b1 = int(b.split(&#39;+&#39;)[0])# 인자 b를 +기준으로 split해서 인덱스 0 값을 정수형으로 변환하여 b1에 저장 
  a2 = int(a.split(&#39;+&#39;)[1].replace(&#39;i&#39;, &#39;&#39;))# 인자 a를 +기준으로 split해서 인덱스 1값의 i를 replace로 제거하고 a2에 저장
  b2 = int(b.split(&#39;+&#39;)[1].replace(&#39;i&#39;, &#39;&#39;))# 인자 b를 +기준으로 split해서 인덱스 1값의 i를 replace로 제거하고 b2에 저장
  return f&#39;{(a1 * b1) + (a2 * b2)*(-1)}+{(a1 * b2) + (a2 * b1)}i&#39;</code></pre></blockquote>
<p>```</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[TIL-CodeKata-Day10]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day10</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day10</guid>
            <pubDate>Wed, 26 Jan 2022 16:16:25 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/6d255bbe-4ea7-43e7-86aa-fe5701743064/image.png" alt=""></p>
<blockquote>
<pre><code>def get_max_area(height):
    areas = []
    for i in range(len(height)-1):
        for j in range(i+1, len(height)):
            print(i,j)
            temp_height = min(height[i],height[j])
            temp_width = abs(i-j)
            area = temp_width * temp_height
            areas.append(area)
    return max(areas)</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] CodeKata Day9]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day9</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day9</guid>
            <pubDate>Wed, 26 Jan 2022 16:13:54 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/822f26ea-340f-4998-9741-9d4dc055c92d/image.png" alt=""></p>
<blockquote>
<pre><code>def more_than_half(nums):
    dic = {} # 빈 딕셔너리 변수 선언
    result = []
    for i in nums: 
        if i not in dic:     # i가 nums안에 없으면
            dic[i] = 1         # dic의 키 i 에 value 1 저장
        else:                 #i가 nums안에 있으면
            dic[i] += 1         # dic의 키 i의 value에 1 더하기
        for i in range(k):
            dic_max = max(dic.keys() , key= dic.get) #dic에서 가장 큰 value값의 키값
               result.append(key_max)
            del dic[key_max]
    return dic_max</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] CodeKata Day8]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day8</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day8</guid>
            <pubDate>Wed, 26 Jan 2022 15:48:11 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/ecf7feac-11e0-4f49-815b-341f3b24ce46/image.png" alt=""></p>
<blockquote>
<pre><code>def is_valid(string):
    left = [&#39;[&#39;, &#39;(&#39;, &#39;{&#39;] # 여는 괄호들을 left 리스트에 저장
    right = [&#39;]&#39;, &#39;)&#39;, &#39;}&#39;] # 닫는 괄호들을 right 리스트에 저장
    stack = [] # 빈 리스트 선언
    for i in string: # string에서 문자들을 하나씩 가져옴
        if i in left: # 문자 i 가 left 리스트에 존재한다면
            stack.append(i) # stack 리스트에 문자 i 를 추가
        elif i in right: #문자 i 가 right 리스트에 존재한다면
            if left.index(stack.pop()) != right.index(i): # left 리스트의 인덱스와 right 리스트의 인덱스가 같지 않으면 False를 리턴
                return False
    return len(stack) == 0 #stack 리스트의 길이가 0이면 True 리턴</code></pre></blockquote>
]]></description>
        </item>
        <item>
            <title><![CDATA[[TIL] CodeKata Day7]]></title>
            <link>https://velog.io/@choich_0807/TIL-CodeKata-Day7</link>
            <guid>https://velog.io/@choich_0807/TIL-CodeKata-Day7</guid>
            <pubDate>Sun, 23 Jan 2022 06:35:56 GMT</pubDate>
            <description><![CDATA[<p><img src="https://images.velog.io/images/choich_0807/post/c1181e05-06c9-491e-a97a-95fac7959a2f/image.png" alt=""></p>
<blockquote>
<pre><code>def more_than_half(nums):
    dic = {} # 빈 딕셔너리 변수 선언
    for i in nums: 
        if i not in dic:     # i가 nums안에 없으면
            dic[i] = 1         # dic의 키 i 에 value 1 저장
        else:                 #i가 nums안에 있으면
            dic[i] += 1         # dic의 키 i의 value에 1 더하기
    dic_max = max(dic.keys() , key= dic.get) #dic에서 가장 큰 value값의 키값
    return dic_max </code></pre></blockquote>
]]></description>
        </item>
    </channel>
</rss>