Python は非常に多様で強力なプログラミング言語です。問題を解決する必要がある場合、さまざまなアプローチがあります。この記事では、リスト内包表記について説明します。使い方について話し合ってみましょう?いつ使用すべきでしょうか、それとも使用すべきではありませんか?
リスト内包表記は、既存のリストに基づいてリストを作成する構文構造です。リスト作成のさまざまな実装を見てみましょう
ループはリストを作成する従来の方法です。どのようなループを使用しても構いません。この方法でリストを作成するには、
numbers = [] for number in range(10): numbers.append(number) print(numbers)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
この例では、空の数値リストをインスタンス化します。次に、for ループを使用して range(10) を反復し、append() メソッドを使用してリストの末尾に各数値を追加します。
map() はリストを作成する別の方法です。 map() に関数と反復可能なオブジェクトを渡し、その後オブジェクトを作成する必要があります。このオブジェクトには、指定された関数を使用して各反復要素を実行することによって取得された出力が含まれます。
たとえば、特定の製品の価格に VAT を追加するというタスクが表示されます。
VAT_PERCENT = 0.1# 10% def add_vat(price): return price + (price * VAT_PERCENT) prices = [10.03, 8.6, 32.85, 41.5, 22.64] grand_prices = map(add_vat, prices) print(grand_prices) grand_prices = list(grand_prices) print(grand_prices)
add_vat() 関数を構築し、価格の反復可能オブジェクトを作成しました。両方の引数を map() に渡し、結果のマップ オブジェクト grand_prices を収集するか、 list() を使用してそれをリストに簡単に変換できます。
<map object at 0x7f18721e7400># map(add_vat, prices) [11.03, 9.46, 36.14, 45.65, 24.9]# list(grand_prices)
それでは、リスト内包表記の方法を見てみましょう。これは確かに Python 的であり、リストを作成するためのより良い方法です。このアプローチがどれほど強力であるかを確認するために、ループの例を 1 行のコードで書き直してみましょう。
numbers = [number for number in range(10)] print(numbers)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
ご覧のとおり、これは素晴らしい方法です。リスト内包表記は十分読みやすいので、1 行以上のコードを記述する必要はありません。
リストをよりよく理解するには、次の構文形式を参照してください。
new_list = [expression for member in iterable]
わかりました。ループ、map( の使用方法を学びました。 ) とリスト内包表記を使用してリストを作成すると、「どちらのアプローチがより効率的か」という疑問が浮かぶかもしれません。分析してみましょう!
import random import timeit VAT_PERCENT = 0.1 PRICES = [random.randrange(100) for x in range(100000)] def add_vat(price): return price + (price * VAT_PERCENT) def get_grand_prices_with_map(): return list(map(add_vat, PRICES)) def get_grand_prices_with_comprehension(): return [add_vat(price) for price in PRICES] def get_grand_prices_with_loop(): grand_prices = [] for price in PRICES: grand_prices.append(add_vat(price)) return grand_prices print(timeit.timeit(get_grand_prices_with_map, number=100)) print(timeit.timeit(add_grand_prices_with_comprehension, number=100)) print(timeit.timeit(get_grand_prices_with_loop, number=100))
0.9833468980004909# with_map 1.197223742999995 # with_comprehension 1.3564663889992516# with_loop
これまで見てきたように、リストを作成する最良の方法はmap()、2番目に良い方法はリストの内包表記、そして最後にループです。
ただし、方法の選択は、何を達成したいかによって異なります。
前に、次の式を示しました。
new_list = [expression for member in iterable]
この式は少し不完全かもしれません。分析式のより完全な説明により、オプションの条件のサポートが追加されました。リスト内包表記に条件ロジックを追加する最も一般的な方法は、式の最後に条件を追加することです。
new_list = [expression for member in iterable (if conditional)]
ここで、条件ステートメントは右括弧の中にあります。
条件は、リスト内包表記で不要な値を除外できるため重要です。これは、一般的な場合に filter() を呼び出して行うこともできます。
numbers = [number for number in range(20) if number % 2 == 0] print(numbers)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
ご覧のとおり、この分析式は2 で割り切れて余りのない数値を集めます。
より複雑なフィルターが必要な場合は、条件ロジックを別の関数に移動することもできます。
def is_prime(number): if number > 1: for el in range(2, int(number/2)+1): if (number % el) == 0: return False else: return True numbers = [number for number in range(20) if is_prime(number)] print(numbers)
[2, 3, 5, 7, 11, 13, 17, 19]
is_prime(number) を構築して、数値が素数かどうかを判断し、ブール値を返します。次に、分析式の条件に関数を追加する必要があります。
この式を使用すると、条件付きロジックを使用して、可能ないくつかの出力オプションから選択できます。たとえば、製品の価格リストがあるとします。負の数値がある場合は、それらを正の数値に変換する必要があります。
price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1] normalized_price_list = [price if price > 0 else price*-1 for price in price_list] print(normalized_price_list)
[1.34, 19.01, 4.2, 6, 8.78, 1,1]
ここで、式 Price には条件ステートメント if Price > 0 else Price* -1 が含まれています。これは、価格が正の場合は価格値を出力し、価格が負の場合は価格を正の値に変換するように Python に指示します。この機能は強力であり、条件付きロジックをそれ自体の関数として考えると非常に便利です。
def normalize_price(price): return price if price > 0 else price*-1 price_list = [1.34, 19.01, -4.2, 6, 8.78, -1,1] normalized_price_list = [normalize_price(price) for price in price_list] print(normalized_price_list)
[1.34, 19.01, 4.2, 6, 8.78, 1,1]
您还可以创建一个集合解析式!它基本与列表解析式相同。不同之处在于集合解析式不包含重复项。您可以通过使用花括号取代方括号来创建集合解析式:
string = "Excellent" unique_string = {letter for letter in string} print(unique_string)
{"E", "e", "n", "t", "x", "c", "l"}
你的集合解析式只包含唯一的字母。这与列表不同,集合不保证项目将以特定顺序存储数据。这就是为什么集合输出的第二个字母是 e,即使字符串中的第二个字母是 x。
字典解析式也是是类似的,但需要定义一个键:
string = "Words are but wind" word_order = {el: ind+1 for ind, el in enumerate(string.split())} print(word_order)
{"Words": 1, "are": 2, "but": 3, "wind": 4}
要创建 word_order 字典,请在表达式中使用花括号 ({}) 以及键值对 (el: ind+1)。
Python 3.8 中引入的海象运算符允许您一次解决两个问题:为变量赋值,返回该值。
假设您需要对将返回温度数据的 API 应用十次。您想要的只是 100 华氏度以上的结果。而每个请求可能都会返回不同的数据。在这种情况下,没有办法在 Python 中使用列表解析式来解决问题。可迭代成员(如果有条件)的公式表达式无法让条件将数据分配给表达式可以访问的变量。
海象运算符解决了这个问题。它允许您在执行表达式的同时将输出值分配给变量。以下示例显示了这是如何实现的,使用 get_weather_data() 生成伪天气数据:
import random def get_weather_data(): return random.randrange(90, 110) hot_temps = [temp for item in range(20) if (temp := get_weather_data()) >= 100] print(hot_temps)
[108, 100, 106, 103, 108, 106, 103, 104, 109, 106]
列表解析式非常有用,它可以帮助您编写清晰且易于阅读和调试的代码。但在某些情况下,它们可能会使您的代码运行速度变慢或使用更多内存。如果它让您的代码效率更低或更难理解,那么可以考虑选择另一种方式。
可以通过嵌套解析式以创建列表、字典和集合的组合集合(译者注:这个集合不是指 set 对象类型,而是 collection,泛指容器)。例如,假设一家公司正在跟踪一年中五个不同城市的收入。存储这些数据的完美数据结构可以是嵌套在字典解析式中的列表解析式。
cities = ['New York', 'Oklahoma', 'Toronto', 'Los Angeles', 'Miami'] budgets = {city: [0 for x in range(12)] for city in cities} print(budgets)
{ "NewYork": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Oklahoma": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Toronto": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "LosAngeles": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], "Miami": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] }
您使用字典解析式创建了 budgets 容器。该表达式是一个键值对,其中包含另一个解析式。此代码将快速生成城市中每个 city 的数据列表。
嵌套列表是创建矩阵的常用方法,通常用于数学目的。查看下面的代码块:
matrix = [[x for x in range(7)] for y in range(6)] print(matrix)
[ [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6], [0, 1, 2, 3, 4, 5, 6] ]
外部列表解析式 [... for y in range(6)] 创建了六行,而内部列表解析式 [x for x in range(7)] 将用值填充这些行中的每一行。
到目前为止,每个嵌套解析式的目标都是真正且直观的。但是,还有一些其他情况,例如创建扁平化的嵌套列表,其中的逻辑可以使您的代码非常难以阅读。让我们看下面的例子,使用嵌套列表解析式来展平一个矩阵:
matrix = [ [0, 1, 0], [1, 0, 1], [2, 1, 2], ] flat = [num for row in matrix for num in row] print(flat)
[0, 1, 0, 1, 0, 1, 2, 1, 2]
扁平化矩阵的代码确实很简洁,但是太难理解了,您应该花点时间弄清楚它是如何工作的。另一方面,如果您使用 for 循环来展平相同的矩阵,那么您的代码将更加简单易读:
matrix = [ [0, 1, 0], [1, 0, 1], [2, 1, 2], ] flat = [] for row in matrix: for num in row: flat.append(num) print(flat)
[0, 1, 0, 1, 0, 1, 2, 1, 2]
现在,您可以看到代码一次遍历矩阵的一行,在移动到下一行之前取出该行中的所有元素。
虽然嵌套列表解析式可能看起来更具有 Python 风格,但对于能够编写出您的团队可以轻松理解和修改的代码来才是更加最重要的。当选择一个方法时,您应该根据解析式是有助于还是有损于可读性来做出相应的判断。
Python 中的列表解析式通过将整个列表存储到内存中来工作。对于小型至中型列表这通常很好。如果您想将前一千个整数相加,那么列表解析式将轻松地解决此任务:
summary = sum([x for x in range(1000)]) print(summary)
499500
但是,如果您需要对十亿个数字求和呢?您可以尝试执行此操作,但您的计算机可能不会有响应。这是可能因为计算机中分配大量内存。也许您是因为计算机没有如此多的内存资源。
例如,你想要一些第一个十亿整数,那么让我们使用生成器!这可能多需要一些时间,但计算机应该可以克服它:
summary = sum((x for x in range(1000000000))) print(summary)
499999999500000000
让我们来对比一下哪种方法是更优的!
import timeit def get_sum_with_map(): return sum(map(lambda x: x, range(1000000000))) def get_sum_with_generator(): return sum((x for x in range(1000000000))) print(timeit.timeit(get_sum_with_map, number=100)) print(timeit.timeit(get_sum_with_generator, number=100))
4940.844053814# get_sum_with_map 3464.1995523349997# get_sum_with_generator
正如您所见,生成器比 map() 高效得多。
本文向您介绍了列表解析式,以及如何使用它来解决复杂的任务,而不会使您的代码变得过于困难。
これであなたは:
以上がPythonのリスト分析の使い方は?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。