Advanced Python

do yeon kim·2022년 6월 28일
0

Advanced Python

List comprehensions

[ 표현식 for 원소 in 반복 가능한 객체 ]

[ 표현식 for 원소 in 반복 가능한 객체 if문 ]

[표현식 if문 else문 for 원소 in 반복 가능한 객체]

list comperhensions이란 새로운 리스트를 만들 때 사용하는 간단한 표현식이다.
먼저 for문을 통해서 lst안의 요소들을 하나씩 꺼내어 i+5를 한 결과를 다시 리스트 안에 담는다.

lst = [10,20,30,40,50]
lst = [i+5 for i in lst]
print(lst)

결과
[15, 25, 35, 45, 55]

for문 뒤에 if문으로 조건을 추가 할 수도 있다.
먼저 for문에서 i로 요소를 하나씩 꺼내온다. 그후 i를 조건과 비교한다. 조건에 맞으면 i*10을 수행한다.
그리고 결과를 리스트로 만든다.

lst = [10,20,30,40,50]
lst = [i*10  for i in lst if i > 30 ]
print(lst)

결과
[400, 500]

if-else문의 조건을 추가하기 위해서는 for문 앞에 조건문을 붙혀야 한다.
먼저 for에서 i로 요소를 하나씩 꺼내온다. 그후 조건문에서 조건 비교 후 리스트로 만든다.

lst = [10,20,30,40,50]
lst = [i*10  if i > 30 else 0 for i in lst ]
print(lst)

결과
[0, 0, 0, 400, 500]

list comprehensionsdms 작성한 코드는 간결하고 데이터베이스에서 조회하여 리스트 만들때 많이 사용한다. 또한 성능 개선을 위해서 사용되는 경우도 있다.
하지만 모든 경우에 사용하는 것은 아니다. 코드의 가독성을 위해서 사용하지 않는 경우도 있다.

Assignments

1번 문제
cities = ["Tokyo", "Shanghai","Jakarta","Seoul","Guangzhou","Beijing","Karachi","Shenzhen","Delhi" ]
result = [i for i in cities if i[0] != "S"]
print(result)


결과
['Tokyo', 'Jakarta', 'Guangzhou', 'Beijing', 'Karachi', 'Delhi']

2번 문제

population_of_city = [("Tokyo", 36923000), ("Shanghai", 34000000), ("Jakarta", 30000000), ("Seoul", 25514000), ("Guangzhou", 25000000), ("Beijing", 24900000), ("Karachi", 24300000), ("Shenzhen", 23300000), ("Delhi", 21753486)]

dic_result = { i[0]:i[1] for i in population_of_city  }
print(dic_result)


결과
{'Tokyo': 36923000, 'Shanghai': 34000000, 'Jakarta': 30000000, 'Seoul': 25514000, 'Guangzhou': 25000000, 'Beijing': 24900000, 'Karachi': 24300000, 'Shenzhen': 23300000, 'Delhi': 21753486}




iterators

우리가 for문을 이용해서 시퀀스자료형을 하나씩 꺼내 올때 안에서는 어떤 원리로 이루어 지는 것일까?

내부적으로 __iter__함수__next__함수 가 작동하면서 하나씩 가지고 온다.

__iter__는 객체를 iterator 객체로 만든다. 그리고 __next__로 iterator객체에서 하나씩 가지고 온다.

범위를 넘는 것을 가지고 오게 되면 StopIteration이 발생한다.

iternext

iter은 객체 __iter__함수를 호출해준다.
next는 객체의 __next__함수를 호출해준다.

D = {'a':1, 'b':2, 'c':3}
# for key in D.keys():
#     print(key)

new_D = iter(D)


while True:
    try: 
        #키 출력
        print(next(new_D)) 
    except:
        print("예외발생")
        break


while True:
    try:
        #키에 대한 값 출력
        a = D[next(new_D)]
        print(a)
    except:
        print("예외발생")
        break

while문 안에서 두개를 같이 출력할 수 없다. next()를 한번 호출하면 반드시 다음 거로 넘어가게 된다.







generators

제너레이터
제너레이터는 이터레이터를 생성해주는 함수이다.
제너레이터는 yield가 있다.
일반함수에서 값을 반환하기 위해서 return을 사용한다면
제너레이터에서는 yield라는 키워드로 값을 반환한다.

일반함수가 return하면 바로 실행을 해서 반환을 해주는 반면,
제너레이터함수는 next가 호출 될 때 까지 반환을 기다리고 있는다.
next가 호출되면 yield로 값을 반환해준다.
yield키워드를 이용해서 next가 호출될 때 마다 이전 결과에 이어서 다음을 반환해준다.

이터레이터의 경우 __iter__함수 또는 iter(제너레이터객체)를 이용해서 이터레이터객체로 만든 후 __next__함수 또는 next(제너레이터객체)를 호출해서 요소를 하나씩 꺼내왔다.

제너레이터의 경우 이터레이터와 같이 __iter__함수``__next__함수가 있지만 따로 이터러블한 객체로 만들지 않고 바로 __next__함수를 이용해서 요소를 가지고 올 수 있다.

def test_generators(): # 제너레이터함수 생성
    for i in test:
        yield i	# for문으로 들어온 값들을 yield해준다.

test= range(1,10)

a  = test_generators() # 제너레이터 객체 생성

try: 
    for i in range(len(test)): # 리스트의 요소만큼 반복
        print(next(a))	# 제너레이터 next()함수 호출
except StopIteration:	# 리스트 이상의 요소 반환 시도시 예외 발생
    print("Stop")

send()함수

제너레이터 함수는 실행 중에 send()함수를 이용해서 값을 보낼 수 있다.

def test_generators():
    x= 0
    while True:
        x = yield x  +100
        
a  = test_generators()

for i in range(5):
    print(a.send(i))

오류발생
can't send non-None value to a just-started generator

제너레이터에서 send()함수를 실행 하기 위해서는
next()를 이용해서 제너레이터를 사용한다는 것을 알려주어야 한다.
generator function is started , it is not possible to pass values in.

def test_generators():
    x= 0
    while True:
        x = yield x  +100
        

a  = test_generators()

next(a) #제너레이터를 실행한다는 것을 알려준다.

for i in range(5):
    print(a.send(i))

제네레이터표현식
제네레이터 표현식은 리스트컴프리헨션과 같이 for문을 이용해서 새로운 형태로 만든다.

리스트컴프리헨션과 달리 제너레이터 표현식은 메모리 사용을 더 적게 한다.
제너레이터 표현식은 Lazy evaluation을 위해서 사용될 수 있습니다.

lst = [1,2,3,4,5]

list_result = [i *10 for i in lst]
generator_result =(i *10 for i in lst)

print(list_result)
print(generator_result)
print(next(generator_result))

[10, 20, 30, 40, 50] 리스트반환
<generator object <genexpr> at 0x10983dd20> 제너레이터 객체반환
10 next를 호출했을 경우 10 반환


제너레이터 표현식은 list comprehension에 비해 메모리를 절약할 수 있다.
list comprehension은 실행결과를 모두 가지고 온다면,
generators 표현식은 실행순간 순간마다 실행결과를 가지고 오기 때문에 메모리를 절약할 수 있다.

list_data = [i*3 for i in range(1,10000 +1)]
generator_data = (i*3 for i in range(1,10000 +1))

#객체가 얼마나 데이터를 잡아먹는지 확인
import sys

print(sys.getsizeof(list_data))
print(sys.getsizeof(generator_data))

실행결과
list comprehension 85176
generator 표현식 104

위에서 얼마만큼의 데이터를 사용하는 지를 알수 있다.
list comprehension 85176
generator 표현식 104 만큼 사용한다.

문제1

이번 과제는 다음코드를 실행해보고 분석한 결과를 블로깅하는 과제 입니다. lazy evaluation 이란 무엇인지와 장점 및 리스트 컴프리헨션과의 차이점에 대하여 블로깅 해주세요.

import time

L = [ 1,2,3]
def print_iter(iter):
    for element in iter:
        print(element)

def lazy_return(num):
    print("sleep 1s")
    time.sleep(1)
    return num

print("comprehension_list=")
comprehension_list = [ lazy_return(i) for i in L ]
print_iter(comprehension_list)

print("generator_exp=")
generator_exp = ( lazy_return(i) for i in L )
print_iter(generator_exp)

실행결과
comprehension_list=
sleep 1s
sleep 1s
sleep 1s
1
2
3

generator_exp=
sleep 1s
1
sleep 1s
2
sleep 1s
3

lazy evaluation의 사전적 의미는 컴퓨터 프로그래밍에서 느긋한 계산법으로 계산의 결과값이 필요할 때까지 계산을 늦추는 기법이다.

위의 코드 결과
comprehension_list는 모든 결과값을 한번에 리턴한다.
generator 표현식은 필요할때마다 하나씩 요소를 반환한다.







lambda expressions

람다함수는 인라인 함수를 정의 할 때 사용하며 익명함수(이름이 없는 함수) 또는 람다 표현식 이라고 한다. 다른 함수의 인자로 넣을 수도 있고 코드가 간결해지며, 메모리가 절약된다는 장점이 있다.

람다함수 기본적 형태

#기본형태
lambda 매개변수 : 결과 

#사용방법
방법1
lambda 매개변수 : 결과 (인자)

방법2
f = lambda 매개변수 : 결과
f(인자)

람다함수에서 if-else구문 사용하기

lambda 매개변수 : 결과 if 조건 else 결과

if문에 대한 결과는 앞에 else문에 대한 결과는 뒤에 온다.


map()함수, filter()함수
map()함수와 filter()함수의 매개변수로 람다함수가 사용된다.

map((lambda 매개변수 : 결과), 시퀀스자료형)
filter((lambda 매개변수 : 결과), 시퀀스자료형)

문제1
import types

f = lambda x,y,z : x+y+z

print(f)
print(type(f))
print( type(f) == types.LambdaType)

문제2
lambdas = [ lambda a : "SHORT_PASSWORD" if len(a) < 8 else None ,
            lambda a : 'NO_CAPITAL_LETTER_PASSWORD' if not any(i.isupper() for i in a) else None
]


def check_password_using_lambda(password):

    for f in lambdas:
        if f(password) is not None:
            return f(password)

    return True


print( check_password_using_lambda('123') )            # SHORT_PASSWORD
print( check_password_using_lambda('12356789f') )      # NO_CAPITAL_LETTER_PASSWORD
print( check_password_using_lambda('123456789F') )    # True

0개의 댓글