裏 RjpWiki

Julia ときどき R, Python によるコンピュータプログラム,コンピュータ・サイエンス,統計学

リスト内包表記はどうなのよ

2020年12月17日 | ブログラミング

リスト内包表記を推奨する記事があった。

しかし,取り上げている例が不適切なこともあり,ひいきの引き倒しになっているんじゃないかと思った。

まあ,人それぞれだから,「リスト内包表記がいいに決まってるじゃないか!」というのに,反対はしない。

その 1

full_name = "Yang Zhou"

に対して,

characters = [char for char in full_name]
# ['Y', 'a', 'n', 'g', ' ', 'Z', 'h', 'o', 'u']

full_name = "Yang Zhou"
characters = []
for char in full_name:
    characters.append(char)

より「Pythoらしく洗練されたプログラムへの第一歩

なるほど。この場合に限っては

list(full_name)

で十分と思いますが。(文字列の分解以外であっても,リスト内包表記以外の解があることもあるでしょう)。

その 2

Matrix = [[2, 1, 5],
          [5, 99, 0],
          [33, 2, 4]]
row_max = [max(row) for row in Matrix]
print(row_max)
# [5, 99, 33]

max 関数だからよかったけど,mean や std を使おうとすると,使用法を類推して使おうとしても,以下のようなものは全部だめ。(リストを対象にするから)

[mean(row) for row in Matrix]
[row.mean() for row in Matrix]

例が不味すぎるというか,以下のように numpy の array を使うとよい。応用範囲の幅が拡がる。統計計算プログラムのときなんかは特に。

import numpy as np
m = np.array(Matrix)
print(m.max(axis=1))
print(m.mean(axis=0))
print(m.std(axis=1))

その 3

> Pythonにはmap()やfilter()などの高階関数があります。高階関数の代わりにリスト内包表記をいつも使う習慣をつけると良いでしょう。
> 他の人がプログラムを読みやすくなるからです。

> map()は常に置き換えられます。

> L = map(func, iterable)
> # can be replaced to:
> L = [func(a) for a in iterable]

> filter()も置き換えられます。

> L = filter(condition_func, iterable)
> # can be converted to
> L = [a for a in iterable if condition]

「他の人」が高階関数を知らないプログラム初心者というならそうでしょう。
そうでなければ,そうでないでしょう。
高階関数を使っていると,何をしているか,すぐにわかります
リスト内包表記は いちいち読まないといけない。

あと,二重ループのリスト内包表記を「わかりやすい」と書いてあったのには驚いた。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

numpy.ndarray をもっと使おう

2020年12月17日 | ブログラミング

リストは,数値計算には全く不向きだ

>>> a = [3, 1, 2, 5, 4]
>>> print(2 * a)
[3, 1, 2, 5, 4, 3, 1, 2, 5, 4]

こんな機能,必要か?
まあ,確かに,定数で初期化した所与の長さのリストを作るときには便利かも知れないが。

>>> b = [0] * 10
>>> print(b)
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

>>> c = [1, 3, 2, 5, 1]
>>> print(a + c)
[3, 1, 2, 5, 4, 1, 3, 2, 5, 1]

print(a - c) # これはないんだ
print(a * c) # これはないんだ
print(a / c) # 当然,これもない

リストで数値計算をやろうとすると必然的に for や リスト内包表記に依存してしまう。


リストではなく,numpy の配列は使い所が広い。

>>> import numpy as np

>>> y = np.array([3, 1, 2, 5, 4])
>>> print(2 * y)
[ 6  2  4 10  8]

>>> z = np.array([5, 3, 2, 1, 4])
>>> print(y + z)
[8 4 4 6 8]

>>> print(np.outer(y, z))
[[15  9  6  3 12]
 [ 5  3  2  1  4]
 [10  6  4  2  8]
 [25 15 10  5 20]
 [20 12  8  4 16]]

>>> print(np.sqrt(z))
[2.23606798 1.73205081 1.41421356 1.         2.        ]

>>> print(z.mean())
3.0

>>> print(np.mean(z))
3.0

リストでなくても,append だってできるし

>>> np.append(z, 100)
array([  5,   3,   2,   1,   4, 100])

insert もできるし

>>> np.insert(z, 2, 200)
array([  5,   3, 200,   2,   1,   4])

delete もできる

>>> np.delete(z, 3)
array([5, 3, 2, 4])

たぶん,その他の所でも,リストでやれることは numpy.ndarray でほとんど全部やれる

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

奇数リストの生成

2020年12月17日 | ブログラミング

3 から n までの奇数を要素とするリストを作りたいらしい

data = [i + 1 for i in range(2, n, 2)]

なぜ,素直に

data = [i for i in range(3, n, 2)]

としないのかわからないし,そもそも

data = list(range(3, n, 2))

で十分なのに。「リスト内包表記」というカッコイイモノを使いたかったのかなあ?

 

そのあとにある,

data = [j for j in data if j % data[0] != 0]

というのもなんだかなあ

 

結局なにがやりたいかというと「n までの素数リストを得たい」と。

手を抜いて sympy を使おうというのはいいのだけど,

from sympy import sieve
print([i for i in sieve.primerange(1,100)])これもいただけない。(sympy.sieve.primerange  のオンラインヘルプにこの記述があるんだけど使用例を示すには,こんな書き方を示すのがよいのか?)
print(list(sieve.primerange(1, 100)))
だけでよいのだ。
リスト内包表記って,そんなにいいものか??

リスト内包表記以外に簡単に書く方法があれば,そのように書けばよいと思うぞ。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

自作パッケージの探索径路(サーチパスともいう)の設定法

2020年12月17日 | Python

環境変数にサーチパスを付け加える例としては,先頭に付け加える例が説明されることが多いようにみえる。

もう一つの方法,import sys; sys.path.append("foo") では,当然ながら末尾に付け加える例が説明されることが多いようにみえる。

当然ながら,後者を前者と同じにするためには,import sys; sys.path.insert(0, "foo") としなければならない。

 

というのに,しばしはまってしまって,まったりとした時間をすごしてしまった。

 

結論としては,自作パッケージにより,既存の何らかのものが覆い隠されてしまわないように,サーチパスの末端に append するほうがよいだろうということ。

自作パッケージより前に探索されてしまうものがあるなら,自作パッケージの名前を変えましょう。それが無難というもの。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

PVアクセスランキング にほんブログ村

PVアクセスランキング にほんブログ村