본문 바로가기
Python/Pythonic Code

Pythonic Code #2 (lambda, mapreduce, iterator, generator, asterisk)

by emilia park 2023. 4. 2.
728x90

Pythonic Code 기법 이어서!!

Step 1은 아래 글에!! 

 

https://emilia.tistory.com/26

 

Pythonic Code #1 (split, join, list comprehension, enumerate, zip)

[Pythonic Code] - 파이썬 스타일의 코딩기법이다. - 파이썬 특유의 문법을 활용하여 효율적인 코드를 작성 가능하다. - 고급 코드를 작성할 수록 더 많이 필요해진다. * 주요 기법 split and join list compre

emilia.tistory.com

 

 

 

f) Lambda

- 함수 이름 없이 함수처럼 쓸 수 있는 익명함수 

- 수학의 람다 대수에서 유래 

- f = lambda x,y: x+y

- (lambda x,y: x+y)(10,50)

- print(f(1,4))

 

##### Lambda Ex

f = lambda x,y: x+y
print(f(1,4))

#출력 
# 5


f = lambda x: x**2
print(f(3))

#출력 
# 9


(lambda x,y: x+y)(10,50) 

#출력
# 60


up_low = lambda x: x.upper() + x.lower()
up_low('My Happy') 

#출력
# 'MY HAPPYmy happy'

 

 

g) Map

- sequence 자료형의 각 element에 동일한 function을 적용시켜준다.

- 두 개 이상의 list에도 적요이 가능하다.

- if filter 사용 가능하다.

##### Map Ex

#method1 - list로 변환
ex = [1,2,3,4,5]
f = lambda x:x**2
print(list(map(f,ex)))

#출력 
# [1, 4, 9, 16, 25]



#method2 - 값 하나하나 출력
for value in map(f,ex): 
    print(value)
result = map(f,ex) 
result 

#출력
1
4
9
16
25
##### Map + List Comprehension

ex = [1,2,3,4,5]
list(map(lambda x:x**2 if x%2==0 else x, ex))

#출력 
# [1, 4, 3, 16, 5]


#####Only List Comprehension

ex = [1,2,3,4,5]
print( [value**2 if value%2==0 else value for value in ex])

#출력 
# [1, 4, 3, 16, 5]

위 처럼 map function 은 굳이 써주지 않아도 List Comprehension 만으로도 같은 출력을 낼 수 있다.

list comprehension 내의 for문으로 map을 쓰지 않고도  sequence자료형의 데이터들을 모두 사용해 원하는 값으로 도출할 수 있는 것이다.

 

 

 

 

h) Reduce

- list에 똑같은 함수 적용해서 결과를 통합한다.

- lamda function 을 작용시키는데 필요한 변수 수보다 입력 값의 개수가 작아선 안된다.

##### Reduce Ex

from functools import reduce #reduce function setup 

a = reduce(lambda x,y: x+y, [1,2,3,4,5])
print(a) 

#출력
# 15

 

*map and reduce function 

파이썬 측에서도 사용 하지 않을 것을 권장한다. 

- 문법이 어렵다. 

- 테스트가 어렵다.

- 문서화 docstring 지원이 미비하다.

- 코드 해석이 어렵다.

- 이름이 존재하지 않는 함수의 출현으로 일관성 떨어진다. 

- 그래도 아직은 쓰이긴 한다

ref) http://www.python.org/dev/peps/pep-0008/

 

 

 

 

i) Iterator & Iterable objects

- sequence 형 자료형에서 데이터를 순서대로 추출하는 object 

: list/ tuple/string 

- iter()와 next()의 함수로 iterable object를 iterator object로 사용한다.

##### Iterable object Ex

cities = ['Seoul','Busan','Jeju']
iter_obj = iter(cities) 
print(iter_obj)

#출력 
# <list_iterator object at 0x7fdfdd4d5490>
#메모리 주소만 가지고 있다.
#출력 방법1 : next()로 iterator object 사용
#출력 방법2 : for 문으로 iterator object 출력


#method1 : next() 
next(iter_obj)

#출력
# 'Seoul'


#method2 : for loop
for value in iter_obj:
    print(value)

#출력
Seoul
Busan
Jeju

 

 

 

j) Generator 

- iterable object를 특수한 형태로 사용하는 함수이다.

- element가 사용되는 시점에 값을 메모리에 반환한다.

- list로 한번에 메모리에 올릴 수 있다. 

- list(gen_ex) 형태를 활용해 메모리에 올린다.

- yield 를 이용해 값을 여러 개로 나누어서 출력이 가능하다.

 

* Generator + list comprehension

- list comprehension 과 유사한 형태로 generator 형태의 list를 생성할 수 있다. 

- generator expression 이라는 이름으로 불린다. 

- [] 대신 ()을 사용한다.

- 즉, list comprehension 형태인데 []대신 ()가 쓰여있다면 generator 형태인 것이고 

- list function 을 활용해야 메모리에 올려진다는 점.

 

* Why Generator ? 

- iterator는 generator에 반해 훨씬 큰 메모리 용량을 사용한다. 

- 필요할 때만 올리는 방식으로 하기엔 generator 가 필요하다.

 

* When Generator !

- list 타입의 데이터를 반환해주는 함수는 generator 로 만들자.

: 읽기 쉽다는 장점

- 큰 데이터 처리시 generator 를 고려하자.

: 데이터가 커져도 처리의 어려움이 없다.

- 파일 데이터 처리시 generator 를 쓰자.

 

##### Yield Generator Ex

def generator_list(value):
    result = []
    for i in range(value): 
        yield i

generator_list(10)
next(generator_list(10))

#출력 
# 0
#next 로 값 확인. next 해줄 때마다 다음 값 출력.
##### Yield Generator Ex

def gen_ex() : 
    n=1 
    print('first')
    yield n 
    
    n+=1
    print('second') 
    yield n 
    
    n+=1
    print('last')
    yield n 
    
    
for item in gen_ex(): 
    print(item)

list(gen_ex())

#출력
first
1
second
2
last
3
first
second
last
[1, 2, 3]
##### Generator + List Comprehension Ex

gen_ex = (n*n for n in range(10)) #[] 말고 ()사용 

for value in gen_ex: 
    print(value) 
    
print(type(gen_ex)) #<class 'generator'>

#출력
0
1
4
9
16
25
36
49
64
81
<class 'generator'>
##### Generator and list comprehension Memory size comparison

from sys import getsizeof 

#generator
gen_ex = (n*n for n in range(500))
print(getsizeof(gen_ex)) #generator size
print(getsizeof(list(gen_ex))) #generator->list size 

#출력
# 112
# 4216


#list comprehension 
list_ex = [n*n for n in range(500)]
print(getsizeof(list_ex)) #list size

#출력
# 4216

위와 같이 generator 상태의 메모리 사이즈는 112로 리스트로 변환했을 때보다 현저히 작은 값을 가진다. 

이는 더 큰 리스트 일수록 더 값 차이가 커지게 된다. 이로써 큰 데이터를 처리할 때는 generator 로 메모리를 줄일 수 있다.

 

##### Generator 속도

def gen_case(): 
    gen_ex = (n*n for n in range(500))
    
    for v in gen_ex: 
        pass

def general_case(): 
    list_ex = [n*n for n in range(500)]
    
    for v in list_ex: 
        pass
    
%timeit gen_case() 
%timeit general_case() 

#출력 
# 45 µs ± 431 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
# 43.6 µs ± 2.82 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

 

 

 

k) Function Arguments (asterisk를 위한 buildup)

- 함수에서 입력되는 arguments에는 다양한 형태가 있다. 

 

     k-i) keyword : 함수에서 입력되는 parameter의 직접 변수명을 사용한다.

     k-ii) default : 함수에서 입력되는 parameter의 기본값을 사용한다. 

            -> 즉, parameter를 입력하지 않을 경우 기본값을 출력한다.

##### Keyword Arguments Ex

def print_something(my_name, your_name): 
    print('hello {0}, My name is {1}'.format(your_name, my_name))
    

print_something(your_name = 'Tstory',my_name = 'emilia') 
print_something('emilia', your_name = 'TEAMLAB') 

#출력
# hello Tstory, My name is emilia
# hello Tstory, My name is emilia

한 파라미터가 keyword argument 쓰는 순간 뒤에도 다 keyword argument 사용해야한다.
순서가 맞으면 상관은 없지만 순서가 뒤바뀌었다면 keyword는 다 써줘야한다.

##### Default Argument Ex

def print_something(my_name, your_name="Tstory"): 
    print('hello {0}, My name is {1}'.format(your_name, my_name))
 

print_something('emilia')

#출력 
# hello Tstory, My name is emilia

 

 

 

l) Asterisk (가변인자, *args) 

- 개수가 정해지지 않은 변수를 함수의 parameter로 사용한다.

- keyword arguments 와 함께 argument 추가가 가능하다.

- asterisk (*) 기호를 사용하여 함수의 파라미터를 표시한다.

- 입력된 값은 tuple type이다.

- 오직 한 개만, 맨 마지막 paameter 위치에 사용이 가능하다.

 

* keyword asterisk (키워드 가변인자, **kwarg)

- 파라미터 이름을 따로 지정하지 않고 입력한다.

- dictionary type을 사용한다.

- 기존 가변인자 다음에 활용한다.

 

* Asterisk Unpacking 

- tuple, dictionary 등 자료형의 값을 unpacking 한다.

- 함수의 입력값, zip 등에 유용하게 사용된다.

##### Asterisk Ex

def asterisk_test( *args): 
    x,y,z = args
    
    return x,y,z 
print(asterisk_test(1,2,3)) #3개 값 필요. 2,4개 입력시 에러.

#출력 
# (1,2,3)
##### Keyword Asterisk Ex

def kwargs_test_1(**kwargs):
    print(kwargs) 
    
kwargs_test_1(first = 3, second=5, third = 5) 

#출력
# {'first': 3, 'second': 5, 'third': 5}



def kwargs_test_3(one, two, *args, **kwargs):
    print(args)
    print(one+two+sum(args))
    print(kwargs) 
    
kwargs_test_3(3,4,5,6,7,8,9, first = 3, second=4, third = 5) #args = (5,6,7,8,9)
kwargs_test_3(3, two =10, first = 3, second=4, third = 5) #no args

#출력
(5, 6, 7, 8, 9)
42
{'first': 3, 'second': 4, 'third': 5}
()
13
{'first': 3, 'second': 4, 'third': 5}
##### Asterisk Unpacking Ex

def asterisk_test(a,args): 
    print(a,args)
    print(type(args))
    
asterisk_test(1,(2,3,4,5,6)) #arg는 튜플이여서 이 자체로 하나의 변수이므로 에러x

#출력 
# 1 (2, 3, 4, 5, 6)
# <class 'tuple'>


asterisk_test(1,*(2,3,4,5,6)) #arg 를 unpacking 하면서 여러 값들로 입력이 되기에 에러 발생

#에러발생
##### Asterisk Unpacking Ex

a,b,c = ([1,2],[3,4],[5,6])
print(a,b,c)

data = ([1,2],[3,4],[5,6])
print(*data)

#출력
# [1, 2] [3, 4] [5, 6]
# [1, 2] [3, 4] [5, 6]
##### Keyword Asterisk Unpacking 

def asterisk_test(a,b,c,d):
    print(a,b,c,d)


data = {"b":1, "c":2, "d":3}
asterisk_test(10,**data) 

#출력
# 10 1 2 3 


def asterisk_test(a,b,c,d,e=0):
    print(a,b,c,d,e) 

data = {"d":1, "c":2, "b":3, 'e':56}
asterisk_test(10,b=3,c=3,d=1,e=56)
asterisk_test(10,**data)

#출력
# 10 3 3 1 56
# 10 3 2 1 56
##### Asterisk with zip 

#Asterisk X
ex = ([1,2],[3,4],[5,6])
a,b,c = ex

for data in zip(a,b,c): 
    print(sum(data))
    
#출력
# 9
# 12


#Asterisk O
ex = ([1,2],[3,4],[5,6],[5,6],[5,6])
for data in zip(*ex): 
    print(data) 

#출력
# (1, 3, 5, 5, 5)
# (2, 4, 6, 6, 6)

 

 

Pythonic Code의 주요 기법은 끝! 

Step3에서는 pythonic code를 활용한 linear algebra 에 대해서 정리를 해보려 한다.

끗!

 

728x90