반응형

 

 

오늘 다뤄볼 주제는 덕 타이핑입니다.

 

 

덕 타이핑은 프로그래밍 언어에서 클래스의 행동에 중점을 둔 컨셉중 하나에요. 

 

클래스의 상속, 유형보다 객체의 동작 즉 행동을 강조해서 유연성을 높이고 캐스팅의 필요성을 줄여주는 프로그래밍 스타일입니다.

 

아래 코드로 예를 들어 보겠습니다.

 

class Duck:

    def sound(self):

        print("Quack!!!")



class Person:

    def sound(self):

        print("I'm Quaking like a duck ! ")





def make_it_sound(obj):

    obj.sound()

 

만약 Dog, Cat 여러 클래스가 추가 개발되야 된다고 해도, make it sound 함수로 주요 로직을 수행하면 되기 때문에, 유사한 여러 객체를 처리할 때 유용합니다.

 

저의 경우에는 데이터를 수집하는 ETL 프로그램에서 덕타이핑을 유용하게 쓰고 있습니다. RestAPI 로 수집하거나, DB 로부터 수집하거나, 파일로부터 수집하거나 “수집”이라는 행동은 공통된 작업이기 때문입니다.

 

그러나 덕 타이핑은 종종 런타임 에러를 낼 수 있는 위험도 있습니다. 예를들어 메소드의 이름이이나 로직이 변경될 때 AttributeError 가 발생할 겁니다.

 

“오리처럼 생겼고, 오리처럼 헤엄치고, 오리처럼 꽥꽥 거린다면 아마도 그것은 오리일 것입니다.”

 

덕 타이핑이란 이름은 위 속담에서 유래가 되었다고 합니다. 

 

끝.

반응형
반응형

안녕하세요. 오늘은 이터레이터에 대해 얕게 배워보겠습니다.

 

iteration 은 (계산 컴퓨터 처리 절차의)반복 이라는 뜻을 갖습니다. 

 

프로그래밍 언어에서 이터레이션은 여러 객체를 담고 있는 반복 가능형 객체(list,set,dictionary)의 요소들을 하나 하나씩 순회하며 꺼낼 수 있는 인터페이스라고 볼 수 있습니다.

 

우리가 파이썬을 공부하면 처음에 배우게 되는 반복문 for 도 구현체 안쪽에서는 iter, __next__() 를 호출하고 있습니다. iter()로 이터레이터 객체를 만들어 next()를 호출하면서 이터레이터 객체를 돌리고, 요소가 없을 때 StopIteraton 예외를 일으켜서 for 루프 종료를 알립니다.

 

직접 for 루프가 되서 호출해보면 다음과 같습니다.

 

test = 'abc'



iterator = iter(test)



next(test)

>> a



next(test)

>> b



next(test)

>> c



next(test)

>> d



next(test)

StopIteration

 

그럼 위에 배운 개념을 이용해서, 요소를 거꾸로 꺼내는 이터레이터 객체를 만들어서 반복문을 돌려보겠습니다.

 

class Reverse:



    def __init__(self,data):

        [self.data](http://self.data) = data

        self.index = len(data)



    def __iter__(self):

        return self



    def __next__(self):

        if self.index == 0 :

            raise StopIteration

        self.index -=1

        return self.data[self.index]

    

rev = Reverse('Hello World')



for c in rev:

    print(c)
 

 

끝.

반응형
반응형

안녕하세요.  오늘의 주제는 함수를 객체처럼 다루기 입니다.

 

 

일단 아래와 같이 factorial 함수를 간단히 작성해보겠습니다.

 

def factorial(n):

    

    if n < 2 :

        return 1

    

    return n * factorial(n-1)



print(factorial(3))

print(factorial.__doc__)  # return n!

 

아래 처럼 함수 객체를 새로운 fact 라는 변수에 할당하고, 이 변수명을 통해 함수를 호출해볼 수 있습니다. 

 

fact = factorial

fact(5)

 

 

이번엔 factorial 을 map() 을 써서 호출해보겠습니다. 

(참고로 map 함수는 반복 가능한 객체를 2번째 요소로 넣어, 1번째 함수의 적용한 결과를 가지는 반복 가능형 객체를 반환합니다.)

 

map(fact,range(5)) -> 0 부터 4까지의 리스트

 

이렇게 하면 map의 주소가 출력되기 때문에, 가시적으로 확인하기 위해 list 로 형변환 해보겠습니다.

list(map(factorial,range(5))) 
-> output [1, 1, 2, 6, 24]

 

 

 위와 같이 구현하는 스타일을 함수형 프로그래밍이라고 부릅니다.

 

 

반응형
반응형

 

오늘은 운영 수준에서 따르면 좋은 파이썬 코딩 규칙들 3가지 정도만 소개해드리겠습니다. 출처는 블로그나 책에서 참고했습니다.

 

 

 

(1) 클래스의 내부 메소드는 _(언더바) 로 시작하는 함수명을 짓는다.

 

(2) 주석 코멘트를 잘 작성해준다.

 

(3) iteration 같은 반복자 루프에서는 null 값을 고려한 방어 코드를 작성한다.

 

 

그럼 짧게 코드로 작성해보면 아래와 같습니다.

class MyClass:

    def run(self, my_list: list[str]):

        for something in my_list or []:              (3) iterating 같은 반복자 루프에서는 null 값을 고려한 방어 코드를 작성한다.  

            self._do_something(something)

        

    

    def _do_something(self,something):   (1) 클래스의 내부 메소드는 _(언더바) 로 시작하는 함수명을 짓는다.

        print(something)

    

    def _clean() -> None:     (2) 주석 코멘트를 잘 작성해준다.



       """write clean code .. """



obj = MyClass()

obj.run(["game","movie","runing"])

 

 

 

 

 

감사합니다. 

 

 

 

.

 

 

 
반응형
반응형

오늘도 간단한 파이썬 코딩을 소개해드리겠습니다.

 

k,v 타입의 파이썬 딕셔너리 타입을 쓸 때, 아래 처럼 키의 유무로 인한 분기를 태우는 코드를 많이 작성하실 거에요. 

 

def use_get_dict():
    my_dict={}
    my_dict['a'] = 1
    my_dict['b'] = 2
    my_dict['c'] = 3

    # 일반적인 방법
    if 'a' in my_dict:
        v = my_dict['a']
        print(f"value is {v}")
    else:
        v = 0
        print("It doesn't have key")
    

딕셔너리 타입의 get () 을 이용해서 동일한 분기 처리를 해보겠습니다.

def use_get_dict():
    my_dict={}
    my_dict['a'] = 1
    my_dict['b'] = 2
    my_dict['c'] = 3

    # dict.get() 을 이용한 방법
    v = my_dict.get('a',0)
    print(f"value is {v}")

 

코드가 조금 간결해졌어요.

 

이번에는 swap 을 해볼게요. 예를 들어 정렬을 구현할 때 두 변수의 값을 교환하는 코드를 보통 이렇게 작성할 텐데요. 

 

def swap_with_temp():
    a = 1
    b = 2
    temp = a
    a = b
    b = temp 

    print(f"a = {a}  b={b}")

 

이번에는 아래 예제 코드를 통해서 temp 변수 없이 a, b 의 변수 값을 교환해보겠습니다.

def swap_without_temp():
    a = 1
    b = 2
    a, b = b, a
    print(f"a = {a}  b={b}") 

 

코드가 조금 더 쉬워보여요

 

오늘은 여기까지하겠습니다.

 

끝.

반응형
반응형

pandas란?

  • 데이터 분석을 위한 파이썬 라이브러리
  • 행과 열로 이루어진 데이터 구조를 다룬다.
  • Series 와 Dataframe 자료구조를 사용한다.

 

 

Dataframe 생성

import pandas as pd

#테스트 데이터 dict 생성
data_exam = {
    'name':['a','b','c','d','e'],
    'height':[160,170,180,185,190],
    'age':[23,15,18,19,25],
    'class':['A','B','A','B','A']
}
.
#pandas dataframe 
df=pd.DataFrame(data_exam)

#read from csv file
df=pandas.read_csv(filepath,names=cols,header=None,encoding="cp949")


#Dataframe()으로 호출하면 안되니까 타이핑에 주의하자

df.index
df.columns
df.dtypes

 

Dataframe 다루기

> 특정 컬럼 조회
df['id'] 

> 특정 복수 컬럼 조회.
df[['id','age']] 

> where 절 조건 조회

df[('id'>10)] # ID 10이상만 조회

df.where(filter1 & filter2, inplace = True)


>컬럼 이름 변경
df.rename(columns={'oldName':'newName'},inplace=True)


>Dataframe convert to tuple
tmp = df['id']
mytuple = [x for x in tmp.to_numpy()]

> 컬럭 삭제
df = df.drop(['컬럼이름','col2'],axis=1)
df.dropna(subset=['컬럼이름'],inplace=True)


> 데이터 컬럼 값 변경
df['Gender'].replace('male',1) # Gender 컬럼의 male 값을 1로 대체
df.loc[df['Gender']=='male','Gender']=1



> 특정 컬럼이 널값인 경우 조회
df[df['컬럼1'].isnull()]


> where, query
dt.where(dt.컬럼명1 == 'value').count()['id']

dt.query('컬럼명1 == "value" | 컬럼명2 > 5').count()


> Group By 
dt.groupby('class') #집계할 컬럼
.agg({'height':['count','mean']}) #집계 함수를 적용
.sort_values([('height','mean')]) # 정렬

#agg 에 컬럼 이름을 주면 multiIndex로 생성되는데 () set 형태로 컬럼 이름이 생성된다.


dt.groupby('컬럼이름').size()  그룹별 카운트


> merge

merge_view=view.merge(user,on='uid').merge(product,on='pid')
merge_view=view.merge(user,on='uid').merge(product,on='pid',how='outer')

 

 

Parquet 파일을 Pandas DataFrame 으로 로드하기

rom fastparquet import ParquetFile

# 만약 압축을 풀어야 한다면
import snappy
def snappy_decompress(data, uncompressed_size):
    return snappy.decompress(data)


pf = ParquetFile('sample.snappy.parquet') # filename includes .snappy.parquet extension
df=pf.to_pandas()
pf = ParquetFile('/Users/amore/178309483_20220714_0000_000000000000.parquet')

## 2
df=pd.read_parquet('/Users/amore/appsflyer.snappy.parquet')
df.head()
print(df.head())

 

MySQL 테이블로부터  Pandas DataFrame 으로 로드하기

from sqlalchemy import create_engine
import pandas as pd
import pymysql



db_conn_str = 'mysql+pymysql://User:비밀번호@DB호스트'
mysql_conn = create_engine(db_conn_str)


data = pd.read_sql_table('BOT_USER',mysql_conn)
 
반응형
반응형

 1.데코레이터

많이들 아시겠지만 파이썬에는 데코레이터라는 기능이 있습니다보통 함수나 메소드에 적용하는 기능인데함수나 메서드의 기능을 확장하거나 변경하는 역할을 합니다

 

 

예를 들어 제가 아래와 같이 어떤 처리 함수 my_func를 만들었습니다. 그런데 함수의 성능을 측정하기 위해 함수의 실행시간을 체크하고 싶어요.

 

함수를 수정할 수도 있겠지만, 저라면 runtime_check 라는 데코레이터로 만들어서 여러 함수에 적용해볼 수 있을 것 같습니다. 아래 코드 처럼 데코레이터를 써볼 수 있습니다.

 

    import time 
    def runtime_check(func):
        def func_wrapper():        
            start_time = time.time()
            func()        # 데코레이터를 적용한 함수가 호출되는 부분
            end_time = time.time()
            print(f"runtime : {(end_time - start_time):.4f}")
        return func_wrapper # wrapper 함수 자체를 반환  

    @runtime_check
    def my_func():
        print("function call..")
        time.sleep(2)
    my_func()

    

   

이 처럼 데코레이터 내부에서의 동작은 기존 함수에 로직을 더해 새로운 함수를 만들고 반환하는 방식입니다.

 

 2.데이터클래스

 

데이터클래스는 모듈 수준의 데코레이터라고 할 수 있어요.

 

예제 코드를 보면서 설명해보겠습니다.

 

# 데이터클래스 데코레이터를 쓰기 위한 import 선언 문이구요.
from dataclasses import dataclass, asdict

@dataclass # 데코레이터는 @ 예약어를 씁니다.
class Customer: # 고객 클래스를 선언하구요.
    name: str   # 이름, 나이, 이메일 정도의 클래스 멤버 변수를 만들구요
    age: int
    email: str
# 2개의 객체를 만들어보았습니다.
c1 = Customer("jss1",20,"jss@test.com")
c2 = Customer("jss1",20,"jss@test.com")
# 객체를 출력하고, 객체간의 비교를 해봤습니다. 
# 그리고 마지막으로 클래스 정보를 json 오브젝트로 변환하기 위해 python dictionary 로 변환해보겠습니다.
print(c1)       # Customer(name='jss1', age=20, email='jss@test.com')
print(c2)        # Customer(name='jss1', age=20, email='jss@test.com')
print(c1==c2)    # True  
print(asdict(c1)) # {'name': 'jss1', 'age': 20, 'email': 'jss@test.com'}

 

네 특별한 게 없는 것 같죠..?

그럼 위 코드에서 @dataclass 를 빼고 실행해보시기 바랍니다.

 

그럼 아마도... 아래와 같은 에러가 발생할 거에요

TypeError: Customer() takes no arguments

 

 

그럼 에러를 처리하기 위해 직접 구현해보겠습니다.

class Customer:
    name: str
    age: int
    email: str
    # 객체 초기화를 위한 특별 메소드
    def __init__(self,name,age,email):
        self.name = name
        self.age = age
        self.email = email
    # 객체를 문자열로 표현해주는 특별 메소드
    def __str__(self) -> str:
        return f"name : {self.name} age : {self.age} email : {self.email}"
    # 객체 비교 특별 메소드
    def __eq__(self, value: object) -> bool:
        return True if self.age == self.age else False

 

 

 

위 코드는 객체를 출력하기 위해 __str__ , 객체를 비교하기 위한 __eq__ , 객체의 생성과 초기화를 위해 __init__ 을 구현해습니다.

** asdict()는 dataclass 타입 인스턴스만 인자로 받기 때문에 에러가 여전히 발생할겁니다.

 

결과적으로 데이터클래스 데코터레이터를 이용하면 작성해야 할 코드를 생략할 수 있어요.  데이터클래스 데코레이터를 이용해서 특수 메서드들이 자동으로 추가된 겁니다.

 

필요하면 활용해보세요. :)

 

끝.

반응형
반응형

5년 전 즈음에 실제 제가 면접에서 받았던 손코딩 문제인데, 재미로 공유 드려봅니다.

 

문제는 되게 간단해요.

 

아래 변수 A 와 B 에 담긴 값을 추가 변수 없이(temp) 없이 교환(swap) 해보는 겁니다.

 

A = 10 

B = 5 

 

한 번 풀어보시죠.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

대부분은 임시 변수를 하나 선언해서 swap 하는 방식을 먼저 떠 올릴 것 같은데요. 고민해보면 이런 방법도 있습니다.

정답은 아래 코드입니다. 

A = A+B // 15 

B = A-B // 10 

A = A-B // 5 

 

 

 

4 바이트를 절약할 수 있었네요. 

 

.

 
반응형
반응형

1.레디스 란?

  • Redis = Re(remote) + di(Dictionary) + s (Server )
  • 메모리를 사용하는 db
  • NoSQL, Replication, Master/Slave 구조로 구성이 가능하다.
  • K/V 형태로 데이터 저장.
  • 파일 싱크를 제공
  • 다양한 데이터 타입 제공
  • Strings, Lists, Set, Hashes, Sorted Sets
  • NoSQL 이기 때문에 Table, db, function, row, column 이 존재 하지 않는다
  • 데이터 Interaction 이 Command 를 통해서 이뤄진다.

 

2.왜 레디스?

  • Simple , Flexible
  • Schema, Table, 이 필요없다.
  • Durable
  • Disk 에 데이터를 저장하는 옵션이 있다.
  • 깃헙, 스냅챗, 트위터, 스택오버플로우 등 다양한 서비스에서 사용중

 

** 추가 정보

  • 100만개의 키들을 저장할때 70MB 정도 공간이 소모 된다.
  • 100만개 - 70 MB. 1억개 - 약 7GB,
  • HashType은 매우 효과적으로 인코딩된 사전구조로 되어 있어, Redis 코어 개발자중 한명인 Pieter Noordhuis가 추천함
  • 아이디를 버킷 사이즈로 divid 한 값을 버킷으로 사용. 예를 들어 버킷 사이즈를 1000개로 만든다면?? 아이디를 1000으로 나눈다. >HSET 'mybucket:1155' '11552' '939' >HGET 'mybucket:1155' '11552'
  • HashType 을 이용하여 버킷으로 저장 하는경우 100만 키 - 16MB
  • 데이터를 durable 할 수 있게 파일에 쓰는 옵션이 다양한데, 안전한 옵션일 수록 redis의 속도를 느리게 한다.

 

3.레디스 도커 컨테이너를 이용하여 빠르게 올려보기

 

A) 레디스 구축 명령어 history

#네트워크 생성
$sudo docker network create redis-net

#레디스 서버 
$sudo docker run --name my-redis --network redis-net -p 6379:6379 -v /home/deploy/redis_data:/data -d redis:alpine redis-server --appendonly yes

# 레디스 컨테이너 실행
$sudo docker run --name my-redis --network redis-net \
-p 6379:6379 \
-v ./redis_data:/data \
-v ./redis.conf:/usr/local/etc/redis/redis.conf \
-d redis:alpine redis-server /usr/local/etc/redis/redis.conf


#레디스 CLI
$sudo docker run -it --network redis-net --rm redis:alpine redis-cli -h my-redis

sudo docker run -it --rm redis:alpine redis-cli -h my-redis
$vi redis.conf
requirepass 1111

 

 

B) redis conf

#인증 패스워드 설정
requirepass 1111

#스냅샷 파일 저장 디렉토리 경로 설정
dir /data

#스냅샷 db 파일 이름 설정
dbfilename dump.rdb

#AOF 설정 (Append-Only File) OS 레벨에서 맛탱이 갔을 때를 대비해 
appendonly yes

# 60초마다 1000번 이상 데이터 변경 시 저장
save 60 1

 

C) Redis Client Command

#인증 패스워드 설정
requirepass 1111

#스냅샷 파일 저장 디렉토리 경로 설정
dir /data

#스냅샷 db 파일 이름 설정
dbfilename dump.rdb

#AOF 설정 (Append-Only File) OS 레벨에서 맛탱이 갔을 때를 대비해 
appendonly yes

# 60초마다 1000번 이상 데이터 변경 시 저장
save 60 1
반응형
반응형

개인 노션을 정리하다 궁금해서 신입부터 경력까지 지원했던 서류와 면접을 집계해봤습니다.

 

서류 탈락 141 개 
서류 합격 56 개 
면접 수 31회 

 

 

자소서 내용까지 보니 당시 어색한 정장을 입고, 심호흡을 하며 면접실로 들어갔던 제 모습이 떠오릅니다. 

 

그 때는 노력에 비해 좋은 결과보다 실망스런 결과가 더 많았던 것 같습니다. 노력이 부족했을 수도 있겠지만 그렇게 생각하고 싶지는 않구요.  "열심히 살았구나" 라고 생각하는게 더 좋겠죠.

 

제 경험을 집약해 볼 때 면접 전에 꼭 준비하고 숙지해야 할 내용들을 대충 생각해서 정리해봅니다. 물론 데이터엔지니어 입장에서..

 

  • 다루고 있는 배치 플랫폼/ 스트리밍 플랫폼의 데이터 규모 (신입이라면 다뤄본 데이터 유형들) 
  • 일일 데이터 적재량 또는 배치 프로그램의 규모 
  • DataWarehouse / DataMart / DataLake / ETL / ELT 의 이해
  • 내가 만들었거나 운영중인 데이터 파이프라인을 그림으로 그리고 설명할 준비
  • 내 강점을 집약해서 한 문장으로 표현
  • 지원한 회사의 정보들 그리고 조사 (회사의 기술 사례 발표 또는 시스템 아키텍쳐) 
  • 면접 마지막에 면접관들에게 던질 진문들 ( 인상적인 질문일 수록 좋음 ) 

 

누군가에게 도움이 되길 바랍니다.

 
반응형

+ Recent posts