수색…


소개

파이썬의 목록 내포는 간결하고 구문적인 구조입니다. 목록의 각 요소에 기능을 적용하여 다른 목록에서 목록을 생성하는 데 활용할 수 있습니다. 다음 절에서는이 표현식의 사용법을 설명하고 보여줍니다.

통사론

  • [x (1, 2, 3)] x 목록 이해력 [x, 1] [2, 3, 4]
  • ((1, 2, 3)에서 x에 대해 x + 1) # 생성자 표현식은 2, 3, 4
  • [x가 (1, 2, 3)이면 x % 2 == 0] # 필터로 목록 이해력, [2]
  • [x + 1이면 x = 2, x는 (1, 2, 3)에서 x는 else x]
  • [x + 1이면 x % 2 == 0 else x는 범위 (-3,4)이면 x> 0] # ternary 및 필터링으로 목록 이해력
  • {x는 (1, 2, 2, 3)에서 x에 대해} # 집합 이해력은 {1, 2, 3}
  • { 'a': 1, 'b': 2} (파이썬 2.7+ 및 {b ', 2)}를 제공합니다. 3.0 이상 만 해당)
  • [10, 20]에서 y의 [1, 2]에서 x에 대한 x + y] # 중첩 루프 [11, 21, 12, 22]
  • [3, 4, 5]에서 y에 대해 x> 2 인 경우 [x, y는 [1, 2, 3에서] x]
  • [x> 2 인 경우 [3, 4, 5]에서 y에 대해 [1, 2, 3에서 x에 대해 y]
  • [x가 x % 2 인 경우 xrange (10) == 0] # 반복 된 숫자가 홀수 인 경우 조건 확인

비고

이해는 특정 언어에 고유 한 데이터 구조 또는 표현을 정의하는 구문 구조입니다. 이해력의 적절한 사용은 이것을 쉽게 이해할 수있는 표현으로 재 해석합니다. 표현식으로 사용할 수 있습니다.

  • 과제의 오른편에
  • 함수 호출에 대한 인수로
  • 람다 함수 의 본문에
  • 독립 실행 형 명세서로 (예 : [print(x) for x in range(10)] )

목록 이해력

목록 이해반복 가능한 각 요소에 표현식을 적용하여 새 list 을 만듭니다. 가장 기본적인 형태는 다음과 같습니다.

[ <expression> for <element> in <iterable> ]

선택적 'if'조건도 있습니다.

[ <expression> for <element> in <iterable> if <condition> ]

<iterable> 의 각 <element> 는 (선택적) <condition> 이 true로 평가 되면 <expression> 연결됩니다. 모든 결과는 새 목록에 한 번에 반환됩니다. 생성자 표현식 은 느리게 평가되지만 목록 내포는 전체 반복자를 즉시 ​​평가합니다. 반복자 길이에 비례하여 메모리를 소비합니다.

제곱 된 정수 list 을 만들려면 :

squares = [x * x for x in (1, 2, 3, 4)]
# squares: [1, 4, 9, 16]

for 표현식은 x(1, 2, 3, 4) 에서 차례대로 각 값으로 설정합니다. x * x 표현식의 결과는 내부 list 추가됩니다. 완료되면 내부 list 이 변수 squares 할당됩니다.

속도 향상 ( 여기에 설명 ) 외에도 목록 이해는 다음 for 루프와 대략 같습니다.

squares = []
for x in (1, 2, 3, 4):
    squares.append(x * x)
# squares: [1, 4, 9, 16]

각 요소에 적용되는 식은 필요한만큼 복잡 할 수 있습니다.

# Get a list of uppercase characters from a string
[s.upper() for s in "Hello World"]
# ['H', 'E', 'L', 'L', 'O', ' ', 'W', 'O', 'R', 'L', 'D']

# Strip off any commas from the end of strings in a list
[w.strip(',') for w in ['these,', 'words,,', 'mostly', 'have,commas,']]
# ['these', 'words', 'mostly', 'have,commas']

# Organize letters in words more reasonably - in an alphabetical order
sentence = "Beautiful is better than ugly"
["".join(sorted(word, key = lambda x: x.lower())) for word in sentence.split()]
# ['aBefiltuu', 'is', 'beertt', 'ahnt', 'gluy']

그밖에

else 는 List comprehension 구문에서 사용할 수 있지만 구문에 대해서는주의해야합니다. if / else 절은 for 루프 전에 사용되어야하며 다음은 사용되지 않아야합니다.

# create a list of characters in apple, replacing non vowels with '*'
# Ex - 'apple' --> ['a', '*', '*', '*' ,'e']

[x for x in 'apple' if x in 'aeiou' else '*']
#SyntaxError: invalid syntax

# When using if/else together use them before the loop
[x if x in 'aeiou' else '*' for x in 'apple']
#['a', '*', '*', '*', 'e']

여기에는 다른 언어 구문 인 조건부 표현식 이 사용되며 이는 자체적으로 독해 구문의 일부가 아닙니다. 반면 if 애프터 for…in 리스트 지능형 일부 소스로부터 반복 가능한 요소를 필터링하는사용된다.


이중 반복

이중 반복의 순서 [... for x in ... for y in ...] 는 자연 스럽거나 반 직관적입니다. 엄지 손가락 규칙은 for 루프를 따라하는 것 for .

def foo(i):
    return i, i + 0.5

for i in range(3):
    for x in foo(i):
        yield str(x)

이것은 다음과 같습니다.

[str(x)
    for i in range(3)
        for x in foo(i)
]

이것은 [str(x) for i in range(3) for x in foo(i)] 로 한 줄로 압축 될 수 있습니다 [str(x) for i in range(3) for x in foo(i)]


현재 위치 변경 및 기타 부작용

목록 이해력을 사용하기 전에 대개 None 을 반환하는 부작용 ( 돌연변이 또는 내부 함수)과 흥미있는 값을 반환하는 함수의 차이점을 이해하십시오.

많은 함수 (특히 순수 함수)는 단순히 객체를 가져 와서 객체를 반환합니다. in-place 함수는 부작용 이라고하는 기존 객체를 수정합니다. 다른 예로 인쇄와 같은 입력 및 출력 작업이 있습니다.

list.sort() 는 현재 위치에서 목록 정렬하고 (원래 목록을 수정 함을 의미) None 값을 반환합니다. 따라서 목록 이해에서 예상대로 작동하지 않습니다.

[x.sort() for x in [[2, 1], [4, 3], [0, 1]]]
# [None, None, None]

대신, sorted() 는 내부 정렬이 아닌 정렬 된 list 반환합니다.

[sorted(x) for x in [[2, 1], [4, 3], [0, 1]]]
# [[1, 2], [3, 4], [0, 1]]

I / O 또는 내부 기능과 같은 부작용에 대한 이해를 사용하는 것이 가능합니다. 그러나 for 루프는 일반적으로 더 읽기 쉽습니다. 이것이 파이썬 3에서 작동하는 동안 :

[print(x) for x in (1, 2, 3)]

대신 다음을 사용하십시오.

for x in (1, 2, 3):
    print(x)

일부 상황에서는 부작용 기능 목록 이해에 적합합니다. random.randrange() 는 난수 생성기의 상태를 변경하는 부작용이 있지만 흥미로운 값을 반환합니다. 또한 iterator에서 next() 를 호출 할 수 있습니다.

다음 임의 값 생성기는 순수하지는 않지만식이 계산 될 때마다 임의 생성기가 재설정되므로 의미가 있습니다.

from random import randrange
[randrange(1, 7) for _ in range(10)]
# [2, 3, 2, 1, 1, 5, 2, 4, 3, 5]

목록 포함의 공백

보다 복잡한 목록 이해력은 바람직하지 않은 길이에 도달하거나 읽기 어려워 질 수 있습니다. 예제에서는 덜 일반적이지만 목록 이해도를 여러 줄로 나눌 수 있습니다.

[
    x for x
    in 'foo'
    if x not in 'bar'
]

사전 이해

사전 독해 는 목록 대신 사전 객체를 생성한다는 점을 제외하고는 목록 이해와 유사합니다.

기본 예 :

Python 2.x 2.7
{x: x * x for x in (1, 2, 3, 4)}
# Out: {1: 1, 2: 4, 3: 9, 4: 16}

이것은 글쓰기의 또 다른 방법입니다.

dict((x, x * x) for x in (1, 2, 3, 4))
# Out: {1: 1, 2: 4, 3: 9, 4: 16}

목록 이해와 마찬가지로 우리는 어떤 조건을 충족하는 dict 요소 만 생성하기 위해 dict 이해 내에서 조건문을 사용할 수 있습니다.

Python 2.x 2.7
{name: len(name) for name in ('Stack', 'Overflow', 'Exchange') if len(name) > 6}  
# Out: {'Exchange': 8, 'Overflow': 8}

또는 생성자 표현식을 사용하여 다시 작성하십시오.

dict((name, len(name)) for name in ('Stack', 'Overflow', 'Exchange') if len(name) > 6)
# Out: {'Exchange': 8, 'Overflow': 8}

사전으로 시작하고 사전 및 독해를 키 - 값 쌍 필터로 사용

Python 2.x 2.7
initial_dict = {'x': 1, 'y': 2}
{key: value for key, value in initial_dict.items() if key == 'x'}
# Out: {'x': 1}

전환 키 및 사전 값 (사전 반전)

간단한 해시 가능 값을 포함하는 dict가있는 경우 (값이 중복 되면 예기치 않은 결과가 발생할 수 있음)

my_dict = {1: 'a', 2: 'b', 3: 'c'}

키와 값을 바꾸려면 코딩 스타일에 따라 여러 가지 방법을 사용할 수 있습니다.

  • swapped = {v: k for k, v in my_dict.items()}
  • swapped = dict((v, k) for k, v in my_dict.iteritems())
  • swapped = dict(zip(my_dict.values(), my_dict))
  • swapped = dict(zip(my_dict.values(), my_dict.keys()))
  • swapped = dict(map(reversed, my_dict.items()))
print(swapped)
# Out: {a: 1, b: 2, c: 3}
파이썬 2.x 2.3

사전이 큰 경우 itertools 가져 오기를 고려하고 izip 또는 imap 활용 izip .


병합 사전

사전을 결합하고 중첩 된 사전 이해로 이전 값을 선택적으로 대체 할 수 있습니다.

dict1 = {'w': 1, 'x': 1}
dict2 = {'x': 2, 'y': 2, 'z': 2}

{k: v for d in [dict1, dict2] for k, v in d.items()}
# Out: {'w': 1, 'x': 2, 'y': 2, 'z': 2}

그러나 사전 압축 풀기 ( PEP 448 )가 선호 될 수 있습니다.

Python 3.x 3.5
{**dict1, **dict2}
# Out: {'w': 1, 'x': 2, 'y': 2, 'z': 2}

참고 : 사전 보충 은 Python 3.0에서 추가되었으며 2.0에서 추가 된 목록 보급과 달리 2.7+로 다시 포트되었습니다. 버전 2.7은 발전기 표현식과 dict() 내장 함수를 사용하여 사전 보급의 동작을 시뮬레이션합니다.

생성자 표현식

생성자 표현식은 목록 내포와 매우 유사합니다. 가장 큰 차이점은 한 번에 전체 결과 집합을 생성하지 않는다는 것입니다. 생성자 객체 를 생성 한 다음 반복 할 수 있습니다.

예를 들어 다음 코드의 차이점을 참조하십시오.

# list comprehension
[x**2 for x in range(10)]
# Output: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Python 2.x 2.4
# generator comprehension
(x**2 for x in xrange(10))
# Output: <generator object <genexpr> at 0x11b4b7c80>

이것들은 매우 다른 두 가지 객체입니다.

  • 지능형리스트는 반환 list 발전기 이해가 반환하는 반면 개체를 generator .

  • generator 객체는 색인을 생성 할 수 없으며 순서대로 항목을 가져 오는 next 함수를 사용합니다.

참고 : xrange 는 생성기 객체도 생성하므로 xrange 사용합니다. 범위를 사용하면 목록이 만들어집니다. 또한 xrange 는 파이썬 2의 최신 버전에만 존재합니다. 파이썬 3에서는 range 가 생성자를 반환합니다. 자세한 내용 은 범위와 xrange 함수차이점 예제를 참조하십시오.


Python 2.x 2.4
g = (x**2 for x in xrange(10))
print(g[0])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'generator' object has no attribute '__getitem__'

g.next()  # 0
g.next()  # 1
g.next()  # 4
...
g.next()  # 81

g.next()  # Throws StopIteration Exception
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
Python 3.x 3.0

참고 : Iterator.next()xrange() 가 Python 3에는 존재하지 않으므로 g.next() 함수는 next(g) , xrangerange 로 대체해야합니다.


이 두 가지 방법은 비슷한 방식으로 반복 될 수 있습니다.

for i in [x**2 for x in range(10)]:
    print(i)

"""
Out:
0
1
4
...
81
"""
Python 2.x 2.4
for i in (x**2 for x in xrange(10)):
    print(i)

"""
Out:
0
1
4
.
.
.
81
"""

사용 사례

생성자 표현식은 느슨하게 평가됩니다. 즉, 생성자 표현식은 생성자가 반복 될 때만 각 값을 생성하고 반환합니다. 대용량 데이터 집합을 반복 할 때 메모리에 데이터 집합의 복사본을 만들지 않아도되는 경우에 유용합니다.

for square in (x**2 for x in range(1000000)):
    #do something

또 다른 일반적인 사용 사례는 그렇게하지 않으면 전체 iterable을 반복하지 않는 것입니다. 이 예제에서 항목은 get_objects() 반복 할 때마다 원격 API에서 검색됩니다. 수천 개의 객체가 존재할 수 있고, 하나씩 검색되어야하며, 패턴과 일치하는 객체가 있는지 알아야합니다. 생성자 표현식을 사용하여 패턴과 일치하는 객체를 만날 때.

def get_objects():
    """Gets objects from an API one by one"""
    while True:
        yield get_next_item()

def object_matches_pattern(obj):
    # perform potentially complex calculation
    return matches_pattern

def right_item_exists():
    items = (object_matched_pattern(each) for each in get_objects())
    for item in items:
        if item.is_the_right_one:


            return True
    return False

이해력 설정

집합 이해는 목록사전 이해 와 유사하지만, 고유 한 요소의 정렬되지 않은 집합 인 집합을 생성합니다.

Python 2.x 2.7
# A set containing every value in range(5):
{x for x in range(5)}
# Out: {0, 1, 2, 3, 4}

# A set of even numbers between 1 and 10:
{x for x in range(1, 11) if x % 2 == 0}
# Out: {2, 4, 6, 8, 10}

# Unique alphabetic characters in a string of text:
text = "When in the Course of human events it becomes necessary for one people..."
{ch.lower() for ch in text if ch.isalpha()}
# Out: set(['a', 'c', 'b', 'e', 'f', 'i', 'h', 'm', 'l', 'o',
#           'n', 'p', 's', 'r', 'u', 't', 'w', 'v', 'y'])

라이브 데모

세트에는 순서가 없습니다. 즉, 세트의 결과 순서가 위의 예와 다를 수 있습니다.

참고 : set comprehension은 2.0에 추가 된 list comprehensions와는 달리 Python 2.7+부터 사용 가능합니다. Python 2.2에서 Python 2.6으로 set() 함수를 생성자 표현식과 함께 사용하여 동일한 결과를 얻을 수 있습니다.

Python 2.x 2.2
set(x for x in range(5))
# Out: {0, 1, 2, 3, 4}

조건절을 사용하여 반복적이고 비싼 작업을 피하십시오.

아래 목록의 이해력을 고려하십시오.

>>> def f(x):
...     import time
...     time.sleep(.1)       # Simulate expensive function
...     return x**2

>>> [f(x) for x in range(1000) if f(x) > 10]
[16, 25, 36, ...]

결과적으로 값을 생성하기위한 하나의 호출과 if 조건을 검사하기위한 하나의 호출이 x 1,000 값에 대해 f(x) 를 두 번 호출합니다. f(x) 가 특히 비싼 연산 인 경우 성능에 상당한 영향을 줄 수 있습니다. 더 나쁜 것은 f() 호출이 부작용이있는 경우 놀라운 결과를 얻을 수 있다는 것입니다.

대신 다음과 같이 중간 반복 가능 ( 생성자 표현식 )을 생성하여 x 각 값에 대해 비싼 연산을 한 번만 평가해야합니다.

>>> [v for v in (f(x) for x in range(1000)) if v > 10]
[16, 25, 36, ...]

또는 내장 된지 도를 사용하여 다음을 수행하십시오.

>>> [v for v in map(f, range(1000)) if v > 10]
[16, 25, 36, ...]

좀 더 읽기 쉬운 코드를 만들 수있는 또 다른 방법은 부분 결과 (앞의 예제에서 v )를 반복 가능한 (예 : 목록 또는 튜플)에 넣은 다음 반복하는 것입니다. v 가 iterable의 유일한 요소이므로 결과는 한 번 계산 된 slow 함수의 출력에 대한 참조를 갖게됩니다.

>>> [v for x in range(1000) for v in [f(x)] if v > 10]
[16, 25, 36, ...]

그러나 실제로는 코드의 논리가 더 복잡 할 수 있으며 읽기 쉽도록 유지하는 것이 중요합니다. 일반적으로 복잡한 한 줄짜리 회로에 대해 별도의 생성기 기능 을 사용하는 것이 좋습니다.

>>> def process_prime_numbers(iterable):
...     for x in iterable:
...         if is_prime(x):
...             yield f(x)
...
>>> [x for x in process_prime_numbers(range(1000)) if x > 10]
[11, 13, 17, 19, ...]

컴퓨팅 방지하는 또 다른 방법은 f(x) 여러 번 사용하는 @functools.lru_cache() (파이썬 3.2 이상) 장식f(x) . 이 방법은 입력 x 대한 f 의 출력이 이미 한 번 계산 되었기 때문에 원본 목록 이해의 두 번째 함수 호출은 사전 조회만큼 빠릅니다. 이 접근법은 효율성을 향상시키기 위해 메모 생성을 사용하며 이는 생성자 표현식을 사용하는 것과 비슷합니다.


목록을 평평하게해야한다고 해봅시다.

l = [[1, 2, 3], [4, 5, 6], [7], [8, 9]]

방법 중 일부는 다음과 같습니다.

reduce(lambda x, y: x+y, l)

sum(l, [])

list(itertools.chain(*l))

그러나 목록 이해력은 최상의 시간 복잡성을 제공합니다.

[item for sublist in l for item in sublist]

+ L을 기반으로 한 바로 가기는 필요에 따라 L 개의 하위 목록이있을 때 O (L ^ 2)입니다. 중간 결과 목록이 길어지면 각 중간 단계에서 새로운 중간 결과 목록 개체가 가져옵니다. 할당되고, 이전 중간 결과의 모든 항목을 복사해야합니다 (끝에 추가 된 몇 가지 새로운 항목과 함께). 그래서 (단순함을 위해서 그리고 실제로는 일반성을 잃지 않고) 여러분은 각각 I 항목의 L 부분 목록을 가지고 있다고 말합니다. 처음 I 항목은 앞뒤로 L-1 번, 두 번째 I 항목은 L-2 번 등으로 복사됩니다. 총 복사 매수는 1에서 L까지 제외 된 x에 대한 x의 합계, 즉 I * (L ** 2) / 2입니다.

목록 이해력은 한 번만 한 목록을 생성하고 각 항목을 (원래 거주지에서 결과 목록으로) 정확히 한 번 복사합니다.

튜플을 포함한 이해력

list comprehensionfor 절은 둘 이상의 변수를 지정할 수 있습니다.

[x + y for x, y in [(1, 2), (3, 4), (5, 6)]]
# Out: [3, 7, 11]

[x + y for x, y in zip([1, 3, 5], [2, 4, 6])]
# Out: [3, 7, 11]

이것은 일반적인 for 루프와 같습니다.

for x, y in [(1,2), (3,4), (5,6)]:
    print(x+y)
# 3
# 7
# 11

단, 이해력을 시작하는 표현식이 튜플 인 경우 괄호로 묶어야합니다.

[x, y for x, y in [(1, 2), (3, 4), (5, 6)]]
# SyntaxError: invalid syntax

[(x, y) for x, y in [(1, 2), (3, 4), (5, 6)]]
# Out: [(1, 2), (3, 4), (5, 6)]

이해력을 사용하여 발생 횟수 계산

어떤 조건을 만족하는 반복 가능한 항목의 수를 세고 싶을 때, 우리는 관용적 인 구문을 만들기 위해 이해력을 사용할 수 있습니다 :

# Count the numbers in `range(1000)` that are even and contain the digit `9`:
print (sum(
    1 for x in range(1000) 
    if x % 2 == 0 and
    '9' in str(x)
))
# Out: 95

기본 개념은 다음과 같이 요약 할 수 있습니다.

  1. range(1000) 의 요소를 반복합니다.
  2. 필요한 모든 if 조건을 연결하십시오.
  3. 표현식 으로 1을 사용하여 조건을 충족하는 각 항목에 대해 1을 반환합니다.
  4. 조건을 충족시키는 항목의 수를 결정하기 위해 1 초를 합산하십시오.

참고 : 여기에 우리가 수집되지 않습니다 1 (대괄호가 없음을 유의) 목록에들하지만, 우리가 직접 사람을 전달하는 sum 를 합산되는 기능. 이를 생성기 표현 이라고하며 이는 이해력과 유사합니다.

목록에서 유형 변경하기

양적 데이터는 처리하기 전에 숫자 형식으로 변환해야하는 문자열로 읽는 경우가 많습니다. 모든 목록 항목의 유형은 List Comprehension 또는 map() 함수 를 사용하여 변환 할 수 있습니다.

# Convert a list of strings to integers.
items = ["1","2","3","4"]
[int(item) for item in items]
# Out: [1, 2, 3, 4]

# Convert a list of strings to float.
items = ["1","2","3","4"]
map(float, items)
# Out:[1.0, 2.0, 3.0, 4.0] 


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow