競争の結果。 パート2:バックダー

こんにちは、habrozhiteli!

トピックを継続して、この投稿では、バックエンド開発者向けの競争の結果を要約し、一般的な間違いと問題の良い解決策について話します。

競争は、Pythonおよび関連技術の知識をテストする8つの課題で構成されていました。



質問1.並列計算を編成する方法は何ですか、各方法の長所と短所は何ですか?

計算の分離方法が存在することについての全論文を受け取りましたが、実際、これは驚くことではありません。問題は現代世界に非常に関連しています。 この質問への回答では、2つの主な方法を述べるだけで十分でした。


質問2.アルゴリズムの複雑さを評価し、改善のためのオプションを提案する

def uniq(iterable): result = [] for i in interable: if i not in result: result.append(i) return result 


実際、ほとんどの回答者は複雑さの計算に誤りを犯しました。
  if i not in result: 

結果はリストであるため、この操作の複雑さはO(n)です。nは結果の長さです。 そして、反復可能オブジェクトに対する各反復の結果の長さは、1からnまで異なります。 算術級数があります。つまり、複雑度はO(n ^ 2)になります。

改善するには、データ構造を変更する必要があります。 挿入時のセットタイプには、O(1)複雑性とO(1)内部検索の複雑性もあります(より興味深い場合は、 一時的な複雑性についてお読みください)。

次のように書き換えることができます。
 def uniq(iterable): result = set() for i in interable: if i not in result: result.append(i) return list(result) 
複雑さは線形になります。

しかし、クーラー:
 def uniq(iterable): result = list(set(iterable)) 


質問3.違いは何ですか、なぜですか。

 r = range(3) a = r * 2 print a # [0, 1, 2, 0, 1, 2] a[0] = 1 print a # [1, 1, 2, 0, 1, 2] a = [r] * 2 print a # [[0, 1, 2], [0, 1, 2]] a[0][0] = 1 print a # [[1, 1, 2], [1, 1, 2]] 


実際、この質問はどの参加者にとっても難しいことではありませんでした。 しかし、好奇心の強い読者のために、説明します。

リストに適用される乗算演算子の詳細は次のとおりです。浅いコピーを使用してリストを繰り返します。

つまり、式を書き換えることができます。
 a = z + z # a = r * 2 """    ,        """ a = [z] + [z] # a = [z] * 2 """      """ 

これにより、質問で説明されている効果が作成されます。

質問4.座標とプリミティブ操作を格納するための独自のクラスPointを思いつきました

次のようになります。
 class Point(): def __init__(self): self.a = None self.b = None self.c = None ... 


次に、このクラスの多数のインスタンスで動作するプログラムが大量のメモリを消費することを発見しました。 100万個のこのようなオブジェクトには少なくとも360mbが必要です。 何がそんなに多くのメモリを消費し、どのように状況を改善できますか?

この質問は、参加者に最大のトラブルをもたらしました。 最も正しい方法は、すべてのフィールドの名前をリストする必要がある__slots__プロパティを使用することです。これにより、オブジェクトのサイズが大幅に削減されます。

 class Point(object): __slots__=('a', 'b', 'c') def __init__(self): self.a = None self.b = None self.c = None 


別の解決策もあります。Pointクラスをタプルに置き換えます。

質問5.何が起こっていますか? 誰のせいですか? どうする

 def add1Cent(sum): return sum + 0.01 s = 0 for i in range(5): s = add1Cent(s) """ now I have 5 cents! """ print s == 0.05 # True """ ok, lets add another five! """ for i in range(5): s = add1Cent(s) """ now I have 10! """ print s == 0.1 # False print s > 0.1 # False print s < 0.1 # True 

この質問は非常に単純であり、誰も間違いを犯していません。

実際、フロートの値はIEEE 754形式で保存され、エラーが含まれています。 通貨を使用するには、Decimal型を使用することをお勧めします。これが不可能な場合は、float用の独自の比較関数を作成します。

質問6.ジェネレーターを使用して次のコードを書き換えます

 file = open('somefile.csv') total = 0 for line in file: csv_list = line.split(',') if csv_list[5]: total += int(csv_list[5]) print ": ", total 

結果のコードの利点は何ですか? 欠点は何ですか?

このタスクで問題は発生しませんでした。 このコードを書き換える方法は数百ありますが、次のようなものを待っていました。
 total = sum(int(line.split(',')[5]) for line in open('somefile.csv') if line.split(',')[5]) 

長所:小さなコード。
短所:判読不能、パフォーマンスが30%低下。

質問7. 「fyva」と「u'fyva」の違いは何ですか? どこで、なぜそれが重要ですか?

テスト対象のほとんどは、この問題について歯を折っています。 トピックは非常に重要なので、これは驚くべきことです。

 '' #   -. 

Pythonのすべての文字列はデフォルトでASCIIでエンコードされます(文字列に非ASCII文字が含まれている場合、コンパイルが問題を引き起こす理由です)。 この動作は、ファイルヘッダーでエンコードを宣言し、最初の行に「#coding = utf-8」などと記述することで変更できます。すべての行はUTF-8でエンコードされていると認識されます。

 u'' #    unicode. 

Unicodeエンコードされた文字列。 このエンコードは、既存のすべての言語と文字をサポートします。 このようなエンコードを使用してデータを処理することの利点は明らかです。 たとえば、多言語アプリケーションの場合。

一部のpython関数は、文字列をデフォルトのエンコードに変換します(print()など)。

これらのデータ型の違いを十分に理解しないと、cvsおよびxmlライブラリを操作することは不可能です。

質問8.クラスAのコンストラクターがコンストラクターBで開始されるようにコードを書き換える方法

 class A: def __init__(self): print "init in A" class B(A): def __init__(self): print "init in B" b = B() # init in B 

絶対多数派がこの質問に対処しました。 クールな答えには、新しいスタイルオブジェクトと古いスタイルの2つの例が含まれていることに注意してください。

最高のバックエンダー

今日、Maxim Avanovのゴーストライターが私たちを訪ねてきて、私たちは彼にオフィスのツアーを提供し、チームメンバーに紹介しました。 マキシムはチェボクサルイ市から早ければ14時間で電車で私たちのところへ行きました。彼は言ったように、彼は外国市場で宣伝したいコンピューターゲームに関するメディアリソースを作っています。

マキシムアヴァノフ、ゴーストライター

Ostrovokとスタートアップに関するマキシム:
ビジネスを真剣に受け止めることの重要性を理解している人がいるのは素晴らしいことです。
スタートアップのファッションと投資家のお金の追求は、どういうわけか不健康です。
あなたが愛していること、あなたが信じていることをする必要があります。


参加したすべての人に感謝します!


チームOstrovok.ru

PS:次の投稿はアナリストについてです。
PPS:ところで、 Python開発者には空きがあります!

Source: https://habr.com/ru/post/J124701/


All Articles