[Python] Git 프로젝트 별 venv 사용법 정리

ChatGPT가 다음과 같이 정리 답변한다.

✅ Git 프로젝트마다 venv 만드는 법

예를 들어 my-awesome-project라는 Git 프로젝트가 있다고 가정하면:

1. 해당 프로젝트 디렉토리로 이동

cd ~/projects/my-awesome-project

2. 가상환경 만들기

python3 -m venv .venv
  • venv는 그냥 관례적으로 많이 쓰는 이름이야. 숨김 폴더가 돼서 깔끔하고, .gitignore에 넣기도 좋아.

3. 가상환경 활성화

source .venv/bin/activate
  • 프롬프트에 (venv) 또는 (.venv)처럼 표시가 붙을 거야.
  • 이 상태에서 pip install 하면 이 프로젝트 안에서만 설치돼.

4. 필요한 패키지 설치

pip install black requests flask

5. requirements.txt 만들기 (필요할 때)

pip freeze > requirements.txt
  • 다른 사람이 이 프로젝트를 클론한 다음,
pip install -r requirements.txt
  • 이렇게 하면 똑같은 환경을 바로 세팅 가능해.

✅ .gitignore 설정

venv 디렉토리는 Git에 굳이 올릴 필요 없어. 아래처럼 .gitignore에 추가해두면 좋아:

.venv/

✅ 프로젝트 폴더마다 적용 구조 예시

my-awesome-project/
├── .venv/ ← 가상환경
├── app.py
├── requirements.txt
└── README.md

🔁 다음에 다시 작업할 때는?

cd ~/projects/my-awesome-project
source .venv/bin/activate

작업 끝났으면:

deactivate

✅ VS Code 사용자라면 (추가 팁)

  • .venv를 자동으로 인식하게 하려면 .vscode/settings.json에 다음 설정 추가:
{
  "python.defaultInterpreterPath": ".venv/bin/python"
}

[Python] requirements.txt

pip freeze > requirements.txt

다음과 같은 형식으로 나타날 경우는 pip list --format=freeze > requirements.txt

pytz @ file:///private/var/folders/sy/f16zz6x50xz3113nwtb9bvq00000gp/T/abs_e0y2h1cdsw/croot/pytz_1695131602326/work

이를 이용해 패키지를 설치할 때는 다음과 같이 한다.

pip install --no-cache-dir -r requirements.txt

도커 이미지 빌드 시 사용은 https://hub.docker.com/_/python 를 참고.

[matplotlib] 한글 폰트 설정

apt-get install -y fonts-nanum
fc-cache -fv
rm ~/.cache/matplotlib -rf

혹은 Windows에서는

from matplotlib import font_manager, rc
font_path = 'C:/Windows/Fonts/NGULIM.TTF'
font = font_manager.FontProperties(fname=font_path).get_name()
rc('font', family=font)

[Python] matplotlib.pyplot 으로 그래프 그리기

import 부터 하자.

import matplotlib.pyplot as pyplot

하나는 x 축, 다른 하나는 y 축으로 리스트 두개를 가지고 그린다. 예를 보자. scatter()를 썼다.

names = ['Bamtol', 'Mong', 'Justin', 'Jay']
bomb = [8, 1, 12, 10]
pyplot.title('Super Mario Cart 8 Deluxe Score')
pyplot.xlabel('Name')
pyplot.ylabel('Score')
pyplot.scatter(names, bomb, color='green')
pyplot.show()

위의 그래프는 막대 그래프가 더 나아보인다. bar()로 막대 그래프를 그래보자. 각각의 색도 바꿔보자.

names = ['Bamtol', 'Mong', 'Justin', 'Jay']
bomb = [8, 1, 12, 10]
pyplot.title('Super Mario Cart 8 Deluxe Score')
pyplot.xlabel('Name')
pyplot.ylabel('Score')
pyplot.bar(names, bomb, color=[ 'blue', 'red', 'gray', 'green' ])
pyplot.show()

barh()를 쓰면 누은 그래프가 나온다. xlabel()과 ylabel() 바꿔주자.

names = ['Bamtol', 'Mong', 'Justin', 'Jay']
bomb = [8, 1, 12, 10]
pyplot.title('Super Mario Cart 8 Deluxe Score')
pyplot.xlabel('Score')
pyplot.ylabel('Name')
pyplot.barh(names, bomb, color=[ 'blue', 'red', 'gray', 'green' ])
pyplot.show()

plot()을 쓰면 선 그래프가 나온다.

weigh = [ 3.26, 4.5, 5.6, 7.2, 8.9, 10.4, 12.6, 14.2, 16.1, 17.4, 16.8, 16.3, 16.5, 17.0]
pyplot.plot(weigh)
pyplot.title("Bamtol's weigh")
pyplot.xlabel('Days')
pyplot.ylabel('Kg')
pyplot.show()

그려진 그래프의 시작이 1이 아닌 0 부터임에 주의하자. 이걸 1부터로 바꾸고, x 축 찍는 위치도 바꾸고, 마커도 넣어보자.

weigh = [ 3.26, 4.5, 5.6, 7.2, 8.9, 10.4, 12.6, 14.2, 16.1, 17.4, 16.8, 16.3, 16.5, 17.0]
axis_x = list(range(1, 15))
pyplot.title("Bamtol's weigh")
pyplot.xlabel('Days')
pyplot.ylabel('Kg')
pyplot.plot(axis_x, weigh, marker = '.', color = 'green')
pyplot.xticks([1, 4, 7, 10, 13])
pyplot.show()

파이 차트를 그릴 때는 pie()를 이용한다.

names = ['Bamtol', 'Mong', 'Justin', 'Jay']
bomb = [8, 1, 12, 10]
pyplot.title('Results: Score', fontdict={'fontsize': 24})
pyplot.pie(bomb, labels=names, autopct='%1.1f%%', colors=['lightblue','pink','yellow','lightgreen'])

[Python] sorted() 설명

sorted() 함수는 iterable로 정렬한 list를 만든다. doc string을 보자.

Return a new list containing all items from the iterable in ascending order.

A custom key function can be supplied to customize the sort order, and the reverse flag can be set to request the result in descending order.

설명에서 보이는대로 key로 function을 받아 그 function의 기준에 따라 정렬 가능하다. 순서를 작아지는 순서로 하고 싶다면, reverse 를 True로 주면 된다. 예를 들면 다음과 같다.

names = [ 'Bamtol', 'Mong', 'Justin', 'Jay']
sorted(names)
['Bamtol', 'Jay', 'Justin', 'Mong']

key를 len()으로 주고, 작아지는 순서대로 해보자.

sorted(names, key=len, reverse=True)
['Bamtol', 'Justin', 'Mong', 'Jay']

[Python] lambda 함수 설명

lambda 함수는 코드를 막 작성하던 중에 그 코드 내에 간단한 함수를 만들 때 흔히 사용한다. 다음과 같은 형식이다.

lambda x, y: x + y

filter나 map 내에서 간단한 함수를 작성한다던가 할 때 유용하게 쓰인다. 예를 들어 0 ~ 999 사이의 값 중 2나 3의 배수들의 합을 구하고 싶으면 다음과 같이 하면 된다.

sum(filter(lambda x: x % 2 == 0 or x % 3 == 0, range(1000)))
333167

[Python] filter() 설명

filter() 함수는 iterables 안의 어떤 조건(함수)에 맞는 것만 골라내는 함수다. doc string을 보자.

filter(function or None, iterable) –> filter object

Return an iterator yielding those items of iterable for which function(item) is true. If function is None, return the items that are true.

어떤 iterables내의 item들 중 function에 참인 것만 골라서 iterator를 만든다. function에 None을 주면 true인 item들만 고른다. 예를 들면 다음과 같다.

names = [ 'Bamtol', 'Mong', 'Justin', 'Jay']
list(filter(lambda x: len(x) == 6, names))
['Bamtol', 'Justin']

[Python] map() 설명

map() 함수의 doc string부터 보자.

map(func, *iterables) –> map object

Make an iterator that computes the function using arguments from each of the iterables. Stops when the shortest iterable is exhausted.

설명 그대로 func 함수를 iterables내의 각 argument에 적용한 iterator를 만든다. 예를 들면 다음과 같다. 일부러 for loop를 돌렸다. 쓰인 len이 length를 return하는 len()임에 주의하자.

names = [ 'Bamtol', 'Mong', 'Justin', 'Jay' ]
for length in map(len, names):
    print(length)
6
4
6
3

iterator를 return하므로 list로 만들고 싶다면 list로 변환한다.

list(map(len, names))
[6, 4, 6, 3]

[Python] Selenium 사용법

webdriver 다운로드

Selenium 사용전 사용하는 브라우저에 맞는 webdriver를 다운로드받아서 해당 파일이 있는 곳을 PATH에 추가해두는 것이 좋다. https://pypi.org/project/selenium/ 의 Drivers 섹션을 참고.

특정 페이지를 열기

from selenium import webdriver

driver = webdriver.Firefox()
driver.get("blog.dasomoli.org")

페이지를 열고 난 후 기다리기

어느 페이지를 열고 난 후 동작을 시작하려면 해당 페이지가 열렸을 때 나타나는 element를 기다려서 동작을 시작해야 한다. link text라면 다음과 같은 식으로 기다릴 수 있다. 아래에서 20은 20초를 의미한다. 첫번째 인자가 괄호로 둘러싸여 있음에 유의하라.

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.LINK_TEXT, "Ult-Build-1")))

다음처럼 어느 태그가 나타나길 기다릴 수도 있다.

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element((By.TAG_NAME, "h1"), "Project INTEGRATED_BUILD_SYSTEM_TOOL"))

페이지 내의 특정 element 찾기

element = driver.find_element_by_name("userName")

element가 찾기 쉽게 id나, class name 등으로 되어 있다면 find_element_by_id() 혹은 find_element_by_class_name() 등으로 쉽게 찾을 수 있다. 아니라면 tag name 등으로 찾은 후 돌리면서 찾아본다. 함수명이 element가 아닌 elements 임에 유의하라.

import re

ultp = re.compile('^Ult-Build-[12].*')
ult_req = { }

elements = driver.find_elements_by_tag_name("tbody")
for tag in elements:
    if ultp.match(tag.text):
        wordlist = tag.text.split()
        if len(wordlist) >= 2:
            ult_req[wordlist[0]] = wordlist[1]

키 입력이나 클릭하기

찾은 element가 input과 같은 입력이 가능한 element라면 바로 send_keys()로 입력이 가능하다.

from selenium.webdriver.common.keys import Keys

element = driver.find_element_by_id("j_username")
element.send_keys("dasomoli")

element = driver.find_element_by_name("j_password")
element.send_keys("password", Keys.ENTER)

직접 element를 찾기 어렵다면 근처 element를 찾은 후 click한 후 key를 입력할 수도 있다.

from selenium.webdriver.common.action_chains import ActionChains

elements = driver.find_elements_by_class_name("setting-name")
for element in elements:
    if element.text == "P4_Shelve_CLs":
        shelve_element = element

actions = ActionChains(driver)
actions.move_to_element_with_offset(shelve_element, shelve_element.rect['width'] + 5, shelve_element.rect['height'] / 2).click().send_keys("12345678", Keys.ENTER)
actions.perform()

send_keys() 대신 click() 을 이용하면 마우스 클릭이 가능하다. 마우스 클릭 지점을 찾기 힘들 때는 context_click()을 사용하면 우클릭되는데, 이 때 나타나는 context menu로 클릭 지점을 대충 파악할 수 있다.

마우스 클릭 등으로 선택된 element를 얻기

actions = ActionChains(driver)
actions.move_to_element_with_offset(workspace_element, workspace_element.rect['width'] + 23, workspace_element.rect['height'] / 2).click()
actions.perform()
element = driver.switch_to.active_element

select form에서 값 선택

from selenium.webdriver.support.ui import Select

select = Select(element)
if value != "":
    select.select_by_visible_text(value)
else:
    select.select_by_index(0)

참고

  1. Selenium with Python – Read the Docs
  2. Selenium Documentation
  3. Selenium Browser Automation Project (한글 버전도 있다)