1. list comprehensions
리스트 컴프리헨션
: 리스트를 쉽게, 짧게 한 줄로 만들 수 있는 파이썬 문법
- [ 표현식 for 원소 in 반복가능한객체 ]
- [ 표현식 for 원소 in 반복가능한객체 if문 ]
new_list = [x for x in range(1,11)]
print(new_list)
list_comprehension = [element for element in range(1,11) if (element % 2) == 1]
print(list_comprehension)
- 다음과 같은 도시목록의 리스트가 주어졌을때, 도시이름이 S로 시작하지 않는 도시만 리스트로 만들 때 리스트 컴프리헨션을 사용하여 함수를 작성해 보세요.
cities = ["Tokyo","Shanghai","Jakarta","Seoul","Guangzhou","Beijing","Karachi","Shenzhen","Delhi"]
def list_comprehension():
city_list = [city for city in cities if (city[0] != "S")]
print(city_list)
list_comprehension()
- 다음과 같은 도시, 인구수가 튜플의 리스트로 주어졌을때, 키가 도시, 값이 인구수인 딕셔너리를 딕셔너리 컴프리헨션을 사용한 함수를 작성해 보세요.
population_of_city = [ ("Tokyo", 36923000), ("Shanghai", 34000000), ("Jakarta", 30000000), ("Seoul", 25514000), ("Guangzhou", 25000000), ("Beijing", 24900000), ("Karachi", 24300000), ("Shenzhen", 23300000), ("Delhi", 21753486) ]
def list_comprehension2():
population_of_city_list = {city:population for city, population in population_of_city}
print(population_of_city_list)
list_comprehension2()
2. iterators
이터레이터
: 값을 순차적으로 꺼내올 수 있는 객체
iterable
: 반복 가능한 객체 (list, dict, set, str, bytes, tuple, range)
L = [1,2,3]
iterator_L = L.__iter__()
print(L.__iter__())
print("dir iterator_L = ", end=""), print(dir(iterator_L))
print(iterator_L.__next__())
print(iterator_L.__next__())
print(iterator_L.__next__())
print(iterator_L.__next__())
L = [1,2,3,4]
I = iter(L)
while True:
try:
X = next(I)
except StopIteration:
break
print(X**2, end=" ")
D = {'a':1, 'b':2, 'c':3}
I2 = iter(D)
while True:
try:
key = next(I2)
except StopIteration:
break
print(key, end=" ")
3. generators
제너레이터
: 배열이나 리스트와 같은 반복가능한 연속적인 값들을 생성해 내는 패턴
def generator_squares():
for i in range(3):
yield i**2
print("gen object=", end=""), print(generator_squares())
print("dir gen =", end=""), print(dir(generator_squares()))
gen = generator_squares()
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
print(gen.__next__())
def generator_send():
received_value = 0
while True:
received_value = yield
print("received_value = ", end="", print(received_value)
yield received_value * 2
gen = generator_send()
next(gen)
print(gen.send(2))
next(gen)
print(gen.send(3))
- 제너레이터 표현식의 문법은 리스트 컴프리헨션 문법과 비슷하지만 대괄호([])가 아닌 괄호()를 사용하여 만듭니다.
L = [1,2,3]
def generate_square_from_list():
result = (x*x for x in L)
print(result)
return result
def print_iter(iter)
for element in iter:
print(element)
print_iter(generate_square_from_list())
- 다음코드를 실행해보고 분석한 결과를 블로깅하는 과제 입니다. lazy evaluation 이란 무엇인지와 장점 및 리스트 컴프리헨션과의 차이점에 대하여 블로깅 해주세요.
import time
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)
Lazy evaluation
- 어떠한 값이 실제로 쓰일 때까지 그 값의 계산을 뒤로 미루는 것
- 어떤 값이 필요할 때에만 연산을 수행하는 것은 컴퓨팅 자원의 절약에 도움이 된다.
- 전체 연산의 시간을 줄일 수 있다.
- 코드가 점점 복잡해지고 난해해 질 수 있다.
리스트 컴프리헨션
: lazy_return을 3회 연속 실행한 후 print_iter을 1회 실행
레이지 에볼루션
: lazy_return 1회 실행 후 print_iter을 1회 실행하는 과정을 3회 반복
import time
import random
counter = random.randrange(1, 11)
print("counter: {}".format(counter))
def return_one_after_five_sec():
print("please wait for 5 seconds")
time.sleep(5)
print("return 1")
return 1
print("[let's make one_list !]")
one_list = [return_one_after_five_sec() for x in range(10)]
print("[let's print one_list !]")
for item in one_list:
counter -= 1
print(item)
if counter == 0:
break
- 50초에 걸쳐 리스트를 미리 다 만들어 놓았으나 랜덤한 counter 값이 2가 나와 실제로 쓰인 값은 두 개이다.
-> 이런 상황에서는 generator로 만들어놓는게 효율적이다! (대괄호만 소괄호로 바꾸면 된다.)
import time
import random
counter = random.randrange(1, 11)
print("counter: {}".format(counter))
def return_one_after_five_sec():
print("please wait for 5 seconds")
time.sleep(5)
print("return 1")
return 1
print("[let's make one_generator !]")
one_generator = (return_one_after_five_sec() for x in range(10))
print("[let's print one_generator !]")
for item in one_generator:
counter -= 1
print(item)
if counter == 0:
break
- 대부분의 요소가 사용될 것이 확실하다면 list를 통해 미리 연산을 하는 것이 효율적이지만 그렇지 않으면 generator사용하는 것이 더 효율적이다.
4. Lambda expressions
람다
: 인라인 함수를 정의할 때 사용하며 익명 합수(anonymous functions) 또는 람다 표현식(lambda expression)이라고 부릅니다.
- 필요한 곳에서 즉시 사용하고 버릴 수 있는 일시적인 함수
- 람다는 표현식이므로 return을 사용할 수 없습니다.
- lambda argument1, argument2, ... argumentN : expression using arguments
f = lambda x,y,z : x+y+z
print(f)
print(f(1,2,3))
Lambdas = [
lambda x : x ** 2,
lambda x : x ** 3,
lambda x : x ** 4
]
for lambda_func in Lambdas:
print(lambda_func(2))
- 다음 코드를 실행해보고 print문으로 출력되는 출력결과를 확인해보고 types 모듈에 LambdaType 외에도 어떤 타입들이 있는지 조사해 보세요.
import types
f = lambda x,y,z : x+y+z
print(f)
print(type(f))
print( type(f) == types.LambdaType)
types의 종류
- types.FunctionType : 사용자 정의 함수
- types.LambdaType : lambda 표현식이 만든 함수
- types.GeneratorType : 제너레이터 객체의 형
- types.CoroutineType : 코루틴 객체의 형
- types.AsyncGeneratorType : 비동기 제너레이터 함수가 만든 비동기 제너레이터-이터레이터 객체의 형
- types.CodeType : compile()이 반환하는 것과 같은 코드 객체의 형
- types.MethodType : 사용자 정의 클래스 인스턴스의 메서드 형
- 다음과 같이 비밀번호의 길이와 대문자가 포함된것을 확인하는 간단한 함수가 있습니다. 이 함수에 있는 if문 두개를 람다표현식을 이용하여 다음과 같은 형식으로 작성해 보세요.
lambdas = [
lambda password : "SHORT_PASSWORD" if len(password) < 8 else None,
lambda password : "NO_CAPITAL_LETTER_PASSWORD" if not any(c.isupper() for c in password) 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'))
print(check_password_using_lambda('12356789f'))
print(check_password_using_lambda('123456789F'))