You& Data_Science & Life

(venv) 1. pyenv를 활용한 다양한 버전의 python 설치하기

배경 상황

pyenv는 프로젝트별로, 서로 다른 Python 버전을 필요로하는 경우, 디렉토리별로 서로 다른 가상환경을 구축하여 각기다른 python 버전을 지정하여 사용할 수 있게 만들어줍니다.



1. pyenv 설치하기 (ubuntu)

1) 종속성 설치

  • pyenv를 설치하기전 OS에 맞는 종속성이 필요합니다.
    sudo apt-get install -y make build-essential libssl-dev zlib1g-dev
    # > libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev 
    # >libncursesw5-dev xz-utils tk-dev libffi-dev liblzma-dev python-openssl
    

2) pyenv-installer 설치

curl https://pyenv.run | bash
# git clone https://github.com/pyenv/pyenv.git ~/.pyenv 

: 정상 설치가 완료되면, ~/.pyenv 폴더가 생성됨.

3) shell 실행시 pyenv 실행을 위한 설정 추가

: 설치가 완료되면, pyenv가 shell 실행되기 위해서, ~/.bashrc or ~/.bash_profile 파일의 가장 하단에 아래 문구를 추가함.

export PATH="${HOME}/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

4) 쉘 재실행

: 변경된 설정을 저장해주기 위한, 쉘 재실행

exec "$SHELL"



2. pyenv를 활용한 파이썬 버전별로 설치하기

1) 설치 가능한 파이썬 버전 확인

pyenv install --list | grep " 3\.[678]" # 3.6 ~3.7 사이의 버전만 살펴보기
pyenv install --list #  모든 phthon 버전 확인하기

2) pyenv를 활용한 파이썬 설치 & 삭제

## 1) python 설치
pyenv install 3.6.9  

## 2) python 설치 여부 확인
ls ~/.pyenv/versions/   

## 3) 설치한 python 버전 삭제  (2가지 방법중 1가지 선택)
rm -rf ~/.pyenv/versions/3.6.9   
pyenv uninstall 3.6.9  



3. pyenv로 사용할 파이썬 지정하기 (⭐️⭐️⭐️)

1) 설치된 파이썬 리스트 출력

: ‘*‘가 체크된 버전이 현재 활성 상태의 파이썬을 의미함.

## 설치된 파이썬 리스트 출력
pyenv versions 
# * system    
#   2.7.9
#   3.6.9 

## 현재 사용중인 파이썬 인터프리터 위치 확인
which python
# /srv/dlab/.pyenv/shims/python
# 이때, "/home/{user_1}/.pyenv/~"로 설정되어 있으면, pyenv로 설치한 python 경로로 잘 연결되어 있는 상황임.

2) 특정 파이썬 지정

(1) global

## 3.6.9 버전으로 변경하기
pyenv global 3.6.9
pyenv versions 
#   system    
#   2.7.9
# * 3.6.9 (set by /home/계정/.pyenv/version)

## 다시 system 버전으로 변경하기
pyenv global system
pyenv versions 
# * system (set by /home/계정/.pyenv/version) 
#   2.7.9
#   3.6.9

(2) local

  • 설정하는 디렉토리내하에서 사용할 python 버전을 지정하게됨
  • global로 설정된 python 버전이 있더라도, 해당 디렉토리가 pyenv local로 설정되어 있는 경우, local version으로 동작함
    ## 3.6.9 버전으로 변경하기
    cd prj_dir
    pyenv local 2.7.9
    pyenv versions 
    #   system
    # * 3.6.9 (set by /home/계정/prj_dir/.python-version)
    



+ pyenv 명령어 정리

## 1) install : 특정 버전의 python 설치
pyenv install 3.6.8

## 2) versions : 현재 설치된 모든 python 버전 표시
pyenv versions

## 3) which : 실행 파일의 경로를 결
pyenv which

## 4) global : 전역 파이썬 설정
pyenv global 3.6.9

## 5) local
pyenv local 2.7.9

Reference

[1] 01) pyenv와 가상환경
[2] pyenv란? pyenv 사용하기
[3] [python] pyenv? virtualenv?

(python-utils) lambda / map / filter / reduce

1. lambda

  • 익명 함수 : 객체를 만들지 않기에, 메모리를 할당하지 않고 다음줄로 넘어가면 힙(heap)메모리 영역에서 증발
  • 일반 함수 : 함수는 객체를 만들고, 재사용을 위해 함수 이름(메모리)를 할당

[Formula]
lambda x, y, ... : [인수를 활용한 표현식]]


## Ex_1)
lambda_sum = lambda a, b : a+b
lambda_sum(10,20)
# > 30

2. map

  • 게으른 연산을 진행하는 map iterator 객체로 리턴.
  • generate와 유사하게 값을 next로 다음 iterator를 실행히며, generate는 list의 다음 값만 추출해준다면, map은 다음 값을 활용한 연산을 진행

[Formula]
map(function, iterable)

  • function : Return 값이 True or Flase 둘중 하나인 함수
  • iterable : iterable 객체
# input
lst = [1,2,3]
## Ex_1) map with labmda 
list(map(lambda x+1 : lst))
# > [2,3,4]

## Ex_2) map with function 
def func(x) :
    return x + 10
list(map(func(x), lst))
# > [11, 12, 13]

## Ex_2) 3항 연산자 (if else, else, else, ...)
li = [-3, -2, 0, 6, 8]
list(map(lambda x : 'positive' if x > 0 else ('negative' if x < 0 else 0) , li))
# > ['음수', '음수', 0, '양수', '양수']
※ [게으른 연산]
속도 자체는 더 느리지만, 한번에 list를 모두 메모리에 올리지 않고 실행에 필요한 다음 값만 메모리에 올리기에, 연산량이 많을 때 메모리 부하를 줄일 수 있음.
  • next() 메소드로 데이터를 순차적으로 호출 가능한 object
  • 마지막 데이터까지 불러오면, StopIteration exception 발생
  • 일반 iterable한 객체(ex. 리스트)를 iterator로 변환하려면, iter() 함수 사용
  x = [1,2,3] 
  print(type(x)) # list ('iterable')
  y = iter(x)
  print(type(y)) # list ('iterator')
  next(y) # 1
  next(y) # 2
  next(y) # 3
  next(y) # Error : StopIteration

3. filter

  • iterable 객체에서, 함수의 리턴값이 참인 값만 반환
  • 따라서 함수의 return값은

[Formula]
filter(function, iterable)

  • function : Return 값이 True or Flase 둘중 하나인 함수
  • iterable : iterable 객체
# input
li = [-2, -3, 5, 6]

## Ex_1) filter with labmda 
list(filter(lambda x: x > 0, li))
# > [5, 6]

## Ex_2) filter with function 
def func(x) :
    return x > 0
list(filter(func, li))
# > [5, 6]

4. reduce

  • 여러 개의 데이터를 주로, 누적집계 하기위해 사용

    [Formula]
    reduce(function, iterable)

    • function : 누적자
    • iterable : 루프를 돌면서 하나씩 가져오는 값(첫번째값이 초기값)
    • initializer(=None) : 초기값, (if initializer ==None, iterable contains only one item, the first item is returned.
from functools import reduce
# input
users = [
  {'mail': 'gregorythomas@gmail.com', 'sex': 'M', 'age': 73},
  {'mail': 'hintoncynthia@hotmail.com', 'sex': 'F', 'age': 29},
  {'mail': 'wwagner@gmail.com', 'sex': 'M', 'age': 51},
  {'mail': 'daniel79@gmail.com', 'sex': 'F', 'age': 32},
  {'mail': 'ujackson@gmail.com', 'sex': 'F', 'age': 42}
  ]

## Ex_1_1) No initialize 
reduce(lambda x, y : x + y['age'], users)
# {'mail': 'gregorythomas@gmail.com', 'sex': 'M', 'age': 73} + 73 # Error
# -> 리스트의 첫번째 값을 초기값으로 사용했기에 `dict` + `int`가 되면셔 Error 발생
## Ex_1_2) With initialize
reduce(lambda x, y : x + y['age'], users, 0)
# 0 + 73
# 73 + 29
# 73 + 29 + 51

## Ex_2) 
reduce(lambda x, y : x + [y['mail']], users, []) 
# [] + ['gregorythomas@gmail.com']
# ['gregorythomas@gmail.com'] + ['hintoncynthia@hotmail.com']
# ['gregorythomas@gmail.com', 'hintoncynthia@hotmail.com'] + ['wwagner@gmail.com']

Reference

[1] T강의노트 03. 파이썬 lambda, map, filter, reduce, dic - 초보몽키의 개발공부로그
[2] 파이썬 reduce 함수 사용법 - daleseo님

(Class) class내 instance method 중복 호출시 에러

1. 문제 상황

1) 문제 코드

: 하나의 클래스에서 여러개의 instance method를 생성하고, 그 중 마지막 main에 해당하는 method가 상위 method를 내부에서 다시 호출하는 구조로 클래스를 만들어, 하나의 클래스의 main만 메소드만 실행하여 전체 메서드를 실행하고자 함.

class Parent :
    def __init__(self) :
        self.budget = 100

    def child_1(self) :
        self.budget -= 10

    def child_2(self) :
        self.budget -= 5

    # 문제가 된 method
    # instance method를 내부에 갖고 있는 instnce method
    def family_main(self) :
        Parent.child_1()
        Parent.child_2()
        print(self.budget)


parnet_inst = Parent()   # instnace 생성
parnet_inst.family_main()# main function 실행 
> TypeError: child_1() missing 1 required positional argument: 'self'

2) 발생 에러

위와 같이 parnet_inst.family_main 메서드를 실행하자, missing 1 required positional argument: 'self' 해당 메서드가 self 인자를 필요로하는데 받지 못했다는 에러가 발생.


2. 문제 원인

: family_main안에 존재하는 Parent.child_1Parent 클래스의 ‘인스턴스 메서드’이다. 따라서 코드를 잘 살펴보면,

  • Parent() 클래스를 parent_inst에 할당
  • 그러나 family_main내부의 메서드를 호출할 땐, 할당한 인스턴스의 이름인 parent_inst가 아닌 클래스명이 Parent로 호출하고 있음.

3. 문제 해결

: 동일한 클래스의 인스턴스 메서드끼리 호출할 때는, 클래스명을 다시 호출하는 것이 아니라, ‘self’를 클래스명으로 호출하면 가능하다.

class Parent :
    def __init__(self) :
        self.budget = 100

    def child_1(self) :
        self.budget -= 10

    def child_2(self) :
        self.budget -= 5

    def family_main(self) :
        self.child_1()
        self.child_2()
        print(self.budget)

Parent().family_main()
> 85

Reference

[1] TypeError: Missing 1 required positional argument: ‘self’ - stackfoverflow
[2] [Python] 메서드(method)와 스태틱/클래스 메서드(static/class method)
[3] 35.3 클래스 메서드 사용하기 - 코딩 도장

(Error) Global variable 호출시, referenced before assignment에러 발생

1. 문제 상황

: 외부 함수에서 선언한 변수를, 다른 함수 내부에서 불러오기 위해 global로 해당 변수를 선언을 해주었다. 이후 다른 함수에서는 해당 변수가 문제없이 잘 불러와졌으나, 특정 함수에서만 global로 선언한 변수가 존재하지 않는 상태로 호출되었다는 “referenced before assignment” 에러가 발생하였다.

def global_func() :
  global a
  a = 10
global_func()
def local_func_1() :
  print(a)
local_func_1()
# 10 # 정상 

def local_func_2() :
  a += 10 
  print(a)
local_func_2()
# local variable 'a' referenced before assignment # Error 발생

2. 문제 원인

: 실제 a변수는 네임스페이스에 global로 존재하지만, local_func_2 함수의 a += 10 코드에서, Python은 새로운 지역변수를 할당하는 코드라고 인식하게 되면서, a라는 지역변수가 먼저 참조 되지 않았다고 에러를 발생시키는 것이다.

def local_func_2() :
  a += 10  #  Python은 새로운 지역변수를 a를 할당하는 코드라고 인식하기에 이 함수 내에서 지역변수로 선언된 a 변수를 탐색함.
  print(a)
local_func_2()

3. 문제 해결

: 따라서 해당 변수를 사용하고자 한다면, 해당 함수 내부에서 해당 변수를 ‘global’로 선언해주어야 한다.

def local_func_2() :
  global a
  a += 10  #  Python은 새로운 지역변수를 a를 할당하는 코드라고 인식하기에 이 함수 내에서 지역변수로 선언된 a 변수를 탐색함.
  print(a)
local_func_2()
# 20

Reference

[1] 파이썬 referenced before assignment에러 이유와 해결 - 홍식의 개발 HDD님의 블로그

local repository를 remote repository로 push하기

#git, #github, #branch , #push

local 디렉토리를 git remote repository로 push하기.

1. (remote) git 서버에 repository 생성하기

: 일반적인 repository를 생성하되, ‘README.md’ 파일을 성성하지 말 것.

  • 생성시, 자동으로 ‘main’ 브랜치가 생성되며, 이후 local에서 업로드한 dev 브랜치와 remote main 브랜치간 연결이 되어있지 않아 pull request가 생성되지 않는 아래와 같은 상황이 발생.
There isn't anything to compare main and mybranch are entirely different commit histories

2. local main -> remote main repository git 연동(push)

:

## 1) local repository git 추적 시작
git init
## 2) git add & commit 
git add README.md
git commit -m "first commit"
## 3) local branch의 이름을 main으로 변경 (중요!!!)
git branch -M main
## 4) 원격 저장소 연결
git remote add origin {remote}
## 5) local 저장소를 원격 origin/main 브랜치로 업로드
git push -u origin main

3. dev branch 생성 하기

## 1) (local) branch 생성 : master branch에서 develop 이라는 새로운 branch를 만들고 갈아탄다.
$ git checkout -b dev

## 2) branch 확인 및 변경 (서버에서 만든 branch가 보이지 않을 땐, pull로 업데이트)
$ git branch # local
$ git branch -r # remote 저장소의 branch 확인
$ git branch -a # local & remote branch 모두 확인

## 3) (원격) dev branch 생성(push)
$ git push -u origin dev # push할 원격 dev branch를 명시.

4. dev -> main 으로 pull request 보내기

## 1) dev branch 이동
$ git checkout dev

## 2) 코드 작업
$ vi README.md # 'text 추가'

## 3) git add & commit 
git add README.md
git commit -m "first commit"

## 4) (원격) dev branch 생성(push)
$ git push -u origin dev # push할 원격 dev branch를 명시.

위 작업 이후, git 사이트로 이동해보면, 정상적으로 pull reqeust가 가능

Reference

[1] connect_local_folder_to_git_repository
[2] pull_request 안될때, A_brnach and B_brnach are entirely different commit histories
[3] 기본 local 폴더 git 업로드 방법