Python 面接の質問
Pythonのインタビューでは、コア言語機能、データ構造、アルゴリズム、オブジェクト指向プログラミングに関する理解が試されます。知識の深さを測る概念的な質問と、実践的なスキルを評価するコーディング問題が出題されることがよくあります。ジュニアでもシニアでも、これらのトピックを習得することが成功の鍵です。
Python 面接で問われる内容
コア構文とデータ構造
リスト、辞書、セット、タプル、文字列操作などのPython組み込み型に関する質問。時間計算量も含みます。
オブジェクト指向プログラミング(OOP)
クラス、継承、ポリモーフィズム、__init__、__str__、プロパティデコレータなどの特殊メソッドをカバーします。
関数型プログラミングと内包表記
lambda、map、filter、reduce、リスト/辞書内包表記、ジェネレータ式を含みます。
並行性とパフォーマンス
GIL、スレッディング vs マルチプロセッシング、async/await、プロファイリングなどのトピック。
Python 面接の質問例
- Pythonの主な特徴は何ですか?良い回答が押さえる点
- 動的型付けとインタプリタ言語
- シンプルで読みやすい文法
- 豊富な標準ライブラリとサードパーティ製モジュール
- オブジェクト指向、関数型、手続き型など複数のパラダイムをサポート
- クロスプラットフォームで動作し、大規模コミュニティが存在
サンプル回答を見る
Pythonは動的型付けのインタプリタ言語であり、コードの記述がシンプルで可読性が高いことが最大の特徴です。豊富な標準ライブラリに加え、PyPIを通じて多数のサードパーティ製モジュールが利用可能なため、Web開発、データサイエンス、機械学習など幅広い分野で活用されています。オブジェクト指向はもちろん、関数型や手続き型など複数のプログラミングパラダイムをサポートしており、開発者は状況に応じて最適なスタイルを選択できます。また、Windows、macOS、Linuxなど主要なプラットフォームで動作し、グローバルな大規模コミュニティによるサポートが充実しています。一方で、動的型付けゆえに実行時エラーが発生しやすく、処理速度がC言語などに比べて遅いという欠点もあります。しかし、型ヒントやC拡張などでこれらの課題を緩和する手段も整っています。
- リストとタプルの違いを説明し、それぞれを使用する場面を教えてください。良い回答が押さえる点
- リストはミュータブル(変更可能)だがタプルはイミュータブル(変更不可)
- リストは多くの組み込みメソッドを持つが、タプルは少ない
- リストは同種のデータ集合に、タプルは異種データの固定セットに適する
- タプルは辞書のキーとして使用可能
サンプル回答を見る
リストとタプルの最も大きな違いはミュータビリティです。リストは要素の追加、削除、変更が可能ですが、タプルは生成後に要素を変更できません。このため、リストはappendやpopなどの多くのメソッドを持ち、動的なデータ操作に適しています。一方、タプルはメソッドが少なく、イミュータブルであることが保証されるため、関数の戻り値として複数の値を返す場合や、データが変更されないようにしたい場合に使用します。また、タプルはハッシュ可能であり、辞書のキーや集合の要素として利用できますが、リストはできません。一般的には、同種の要素を扱う動的コレクションにはリストを、異種の要素を固定の順序で保持する場合にはタプルを選択します。メモリ使用量もタプルの方がわずかに少なく、処理速度も若干速いことが多いです。
- Pythonはメモリをどのように管理しますか?ガベージコレクションと参照カウントについて説明してください。良い回答が押さえる点
- Pythonは参照カウントとガベージコレクションの両方でメモリを管理
- 参照カウントは各オブジェクトが持つ参照数をカウントし、0になると即座にメモリ解放
- 循環参照は参照カウントでは解放できず、ガベージコレクタが検出して解放
- ガベージコレクタは世代別アプローチを採用し、パフォーマンスを最適化
サンプル回答を見る
Pythonのメモリ管理は主に参照カウントとガベージコレクション(GC)の二つの仕組みで成り立っています。参照カウントは各オブジェクトが保持する参照の数を数え、その値が0になった瞬間にオブジェクトを即座に解放します。これにより、不要になったメモリは速やかに回収されます。しかし、参照カウントだけでは循環参照(例:お互いを参照し合うオブジェクト)を検出できません。そこで、PythonのGCは定期的に循環参照を検出し、到達不可能なオブジェクトを解放します。GCは世代別アルゴリズムを採用しており、新しく生成されたオブジェクト(若い世代)を優先的にチェックすることで、パフォーマンスを向上させています。開発者はこれらのメカニズムを意識せずにメモリ管理が行えますが、大量のオブジェクトを扱う場合やリアルタイム性が求められる場合は、GCの影響を考慮する必要があります。なお、gcモジュールを使ってGCの動作を細かく制御することも可能です。
- ソートを使用せずに、リスト内の2番目に大きい数値を見つける関数を書いてください。良い回答が押さえる点
- ソートを使わずに線形スキャンで解く
- 最大値と2番目の最大値を追跡する
- リストが2要素未満の場合はエラーを考慮
- 重複する最大値がある場合の扱いに注意
サンプル回答を見る
この問題は、リストを一度だけ走査し、最大値と2番目の最大値を保持することでO(n)時間で解けます。初期化として、最大値と2番目の最大値をNoneまたは最小値に設定し、各要素を比較しながら更新します。要素が現在の最大値より大きければ、2番目を旧最大値に、最大値を新要素に更新します。要素が最大値より小さく、2番目より大きければ、2番目を更新します。これにより、ソートによる追加コスト(O(n log n))を避けられます。注意点として、リストの長さが2未満の場合や、全ての要素が同じ値の場合、2番目が存在しないためエラー処理が必要です。また、重複値がある場合、2番目の値が最大値と等しくならないように条件を設定します。以下に実装例を示します。
参考コードpython def second_largest(nums): """ リストから2番目に大きい数値を返す。 要素数が2未満の場合はNoneを返す。 """ if len(nums) < 2: return None # 初期化:最大値と2番目の最大値を非常に小さい値に設定 first = second = float('-inf') for num in nums: if num > first: second = first first = num elif num > second and num != first: second = num # もしsecondが初期値のままなら、2番目が存在しない(すべて同じ値など) if second == float('-inf'): return None return second # 使用例 print(second_largest([3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5])) # 出力: 6 - 関数の実行時間を測定するデコレータを実装してください。良い回答が押さえる点
- デコレータは関数を引数に取り、その機能を拡張する高階関数
- functools.wrapsを使って元の関数のメタデータを保持
- timeモジュールで実行時間を計測し、結果を表示またはログ出力
- デコレータは関数定義の直前に@記法で適用
サンプル回答を見る
実行時間を測定するデコレータは、呼び出しの前後にタイムスタンプを取得し、その差を計算することで実現します。デコレータ自体は、ラップする関数(target)を受け取り、ラッパー関数を返します。ラッパー関数では、targetを呼び出す前後の時刻をtime.time()またはtime.perf_counter()で記録し、実行時間を出力します。functools.wrapsを使用することで、元の関数の名前やdocstringなどのメタデータがラッパーにコピーされ、デバッグやドキュメンテーションが容易になります。このデコレータは、関数定義の直前に@timerと記述するだけで適用できます。以下に実装例を示します。
参考コードpython import time import functools def timer(func): """実行時間を計測するデコレータ""" @functools.wraps(func) def wrapper(*args, **kwargs): start = time.perf_counter() # 開始時刻 result = func(*args, **kwargs) end = time.perf_counter() # 終了時刻 print(f'{func.__name__} took {end - start:.6f} seconds') return result return wrapper # 使用例 @timer def slow_function(): time.sleep(2) return "Done" slow_function() # 出力例: slow_function took 2.000123 seconds - GILとは何ですか?マルチスレッディングにどのような影響を与えますか?良い回答が押さえる点
- GIL(Global Interpreter Lock)はPythonインタプリタが持つロック
- 一度に1つのスレッドしかバイトコードを実行できないようにする
- CPUバウンドな処理ではマルチスレッドの恩恵が得られないが、I/Oバウンドでは有効
- マルチプロセスや非同期処理(asyncio)が代替手段として存在
サンプル回答を見る
GIL(Global Interpreter Lock)は、CPythonインタプリタがメモリ管理におけるスレッド安全性を保証するために採用している排他ロックです。このロックにより、マルチスレッド環境でも一度に1つのスレッドしかPythonバイトコードを実行できません。その結果、CPUバウンドな処理(計算集約型)では、複数スレッドを使っても並列処理が行われず、むしろオーバーヘッドが増加してシングルスレッドよりも遅くなる可能性があります。一方、I/Oバウンドな処理(ファイル読み書きやネットワーク通信など)では、スレッドがI/O待ちの間に他のスレッドが実行できるため、マルチスレッドによる効率化が期待できます。GILの影響を回避するには、マルチプロセス(multiprocessingモジュール)を使用してプロセスごとに独立したインタプリタを動かす方法や、asyncioによる非同期I/Oを用いる方法が一般的です。また、C拡張やJython、IronPythonなどGILのないインタプリタを選択するという選択肢もあります。
- nまでのフィボナッチ数列を生成するジェネレータを書いてください。良い回答が押さえる点
- ジェネレータはyield文を使って値を逐次生成
- メモリ効率が良く、無限シーケンスも表現可能
- フィボナッチ数列の各項をyieldで返す
- nまでの項を生成し、呼び出し側でforループなどで消費
サンプル回答を見る
フィボナッチ数列を生成するジェネレータは、初期値としてa=0, b=1を設定し、aをyieldしながらa,bをb, a+bで更新することで実現できます。nが指定された場合、その数まで生成するにはループ内で項数をカウントするか、無限ジェネレータにしてスライスで制限する方法があります。ジェネレータを使用することで、必要な値を逐次的に生成できるため、メモリ消費が少なく、大きなnでも効率的です。以下にnまでのフィボナッチ数列を生成するジェネレータの実装例を示します。
参考コードpython def fibonacci(n): """ nまでのフィボナッチ数列を生成するジェネレータ """ a, b = 0, 1 count = 0 while count < n: yield a a, b = b, a + b count += 1 # 使用例: 最初の10項を出力 for num in fibonacci(10): print(num, end=' ') # 出力: 0 1 1 2 3 5 8 13 21 34 - PythonのMRO(メソッド解決順序)とsuper()の動作について説明してください。良い回答が押さえる点
- MROはクラスのメソッド探索順序を定義する
- C3線形化アルゴリズムを用いて決定される
- super()はMROに従って次のクラスを委譲する
- 多重継承において協調的なメソッド呼び出しを実現
サンプル回答を見る
PythonのMRO(Method Resolution Order)は、クラスの継承ツリーにおけるメソッド探索の順序を定義したものです。これはC3線形化アルゴリズムによって計算され、すべてのクラスは単一の線形順序を持ちます。具体的には、子クラスを優先し、親クラスの継承順序を保ちつつ、共通の祖先は一度だけ現れるようにします。super()関数は、このMROに従って「次の」クラスを委譲します。つまり、super()で親クラスのメソッドを呼び出すと、単純な親ではなく、MRO上の次のクラスに委譲されます。これにより、多重継承時にもすべての関連クラスのメソッドが適切に呼び出される「協調的なメソッド呼び出し」が可能になります。例えば、ダイヤモンド継承の場合、super()を使うことで各クラスが一度ずつ呼ばれるように設計できます。一方、super()を使用せずに親クラスを明示すると、一部のクラスが複数回呼ばれたり、順序が乱れたりする可能性があります。したがって、多重継承を扱う際にはsuper()の利用が推奨されます。
準備方法
- 組み込み関数と標準ライブラリ(例:itertools、collections)をマスターしましょう。
- LeetCodeやHackerRankなどのプラットフォームで、Python固有のソリューションに焦点を当てたコーディング問題を練習しましょう。
- Pythonのメモリモデルとオブジェクトの受け渡し(参照 vs 値)を理解しましょう。
- デザインパターンやPythonらしいイディオム(コンテキストマネージャー、デコレータなど)を説明できるようにしましょう。
- 重要なデータ構造(辞書、セット)とその時間計算量を復習しましょう。
よくある質問
`==` と `is` の違いは何ですか?
`==` は値の等価性をチェックします。`is` は同一性(同じオブジェクト)をチェックします。`None` のようなシングルトンには `is` を使用してください。
Pythonで例外を処理するにはどうすればよいですか?
try/except ブロックを使用します。必要に応じて else や finally を追加して後処理を行います。むき出しの except は避けてください。
Pythonの名前空間とスコープルールは何ですか?
LEGBルール:ローカル、エンクロージング、グローバル、ビルトイン。変数はこの順序で検索されます。
ジェネレータとは何ですか?リストとはどのように異なりますか?
ジェネレータはyieldを使って遅延的にアイテムを生成します。すべての値をメモリに保存しないため、大きなデータに適しています。
Pythonコードのパフォーマンスを最適化するにはどうすればよいですか?
組み込み関数(map、filterなど)、リスト内包表記を使用し、グローバルルックアップを避け、プロファイリングツールを使用し、C拡張を検討してください。
Python の質問をAIで練習、瞬時にフィードバック
履歴書をアップロードして、パーソナライズされた模擬面接を受け、改善点を確認 — 無料で始められます。