Python-リスト内包表記とジェネレータ

リスト内包

フォーマット:

list1 = [条件が満たされる必要がある場合に、元のリスト内の元のリストの要素の要素を生成する式]

使用する:

次のコードは例です。list0のすべての偶数要素の2乗が最終的なlist1に格納されていることがわかります。
その操作のプロセスは、list0から要素の変数iを1つずつ取り出し、iが2で割り切れるかどうかを判断し、割り切れる場合は、初期式i * iを実行してから、この要素を配置します。新しいリスト
では、リスト内包表記は古いリストから新しいリストを導出することであると見なすことができます。

list0 = [2, 5, 6, 7, 4]
list1 = [i * i for i in list0 if i % 2 == 0]
print(list1)
'''
输出:
[4, 36, 16]
'''

リスト内包表記には他にも多くの用途があります。次にいくつかの例を示し
ます。三項演算子を使用する

list0 = [2, 5, 6, 7, 4]
list1 = [i * i if i % 2 else -i for i in list0]
print(list1)
'''
输出:
[-2, 25, -6, 49, -4]
'''
# 这里Py的非零整数就是True,零就是False

文字列要素を操作する

list0 = ['abc', 'ccc', 'here', 'cute']
list1 = [i * 5 for i in list0 if len(i) > 3]
print(list1)
'''
输出:
['hereherehereherehere', 'cutecutecutecutecute']
'''

リスト要素をフィルタリングする

list0 = ['abc', 'ccc', 3, 'here', 'cute', 5, True, False]
list1 = [i for i in list0 if isinstance(i, str)]
print(list1)
'''
输出:
['abc', 'ccc', 'here', 'cute']
'''

辞書要素を操作する

list0 = [{
    
    'key': 10}, {
    
    'key': 34}, {
    
    'key': 66}]
list1 = [i for i in list0 if i['key'] <= 10]
print(list1)
'''
输出:
[{'key': 10}]
'''

ループネスティング

list1 = [(i, j) for i in range(5) if i % 2 for j in range(5) if j % 2 == 0]
print(list1)
'''
输出:
[(1, 0), (1, 2), (1, 4), (3, 0), (3, 2), (3, 4)]
'''

リストの理解は、リストを1つずつトラバースして新しいリストを追加するよりも高速です。

リスト内包表記

実際、重複を削除する必要があることを除けば、リスト内包表記と同じです。

set1 = {
    
    i % 2 for i in range(10)}
print(set1)
''''
输出:
{0, 1}
''''
辞書の理解

リスト内包表記と同じですが、キーに応じて上書きされ、生成された値が最初に生成された値に置き換わります

dict0 = {
    
    'aaa': 233, 'bbb': 332, 'ddd': 555}
dict1 = {
    
    key: value + 5 for key, value in dict0.items()}
print(dict1)
'''
输出:
{'aaa': 238, 'bbb': 337, 'ddd': 560}
'''

キーと値を逆にすると
、逆にした後に重複するキーがある場合、値が置き換えられることがわかります。

dict0 = {
    
    'aaa': 233, 'bbb': 233, 'ddd': 555}
dict1 = {
    
    value: key for key, value in dict0.items()}
print(dict1)
'''
输出:
{233: 'bbb', 555: 'ddd'}
'''

ビルダー

ジェネレータ式

上記のリスト内包表記の記号が括弧に置き換えられた場合、新しく生成されたジェネレーターはジェネレーターです。
次のコードからわかるように、リストはリストではなく、ジェネレーターオブジェクトです。もちろん、強制することもできます。リストに変換されます

list1 = (i * i for i in range(6))
print(list1)
'''
输出:
<generator object <genexpr> at 0x0000013E4C03F5C8>
'''

この時点で、要素を取得する場合は、次のメソッドを使用する必要があります

generator = (i * i for i in range(6))
print(generator.__next__()) # 使用自带的__next__()方法来返回下一个元素
print(generator.__next__())
'''
输出:
0
1
'''
generator = (i * i for i in range(6))
print(next(generator))# 使用系统自带的next函数
print(next(generator))
print(next(generator))
'''
输出:
0
1
4
'''

nextの2つのタイプは、毎回次の要素のみを返し、要素をスキップしたり、任意のポイントから戻ったりすることはできず、ジェネレーターは反復可能なタイプであることに注意してください。
トラバーサルジェネレータ

generator = (i * i for i in range(6))
for i in generator:
    print(i)
'''
输出:
0
1
4
9
16
25
'''

マップマッピングを使用する

generator = (i * i for i in range(6))
print(list(map(lambda x: x * x, generator)))
'''
输出:
[0, 1, 16, 81, 256, 625]
'''
ジェネレーター機能

式を使用すると、単純な式しか作成できません。もう少し複雑な場合は、関数を使用する必要があります。

イールドキーワード

次のコードから、yieldキーワードが関数に追加された後、関数がジェネレーターになることがわかります。

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += n
        yield cnt


print(generator(5))
'''
输出:
<generator object generator at 0x0000024845B154C8>
'''

次のコードからプログラムの一般的なプロセスを知ることができます(プロセスを再度確認するには、デバッグすることをお勧めします)

  1. geはジェネレータオブジェクトのアドレスを取得しましたが、ジェネレータ内のコードを実行しませんでした
  2. 最初の次を実行し、内部コードの実行を開始し、最初に最も外側の初期化cntを実行し、次にループに入ります。yieldキーワードが実行されるまで、cntはその時点で取得された値として返され、ジェネレーターの内部実行は停止します。
  3. 次に2番目を実行すると、「yield」を出力した後、最後にyieldが終了した後に2番目の実行が実行されることがわかります。
def generator(n: int):
    cnt = 1
    print("进入生成器")
    while cnt < n:
        cnt += 1
        print("yield之前")
        yield cnt
        print("yield后")


ge = generator(5)
print("得到生成器----开始获取元素", end='\n\n\n')
print(ge.__next__())
print("第一个元素获取完毕", end='\n\n\n')
print(ge.__next__())
print("第二个元素获取完毕", end='\n\n\n')
'''
输出:
得到生成器----开始获取元素


进入生成器
yield之前
2
第一个元素获取完毕


yield后
yield之前
3
第二个元素获取完毕

'''

イールド後の変数は値として返され、イールドに遭遇した後、ジェネレーター内のコードは次のコードが呼び出されるまで実行を停止すると結論付けられます。別の例を挙げてください。

def generator(n: int):
    cnt = 1
    print("进入生成器")
    cnt += 1
    yield cnt
    yield 23333


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
'''
输出:
进入生成器
2
23333
'''

イールドは特別なリターンと考えることができますが、現在のイテレータは実行後に終了しません。実際、イールドは戻り値なしで使用できるため、イールドを一時停止ツールとして使用できます。

関数発生器とリターン

次のコードを実行すると例外が発生します。これは、現在のジェネレーターが生成できる要素は2つだけですが、次に3つ実行したためです。

def generator(n: int):
    cnt = 1
    cnt += 1
    yield cnt
    yield 23333


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
print(ge.__next__())
'''
輸出:
2
23333
Traceback (most recent call last):
  File "D:\Pycharm\Project\Pytest\test.py", line 11, in <module>
    print(ge.__next__())
StopIteration
'''

ここにリターンを追加すると、リターンの値が異常なメッセージとして出力されていることがわかります。

def generator(n: int):
    cnt = 1
    cnt += 1
    yield cnt
    yield 23333
    return "生成器结束"


ge = generator(5)
print(ge.__next__())
print(ge.__next__())
print(ge.__next__())
'''
输出:
Traceback (most recent call last):
2
  File "D:\Pycharm\Project\Pytest\test.py", line 12, in <module>
23333
    print(ge.__next__())
StopIteration: 生成器结束
'''
sendメソッド

ジェネレーターでsendメソッドを使用すると、ジェネレーターに値を渡し、ジェネレーターの戻り要素を取得して、ジェネレーターが外部と通信できるようにすることができます。

sendを使用するときに送信される情報は、yieldの値と同等であるため、変数を使用してyieldの値を受け取ります。

sendを最初に使用するときにのみNoneを渡すことができることに注意してください。そうしないと、エラーが報告されます。
理由は非常に単純です。上記のジェネレーターの実行プロセスを分析すると、ジェネレーターが最初に実行されたとき、yieldが実行されたときに実行が終了する、つまり、yieldの機会がないことがわかります。値を受け取るため、値はエラーとして報告されます。
理解プロセスをデバッグすることをお勧めします

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.send(1005))
'''
输出:
Traceback (most recent call last):
  File "D:\Pycharm\Project\Pytest\test.py", line 10, in <module>
    print(ge.send(1005))
TypeError: can't send non-None value to a just-started generator
'''

正しく使用する:

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.send(None))
print(ge.send(1005))
print(ge.send(1005))
'''
输出:
2
1005
3
1005
4
'''

あなたもすることができます:

def generator(n: int):
    cnt = 1
    while cnt < n:
        cnt += 1
        message = yield cnt
        print(message)


ge = generator(5)
print(ge.__next__())
print(ge.send(1005))
print(ge.send(1005))
'''
输出:
2
1005
3
1005
4
'''

つまり、sendを使用してNone以外のメッセージを送信する前に、yieldを1回実行する必要があります。

おすすめ

転載: blog.csdn.net/qq_36102055/article/details/107425854