71104


初投稿ゆえ、拙い文章と汚いコードについてはご放念くださると幸いです  
以下の2つのクラスがあります(Python 3.6.9)  
二つのスタックを使って、キューを作成しようとしています

[code]

    class Stack:
      def __init__(self, data=[]):
        self.data = data
    
      def push(self, val):
        self.data.append(val)
      
      def pop(self):
        if self.is_empty():
          return None
        v = self.data.pop()
        return v
        
      def peek(self):
        return None if self.is_empty() else self.data[-1]
    
      def is_empty(self):
        return len(self.data)==0
    
[/code]

[code]

    class TwoStacksAsQueue:
      def __init__(self, capacity):
        self.new_stack = Stack()
        self.old_stack = Stack()
        self.capacity = capacity
    
      def add(self, val):
        if self.is_full(self.new_stack):
          raise Exception("No more capacity")
        self.new_stack.push(val)
    
      def remove(self) -> Union[int, None]:
        if self.old_stack.is_empty():
          if self.new_stack.is_empty():
            return None
          while self.new_stack.is_empty():
            p = self.new_stack.pop()
            self.old_stack.push(p)
        v = self.old_stack.pop()
        return v
    
      def peek(self) -> Union[int, None]:
        if self.old_stack.is_empty():
          if self.new_stack.is_empty():
            return None
          while self.new_stack.is_empty():
            p = self.new_stack.pop()
            self.old_stack.push(p)
        v = self.old_stack.peek()
        return v
    
[/code]

この状態で例えば以下のようなコードを実行すると、最後の`q.remove()`で返ってくる値は3であってほしいので対し、実際返ってくる値は5です。

[code]

    q = TwoStacksAsQueue()
    q.add(3)
    q.add(4)
    q.add(5)
    q.remove()
    
[/code]

デバッグをしたところ、`TwoStacksAsQueue`クラスの`add`メソッドで`self.new_stack.data`にのみ値を入れているはずが、`self.new_stack.data`と`self.old_stack.data`両方に値が入っていました

つまりスタックの`self.data`が別のインスタンスのはずなのにシェアされているのでは、と思ったのですが、それはなぜでしょうか？


CC BY-SA 4.0
2020-10-11T08:56:46.783
71098
2020-10-11T12:31:05.697
2020-10-11T12:31:05.697
42273
42273
question
python
Pythonのコードが意図した挙動になりません


関数またはメソッドの引数にデフォルトオブジェクトを指定する場合、関数またはメソッドの呼び出し毎に、関数定義時に評価されたデフォルトオブジェクトを引数に代入する動作となります。

[code]

    class Stack:
      def __init__(self, data=[]):
        self.data = data
    
[/code]

は

[code]

    class Stack:
      def __init__(self, data=None):
        if data is None:
            data = []
        self.data = data
    
[/code]

とすれば意図した動作になるでしょう。

なお、Stack クラスを実装するのであれば list を継承して

[code]

    class Stack(list):
        def push(self, v):
            self.append(v)
        def peek(self):
            return None if self.is_empty() else self[-1]
        def is_empty(self):
            return not self
    
[/code]

としてはいかがでしょう。


CC BY-SA 4.0
2020-10-11T11:32:54.013
71104
2020-10-11T11:32:54.013
41756
71098
answer