ホームページ  >  記事  >  バックエンド開発  >  Python の面接での質問の詳細な概要 (回答付き)

Python の面接での質問の詳細な概要 (回答付き)

不言
不言転載
2019-02-23 13:15:367536ブラウズ

Python の面接での質問の詳細な概要 (回答付き)

この記事は、Python の面接での質問 (回答付き) をまとめたものです。一定の参考価値があります。困っている友人は参考にしてください。お役に立てれば幸いです。助けてくれた。

# おすすめ関連記事:「2020年Python面接の質問まとめ(最新)

##1.次のコードの出力は何でしょうか?説明してください。
def extendList(val, list=[]):
    list.append(val)
    return list
list1 = extendList(10)
list2 = extendList(123,[])
list3 = extendList('a')
print "list1 = %s" % list1
print "list2 = %s" % list2
print "list3 = %s" % list3

extendList の定義を変更して次の予想される動作を生成するにはどうすればよいですか?

上記のコードの出力結果は次のようになります:

list1 = [10, 'a']
list2 = [123]
list3 = [10, 'a']

多くの人は次のように誤解します。 list1=[10]、list3=['a'] は、extendList が呼び出されるたびに list パラメータのデフォルト値が [] に設定されると考えたためですが、実際の状況では、新しいデフォルトのリストは関数が定義された時点で使用され、一度作成されます。

特定のパラメーター リストを指定せずに extendList を呼び出すと、このリストのセットの値が以降使用されます。これは、デフォルト パラメーターを持つ式が関数の呼び出し時ではなく定義時に評価されるためです。したがって、list1 と list3 は、同じデフォルトのリストに基づいて操作 (計算) されます。そして list2 は別のリストに対して演算 (計算) します。 (リスト引数の値として独自の空のリストを渡すことによって)。

extendList の定義は次のように変更できます。

ただし、特定のリスト パラメーターを持たない新しいリストが作成されます。

次のコードにより、望ましい結果が得られる可能性があります。

def extendList(val, list=None):
  if list is None:
    list = []
  list.append(val)
  return list

上記の変更により、出力結果は次のようになります:

list1 = [10]
list2 = [123]
list3 = ['a']

2. 次のコードの出力結果はどうなるでしょうか?説明してください。

def multipliers():
  return [lambda x : i * x for i in range(4)]
print [m(2) for m in multipliers()]

望ましい結果を得るには、上記の乗算器の定義をどのように変更しますか?

上記のコードによって出力される結果は [6, 6, 6, 6] です (思ったような [0, 2, 4, 6] ではありません)。

上記の問題は、Python クロージャのバインディングの遅延が原因で発生します。これは、内部関数が呼び出されるときに、引数の値がクロージャ内で検索されることを意味します。したがって、multipliers() によって返された関数が呼び出されるとき、i の値は近くの範囲で検索されます。その時点で、返された関数が呼び出されたかどうかに関係なく、for ループが完了し、i に最終値 3 が割り当てられます。

したがって、前のコードで渡された値は 2 であるため、返される関数には毎回渡された値 3 が乗算され、最終的には 6 (3*2) が返されます。偶然ですが、『The Hitchhiker’s Guide to Python』でもラムダ関数に関して広く誤解されている知識があると指摘されていますが、今回の場合とは異なります。ラムダ式で作成した関数は特別なことはなく、実際にはdefで作成した関数と同じです。

この問題を解決する方法をいくつか紹介します。

解決策の 1 つは、Python ジェネレーターを使用することです。

def multipliers():
  for i in range(4): yield lambda x : i * x

もう 1 つの解決策は、クロージャを作成し、デフォルト関数を使用してすぐにバインドすることです。

def multipliers():
  return [lambda x, i=i : i * x for i in range(4)]

別の方法は、部分関数を使用することです:

from functools import partial
from operator import mul
def multipliers():
  return [partial(mul, i) for i in range(4)]

3. 次のコードの出力はどうなりますか?説明してください。

class Parent(object):
    x = 1
class Child1(Parent):
    pass
class Child2(Parent):
    pass
print Parent.x, Child1.x, Child2.x
Child1.x = 2
print Parent.x, Child1.x, Child2.x
Parent.x = 3
print Parent.x, Child1.x, Child2.x

出力結果は次のようになります:

1 1 1
1 2 1
3 2 3

多くの人を混乱させたり、驚かせたりするのは、なぜ出力の最後の行が 3 2 1 ではなく 3 2 3 なのかということです。なぜ親も変更されるのかということです。 x を同時に? child2.x の値を変更しました?しかし、同時に Child1.x の値は変更されませんか?

この答えの鍵は、Python ではクラス変数が辞書として内部的に渡されるということです。

変数名が現在のクラスの辞書に見つからない場合。次に、参照された変数名が見つかるまで、上位レベルのクラス (その親クラスなど) を徹底的に検索します。 (参照変数名が自身のクラスや上位クラスに見つからない場合は属性エラーが発生します。)

したがって、親クラスに x = 1 を設定し、変数 x をクラスにします。 (値 1 の場合) そのクラスおよびそのサブクラスで参照できます。これが、最初の print ステートメントの出力が 1 1 1

である理由です。したがって、そのサブクラスのいずれかが値で上書きされると (たとえば、ステートメント Child1.x = 2 を実行するとき)、この値はサブクラス内でのみ変更されます。これが、2 番目の print ステートメントの出力が 1 2 1

になる理由です。最後に、この値が親クラスで変更されると (たとえば、ステートメント Parent.x = 3 を実行するとき)、この変更は行われます。サブクラス (この例では Child2) によってオーバーライドされていない値に影響します。これが、3 番目の print ステートメントの出力結果が 3 2 3

4 になる理由です。次のコードは、 Python2での結果はどうなるでしょうか?説明してください。

def div1(x,y):
    print "%s/%s = %s" % (x, y, x/y)
def div2(x,y):
    print "%s//%s = %s" % (x, y, x//y)
div1(5,2)
div1(5.,2)
div2(5,2)
div2(5.,2.)

Python3 では結果はどう変わりますか? (もちろん、上記の print ステートメントが Python3 の構文に変換されていることを前提としています)

Python2 では、上記のコードの出力は次のようになります

5/2 = 2
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

デフォルトでは、Python 2 は自動的に整数計算を実行します。両方が整数の場合。したがって、5/2 の結果は 2 になり、5./2 の結果は 2.5

Python 2 では、次の参照を追加することでこの動作をオーバーライドできることに注意してください。

今後のインポート除算から


また、 // 演算子は、演算子の種類に関係なく、常に整数の除算を実行することに注意してください。 Python 2 でも 5.0//2.0 の結果が 2.0 になるのはそのためです。ただし、Python3 にはそのような機能はありません。

例如,在两端都是整形的情况下,它不会执行整形除法

因此,在Python3中,将会是如下结果:

5/2 = 2.5
5.0/2 = 2.5
5//2 = 2
5.0//2.0 = 2.0

注: 在 Python 3 中,/ 操作符是做浮点除法,而 // 是做整除(即商没有余数,比如 10 // 3 其结果就为 3,余数会被截除掉,而 (-7) // 3 的结果却是 -3。这个算法与其它很多编程语言不一样,需要注意,它们的整除运算会向0的方向取值。而在 Python 2 中,/ 就是整除,即和 Python 3 中的 // 操作符一样)

5、下面代码的输出结果将是什么?

list = ['a', 'b', 'c', 'd', 'e']
print list[10:]

下面的代码将输出[],不会产生IndexError错误。就像所期望的那样,尝试用超出成员的个数的index来获取某个列表的成员。

例如,尝试获取list[10]和之后的成员,会导致IndexError.

然而,尝试获取列表的切片,开始的index超过了成员个数不会产生IndexError,而是仅仅返回一个空列表。

这成为特别让人恶心的疑难杂症,因为运行的时候没有错误产生,导致bug很难被追踪到。

6、考虑下列代码片段:

list = [ [ ] ] * 5
list  # output?
list[0].append(10)
list  # output?
list[1].append(20)
list  # output?
list.append(30)
list  # output?

2,4,6,8行将输出什么结果?试解释。

输出的结果如下:

[[], [], [], [], []]
[[10], [10], [10], [10], [10]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]
[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30]

解释如下:

第一行的输出结果直觉上很容易理解,例如 list = [ [ ] ] * 5 就是简单的创造了5个空列表。然而,理解表达式list=[ [ ] ] * 5的关键一点是它不是创造一个包含五个独立列表的列表,而是它是一个创建了包含对同一个列表五次引用的列表。只有了解了这一点,我们才能更好的理解接下来的输出结果。

list[0].append(10) 将10附加在第一个列表上。

但由于所有5个列表是引用的同一个列表,所以这个结果将是:

[[10], [10], [10], [10], [10]]

同理,list[1].append(20)将20附加在第二个列表上。但同样由于5个列表是引用的同一个列表,所以输出结果现在是:

[[10, 20], [10, 20], [10, 20], [10, 20], [10, 20]]

作为对比, list.append(30)是将整个新的元素附加在外列表上,因此产生的结果是: [[10, 20], [10, 20], [10, 20], [10, 20], [10, 20], 30].

7、Given a list of N numbers。

给定一个含有N个数字的列表。

使用单一的列表生成式来产生一个新的列表,该列表只包含满足以下条件的值:

(a)偶数值

(b)元素为原始列表中偶数切片。

例如,如果list[2]包含的值是偶数。那么这个值应该被包含在新的列表当中。因为这个数字同时在原始列表的偶数序列(2为偶数)上。然而,如果list[3]包含一个偶数,

那个数字不应该被包含在新的列表当中,因为它在原始列表的奇数序列上。

对此问题的简单解决方法如下:

[x for x in list[::2] if x%2 == 0]

例如,给定列表如下:

list = [ 1 , 3 , 5 , 8 , 10 , 13 , 18 , 36 , 78 ]

列表生成式[x for x in list[::2] if x%2 == 0] 的结果是,

[10, 18, 78]

这个表达式工作的步骤是,第一步取出偶数切片的数字,

第二步剔除其中所有奇数。

8、给定以下字典的子类,下面的代码能够运行么?为什么?

class DefaultDict(dict):
  def __missing__(self, key):
    return []d = DefaultDict()
d['florp'] = 127

能够运行。

当key缺失时,执行DefaultDict类,字典的实例将自动实例化这个数列。

相关学习推荐:python视频教程

以上がPython の面接での質問の詳細な概要 (回答付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事は公众号:马哥Linux运维で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。