web-dev-qa-db-ja.com

Cのループの複雑さPython

ちょうど今、私はスタックオーバーフローに関するPythonの質問を読んでいました。結果のリスト/配列を特定の範囲内に収めることについての質問です。

より簡単な答えの1つは、次のようなものを提案しました:

_clamped_list = [ max(64, min(128, i)) for i in source_list ]
_

この種のリスト/配列構築ループは「The Pythonic Way」として支持されています。回答がこの同じアルゴリズムをループ本体の一連のステップとして実装する場合、「Pythonicではない」という提案があり、おそらく反対票が投じられます。

しかし、C/C++ for()ループが同様に構築された場合〜

_for (i=0; i<MAX_ELEMENTS; clamped[i] = iMAX( 64, iMIN( 128, source[i] ) ), i+=1 );
_

それは決してどんな種類のコードレビューもパスしません(少なくとも私がこれまでに参加したことはありません)。

この複雑な「Pythonic Way」の歴史は何ですかPythonが発明されるずっと以前から、他の言語で不快だった何かがイディオマティックPythonでの方法?

2
Kingsley

Cには言語の一部としてのリストはなく、リストの内包表記もありません。そのため、インデックスを使用して配列/ベクトルを操作するか、明示的に割り当てまたは宣言する必要があるため、セクション全体が少し不格好になります。

しかし、非常に同じステートメントを並べ替えると、Cの例で次のようなループ本体に表示されます

for (i=0; i<MAX_ELEMENTS; i++) 
{
   clamped[i] = iMAX( 64, iMIN( 128, source[i] ));
}

(単一のステートメントであっても、ループのないループ本体が嫌いな人のためにブラケットを追加します)、これがコードレビューに合格できなかった理由はわかりません。

ただし、Pythonステートメントは上記のCコードよりも多くのことを行うことに注意してください。clamped_listsource_listと同じサイズのリストとして宣言します。同等のコードでは、CとPythonの違いがより明白になります。

int i;
int clamped[MAX_ELEMENTS];
for (i=0; i<MAX_ELEMENTS; i++) 
{
   clamped[i] = iMAX( 64, iMIN( 128, source[i] ));
}

したがって、Cコードがより冗長である理由(ここではcomplex、実際の複雑度は同じです)は、

  • Cには組み込みのリストやリストの内包がないため、明示的なインデックス付け/反復が必要です
  • Cでは変数と配列の明示的な宣言が必要
  • 多くのCプログラマーは、ワンライナーでもブラケットを好みます。

この例には相乗効果もあることに注意してください。Pythonコードは非常に少ない「ノイズ」コードを必要とするため、リスト内包表記のある「最小/最大」ステートメントを1行に入れるだけでも、 Cでは、反復を記述したコードを1行に配置し、最小/最大演算を1行に配置する方がおそらく良いでしょう。両方を1行にまとめると理解しにくくなるためです。

さらに、C++ 14以降では、Pythonの場合とほとんど同じように「高密度」のコードを記述できます。コメントから@Calethの例を引用すると、最近のC++ではこのようにコードを書くことができます

  auto clamped_view = source | transformed([](auto i){ return max(64, min(128, i)); });

Python行と同じくらい読みやすい場合は、確かに好みの問題であり、どのコードに慣れているかの問題です。

7
Doc Brown

最終的には、視点の問題になります。

pythonの例で使用しているものである)リスト内包表記は、ループを配列構文内に置くことにより、ループから配列を生成するという考えに取り組みます。

これがCで可能であれば、次のようになります。

// clamped_list = [ max(64, min(128, i)) for i in source_list ]
int clamped_list[16] = { max(64, min(128, source_list[i])) for (i=0,i<16,i++) };

16の固定長とintの型を想定しています。

代わりに、Cは古い言語であり、ループが外側にあり、要素を配列に明示的に配置するという、より命令的な方法で物事を行います。

これに対処する別の非常に一般的な(そして私の個人的なお気に入り????)方法は、map関数などの関数の概念です。ここで、(擬似コード)のようなものを記述します

clamped_list = map( source_list, (element) -> max(min(element, 128), 64) )

最終的に3つすべてが同じことを行いますが、ドメインや以前に使用されたプログラミング言語の経験などの多くの要因に基づいて、プログラマが異なれば理解しやすさも異なります。

ここで取り上げるべき重要なことは、常に慣用的なコードを書くことです。 Cでpythonコードを記述しようとすると、C-Style python code。

3
DarkWiiPlayer