目次
リスト内包表記とジェネレーター式
ジェネレーター式の構造
生成器表达式中的条件
多个迭代对象
集合解析
字典解析
风险
1.代码变得难以阅读
2.它们不会替换循环
3.它们很难调试
ホームページ バックエンド開発 Python チュートリアル Python のリスト内包表記とジェネレーター式の構造は何ですか

Python のリスト内包表記とジェネレーター式の構造は何ですか

May 18, 2023 pm 02:58 PM
python

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

ジェネレーター式は、コンテナーを生成する簡潔な方法です。最も一般的には list 内包表記 と呼ばれますが、set 内包表記 dictionary 内包表記もあります。 ただし、用語の違いはある程度重要です。実際にリストを作成している場合、それは単に リストの理解にすぎません。

ジェネレータ式は括弧( )で囲まれ、リスト内包表記は角括弧で囲まれています[ ]解析の設定中括弧で囲みます{ }。これらの違いを除けば、構文は 3 つのケースすべてで同じです。

(辞書解析についてはさらに詳しく説明します。これについては後ほど説明します。)

ジェネレータ式は generators に関連しており、これについては後のセクションで詳しく説明します。話し合う。現時点では、ジェネレーター式の公式定義を使用するだけで十分です。

ジェネレーター式 - イテレーターを返す式。

ジェネレーター式の構造

ジェネレーター式 (またはリスト/セットの屋外グループ) は、反転された for ループに少し似ています。

簡単な例として、華氏温度のリストを摂氏に変換した前の記事の例を確認してみましょう。数値を直接印刷するのではなく、別のリストに保存するように少し調整します。

temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]
temps_c = []

def f_to_c(temp):
    return round((temp - 32) / 1.8, 1)

for c in map(f_to_c, temps_f):
    temps_c.append(c)

print(temps_c)
ログイン後にコピー

信じられないかもしれませんが、リスト内包表記を使用するとプログラム全体が 3 行に減ります。私の言いたいことがわかるように、一度に 1 つずつ簡略化してみましょう。

for ループをリスト内包表記に置き換えることから始めましょう...

temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]

def f_to_c(temp):
    return round((temp - 32) / 1.8, 1)

temps_c = [f_to_c(temp) for temp in temps_f]

print(temps_c)
ログイン後にコピー

コードの重要な行は temps_c = [f_to_c(temp) for temp in temps_f]. これは map() と非常によく似た動作をします。 tempリスト内の要素 temps_f ごとに、関数 f_to_c() を適用します。

さて、どこかで f_to_c() 関数が必要な場合は、ここで終了します。ただし、これが華氏から摂氏への変換ロジックが必要な唯一の場所である場合、この関数をまったく使用できず、ロジック コードを直接解析に移動することはできません。

temps_f = [67.0, 72.5, 71.3, 78.4, 62.1, 80.6]
temps_c = [round((temp-32) / 1.8, 1) for temp in temps_f]
print(temps_c)
ログイン後にコピー

何を言ったでしょうか? 3本ライン!たったの3行のコードではないでしょうか?

入手したデータに基づいて、さらに削減することもできます。これを別の例で見てみましょう。

5 4 1 9 5 7 5 のように、スペースで区切られた多数の整数を 1 行に受け取るプログラムがあると想像してください。これらすべての整数の合計を求めたいとします。 (わかりやすくするために、入力ミスの危険性がないと仮定します。)

まず、 リスト内包表記を使用せずに、わかりやすい方法で記述してみましょう。

user_input = input()
values = user_input.split(' ')

total = 0

for v in values:
    n = int(v)
    total += n

print(total)
ログイン後にコピー
当然ですよね?ユーザー入力を文字列として取得し、リストをスペースで分割して個々の数値を取得します。合計を保存する変数を作成し、ループを使用して各値を調べ、整数に変換して合計に加算します。コード ロジックが完成したので、それを簡素化して最適化しましょう。

まず、ここで明らかなコードを単純化してみましょう。これらの概念はすべて以前に説明したので、どこが改善されたか見つけてください。

values = input().split(' ')
total = 0

for v in values:
    total += int(v)

print(total)
ログイン後にコピー
リスト内包表記を使用しない限り、これより単純にすることはできません。それでは、今すぐ始めましょう。

values = input().split(' ')
total = sum(int(v) for v in values)
print(total)
ログイン後にコピー
ここでのジェネレーター式は

(int(v) for v invalues) です。 v はリスト values の各値に対応し、これを整数 ( int(v)) に変換します。

sum() 関数を使用して、ジェネレーター式を直接渡していることに注目してください。式は唯一の引数として直接渡されるため、余分な括弧は必要ありません。

これで、

values 他のリストが必要ない場合は、実際にそのロジックをジェネレーター式に直接移動できます。

total = sum(int(v) for v in input().split(' '))
print(total)
ログイン後にコピー
とても簡単ですよね?

ネストされたリストの解析

代わりに、入力された各数値の

二乗の合計が必要な場合はどうなるでしょうか。 実際には、これを行うには 2 つの方法があります。これを行う簡単な方法は次のとおりです。

total = sum(int(v)**int(v) for v in input().split(' '))
print(total)
ログイン後にコピー
これは機能しますが、どういうわけか正しく感じられません。

v を 2 回整数に変換したいと考えています。

我们可以通过将列表解析嵌套到我们的生成器表达式中来解决这个问题!

total = sum(n**2 for n in [int(v) for v in input().split(' ')])
ログイン後にコピー

列表解析和生成器表达式从内部外部进行解析。最里面的表达式 ,int(v) for v in input().split(' ')首先运行,并且封闭的方括号[ ]将其转换为列表(可迭代)。

接下来,n**2 for n in [LIST]运行外部表达式,[LIST]就是我们刚才生成的列表。

这种嵌套不是很容易理解,也不直观。尽量少用它。当我需要嵌套时,我将每个列表理解写在单独的行上并将其存储...

the_list = [int(v) for v in input().split(' ')]
total = sum(n**2 for n in the_list)
print(total)
ログイン後にコピー

...测试一下,然后通过复制和粘贴开始嵌套。

生成器表达式中的条件

如果我们只想要列表中奇数的总和怎么办?生成器表达式和列表解析也可以做到这一点。

我们将在此示例中使用嵌套,但我们将首先从非嵌套版本开始,为了使新逻辑更易于查看。

the_list = [int(v) for v in input().split(' ')]
total = sum(n**2 for n in the_list if n%2==0)
print(total)
ログイン後にコピー

新部分在第二行。在生成器表达式的末尾,我添加了if n%2==0. 你可能认识模运算符 ( %),它为我们提供了除法的余数。任何偶数都可以被2整除,这意味着它没有余数。因此,n%2==0仅适用于偶数

将条件放在语句之后而不是之前,感觉有点奇怪。理解它的最简单方法是和没有生成器表达式的相同代码逻辑做对比......

output = []
for n in the_list:
    if n%2==0:
        output.append(n**2)
ログイン後にコピー

基本上,要将其转换为生成器表达式,你只需知道append(),从这儿开始......

n**2
for n in the_list:
    if n%2==0:
ログイン後にコピー

然后从forif语句中删除冒号 ( :)、换行符缩进...

n**2 for n in the_list if n%2==0
ログイン後にコピー

多个迭代对象

我们还可以使用生成器表达式和列表解析一次循环遍历多个可迭代对象,其方式与嵌套循环相同。

考虑以下逻辑:

num_a = [1, 2, 3, 4, 5]
num_b = [6, 7, 8, 9, 10]
output = []

for a in num_a:
    for b in num_b:
        output.append(a*b)
ログイン後にコピー

我们也可以按照我刚才给出的相同步骤将其转换为列表解析!我们把append()的参数放在前面...

a*b
for a in num_a:
    for b in num_b:
ログイン後にコピー

...然后我们将其余部分折叠成一行,删除冒号。

a*b for a in num_a for b in num_b
ログイン後にコピー

最后,将其包裹在方括号中,并将其复制给变量output输出。

output = [a*b for a in num_a for b in num_b]
ログイン後にコピー

集合解析

正如我在文章开头提到的,就像你可以使用包含在方括号[ ]中的生成器表达式来创建列表一样,你也可以使用花括号{ }来创建集合

例如,让我们生成通过100 除以小于 100 的奇数得到的所有余数组成的集合。通过使用集合,我们确保没有重复项,使结果更容易理解。

odd_remainders = {100%n for n in range(1,100,2)}
print(odd_remainders)
ログイン後にコピー

运行该代码给我们...

{0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49}
ログイン後にコピー

这里真的没有什么特别的地方。集合解析的工作方式与列表解析相同,只是创建了不同的容器。

字典解析

字典解析遵循与其他形式的生成器表达式几乎相同的结构,但有一个区别:冒号

如果你还记得,当你创建集合字典时,你使用花括号{ }。唯一的区别是,在字典中,你使用冒号:来分隔键值对,这是在集合中不会执行的操作。同样的原则在这里也适用。

例如,如果我们想创建一个字典,将 1 到 100 之间的整数存储为键,并将该数字的平方作为值...

squares = {n : n**2 for n in range(1,101)}
print(squares)
ログイン後にコピー

这就是字典解析!除了冒号之外:,其他所有内容都与任何其他生成器表达式相同。

风险

对所有情况都使用列表解析或生成器表达式可能非常诱人。它们相当容易上瘾,部分原因是写出来时看起来非常高端优雅。强大的单行代码让程序员非常兴奋——我们真的很喜欢优雅地地处理我们的代码。

但是,我必须提醒你不要过分追求优雅。记住The Zend Of Python,这里有一些与此主题相关的部分:

美丽总比丑陋好。
...
简单胜于复杂。
复杂胜于复杂。
平面优于嵌套。
稀疏比密集好。
可读性很重要。
...

列表解析可能很优雅,但如果使用不当,它们也可能成为密集的、垃圾的逻辑片段。

1.代码变得难以阅读

我从互联网上的一项调查中借用了这个例子

primary = [ c for m in status['members'] if m['stateStr'] == 'PRIMARY' for c in rs_config['members'] if m['name'] == c['host'] ]
secondary = [ c for m in status['members'] if m['stateStr'] == 'SECONDARY' for c in rs_config['members'] if m['name'] == c['host'] ]
hidden = [ m for m in rs_config['members'] if m['hidden'] ]
ログイン後にコピー

你能说出这段代码的意思?如果你阅读一会,你可能可以,但你为什么要阅读?代码一清二楚。(在调查中,这被评为最不可读的示例。)当然,你可以添加注释来解释正在执行的逻辑 - 事实上,他们在原始示例中做了 - 但任何时候你需要注释来解释代码正在做什么,这几乎可以肯定太复杂了。

列表解析和生成器表达式固然很强大,但如果大量使用会像刚刚那样变得难以阅读。

不一定非得像刚刚那样做。只需将列表理解拆分为多行,你就可以重新获得很多可读性,其结构与传统循环类似。

primary = [
    c
    for m in status['members']
        if m['stateStr'] == 'PRIMARY'
    for c in rs_config['members']
        if m['name'] == c['host']
    ]

secondary = [
    c
    for m in status['members']
        if m['stateStr'] == 'SECONDARY'
    for c in rs_config['members']
        if m['name'] == c['host']
    ]

hidden = [
    m
    for m in rs_config['members']
        if m['hidden']
    ]
ログイン後にコピー

请注意,这并不能完全证明上述说法是正确的。我仍然会使用传统的循环而不是前面的示例,只是因为它们更易于阅读和维护。

如果你仍然不相信这是 Python 的一个容易被滥用的特性?我的有一个朋友分享他遇到的这个真实案例。我们根本不知道它做了什么。

cropids = [self.roidb[inds[i]]['chip_order'][
               self.crop_idx[inds[i]] % len(self.roidb[inds[i]]['chip_order'])] for i in
           range(cur_from, cur_to)]
ログイン後にコピー

光是看着,我的可能都会有点烦躁了。

2.它们不会替换循环

看看以下情况。(此代码是虚构的,仅供参考。)

some_list = getTheDataFromWhereever()
[API.download().process(foo) for foo in some_list]
ログイン後にコピー

对于未经训练的人来说,这看起来没啥问题,但请注意请仔细看砍......数据<strong>some_list</strong>正在被直接修改(变异),但结果没有被存储。这是列表解析甚至生成器表达式被滥用来代替循环的情况。它使阅读变得困难,更不用说调试了。

无论你想使用生成器表达式来变得优雅,这都是你应该坚持使用循环的一种情况:

some_list = getTheDataFromWhereever()
for foo in some_list:
    API.download().process(foo)
ログイン後にコピー

3.它们很难调试

想一想列表解析的本质:你将所有内容打包成一个巨大的语句。这样做的好处是你消除了一堆中间步骤。缺点也是……你消除了一堆中间步骤。

考虑调试一个典型的循环。你可以单步执行它,一次迭代,使用调试器随时观察每个变量的状态。你还可以使用错误处理来处理异常的边缘情况。

相比之下,这些都不适用于生成器表达式或列表解析。一切要么有效,要么无效!你可以尝试解析错误和输出以找出你做错了什么,但我可以向你保证,这是一种令人困惑的体验。

你可以通过避免在你的第一个代码版本中使用列表解析来避免这种疯狂!使用传统的循环和迭代器工具以显而易见的方式编写逻辑。一旦你知道它有效,那么并且只有在那时你才应该将逻辑折叠到生成器表达式中,并且只有在你可以这样做而不避免错误处理的情况下。

这听起来像是很多额外的工作,但我在平常的代码编写中中遵循了这个确切的模式。我对生成器表达式的理解通常是我对抗经验不足的竞争对手的主要优势,但我总是先编写标准循环:我不能把浪费时间在调试生成器表达式中错误逻辑上。

以上がPython のリスト内包表記とジェネレーター式の構造は何ですかの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

mysqlは支払う必要がありますか mysqlは支払う必要がありますか Apr 08, 2025 pm 05:36 PM

MySQLには、無料のコミュニティバージョンと有料エンタープライズバージョンがあります。コミュニティバージョンは無料で使用および変更できますが、サポートは制限されており、安定性要件が低く、技術的な能力が強いアプリケーションに適しています。 Enterprise Editionは、安定した信頼性の高い高性能データベースを必要とするアプリケーションに対する包括的な商業サポートを提供し、サポートの支払いを喜んでいます。バージョンを選択する際に考慮される要因には、アプリケーションの重要性、予算編成、技術スキルが含まれます。完璧なオプションはなく、最も適切なオプションのみであり、特定の状況に応じて慎重に選択する必要があります。

インストール後にMySQLの使用方法 インストール後にMySQLの使用方法 Apr 08, 2025 am 11:48 AM

この記事では、MySQLデータベースの操作を紹介します。まず、MySQLWorkBenchやコマンドラインクライアントなど、MySQLクライアントをインストールする必要があります。 1. mysql-uroot-pコマンドを使用してサーバーに接続し、ルートアカウントパスワードでログインします。 2。CreatedAtaBaseを使用してデータベースを作成し、データベースを選択します。 3. createTableを使用してテーブルを作成し、フィールドとデータ型を定義します。 4. INSERTINTOを使用してデータを挿入し、データをクエリし、更新することでデータを更新し、削除してデータを削除します。これらの手順を習得することによってのみ、一般的な問題に対処することを学び、データベースのパフォーマンスを最適化することでMySQLを効率的に使用できます。

MySQLはダウンロード後にインストールできません MySQLはダウンロード後にインストールできません Apr 08, 2025 am 11:24 AM

MySQLのインストール障害の主な理由は次のとおりです。1。許可の問題、管理者として実行するか、SUDOコマンドを使用する必要があります。 2。依存関係が欠落しており、関連する開発パッケージをインストールする必要があります。 3.ポート競合では、ポート3306を占めるプログラムを閉じるか、構成ファイルを変更する必要があります。 4.インストールパッケージが破損しているため、整合性をダウンロードして検証する必要があります。 5.環境変数は誤って構成されており、環境変数はオペレーティングシステムに従って正しく構成する必要があります。これらの問題を解決し、各ステップを慎重に確認して、MySQLを正常にインストールします。

MySQLダウンロードファイルが破損しており、インストールできません。修復ソリューション MySQLダウンロードファイルが破損しており、インストールできません。修復ソリューション Apr 08, 2025 am 11:21 AM

mysqlダウンロードファイルは破損していますが、どうすればよいですか?残念ながら、MySQLをダウンロードすると、ファイルの破損に遭遇できます。最近は本当に簡単ではありません!この記事では、誰もが迂回を避けることができるように、この問題を解決する方法について説明します。それを読んだ後、損傷したMySQLインストールパッケージを修復するだけでなく、将来の行き詰まりを避けるために、ダウンロードとインストールプロセスをより深く理解することもできます。最初に、ファイルのダウンロードが破損した理由について話しましょう。これには多くの理由があります。ネットワークの問題は犯人です。ダウンロードプロセスの中断とネットワーク内の不安定性は、ファイル腐敗につながる可能性があります。ダウンロードソース自体にも問題があります。サーバーファイル自体が壊れており、もちろんダウンロードすると壊れています。さらに、いくつかのウイルス対策ソフトウェアの過度の「情熱的な」スキャンもファイルの破損を引き起こす可能性があります。診断問題:ファイルが本当に破損しているかどうかを判断します

MySQLインストール後に開始できないサービスのソリューション MySQLインストール後に開始できないサービスのソリューション Apr 08, 2025 am 11:18 AM

MySQLは開始を拒否しましたか?パニックにならないでください、チェックしてみましょう!多くの友人は、MySQLのインストール後にサービスを開始できないことを発見し、彼らはとても不安でした!心配しないでください、この記事はあなたがそれを落ち着いて対処し、その背後にある首謀者を見つけるためにあなたを連れて行きます!それを読んだ後、あなたはこの問題を解決するだけでなく、MySQLサービスの理解と問題のトラブルシューティングのためのあなたのアイデアを改善し、より強力なデータベース管理者になることができます! MySQLサービスは開始に失敗し、単純な構成エラーから複雑なシステムの問題に至るまで、多くの理由があります。最も一般的な側面から始めましょう。基本知識:サービススタートアッププロセスMYSQLサービススタートアップの簡単な説明。簡単に言えば、オペレーティングシステムはMySQL関連のファイルをロードし、MySQLデーモンを起動します。これには構成が含まれます

MySQLインストール後にデータベースのパフォーマンスを最適化する方法 MySQLインストール後にデータベースのパフォーマンスを最適化する方法 Apr 08, 2025 am 11:36 AM

MySQLパフォーマンスの最適化は、インストール構成、インデックス作成、クエリの最適化、監視、チューニングの3つの側面から開始する必要があります。 1。インストール後、INNODB_BUFFER_POOL_SIZEパラメーターやclose query_cache_sizeなど、サーバーの構成に従ってmy.cnfファイルを調整する必要があります。 2。過度のインデックスを回避するための適切なインデックスを作成し、説明コマンドを使用して実行計画を分析するなど、クエリステートメントを最適化します。 3. MySQL独自の監視ツール(ShowProcessList、ShowStatus)を使用して、データベースの健康を監視し、定期的にデータベースをバックアップして整理します。これらの手順を継続的に最適化することによってのみ、MySQLデータベースのパフォーマンスを改善できます。

高負荷アプリケーションのMySQLパフォーマンスを最適化する方法は? 高負荷アプリケーションのMySQLパフォーマンスを最適化する方法は? Apr 08, 2025 pm 06:03 PM

MySQLデータベースパフォーマンス最適化ガイドリソース集約型アプリケーションでは、MySQLデータベースが重要な役割を果たし、大規模なトランザクションの管理を担当しています。ただし、アプリケーションのスケールが拡大すると、データベースパフォーマンスのボトルネックが制約になることがよくあります。この記事では、一連の効果的なMySQLパフォーマンス最適化戦略を検討して、アプリケーションが高負荷の下で効率的で応答性の高いままであることを保証します。実際のケースを組み合わせて、インデックス作成、クエリ最適化、データベース設計、キャッシュなどの詳細な主要なテクノロジーを説明します。 1.データベースアーキテクチャの設計と最適化されたデータベースアーキテクチャは、MySQLパフォーマンスの最適化の基礎です。いくつかのコア原則は次のとおりです。適切なデータ型を選択し、ニーズを満たす最小のデータ型を選択すると、ストレージスペースを節約するだけでなく、データ処理速度を向上させることもできます。

mysqlはインターネットが必要ですか? mysqlはインターネットが必要ですか? Apr 08, 2025 pm 02:18 PM

MySQLは、基本的なデータストレージと管理のためにネットワーク接続なしで実行できます。ただし、他のシステムとのやり取り、リモートアクセス、または複製やクラスタリングなどの高度な機能を使用するには、ネットワーク接続が必要です。さらに、セキュリティ対策(ファイアウォールなど)、パフォーマンスの最適化(適切なネットワーク接続を選択)、およびデータバックアップは、インターネットに接続するために重要です。

See all articles