Функции ...
Рассмотрим следующую группу функций:
def stack_push(stack, value):
stack.append(value)
def stack_is_empty(stack):
return len(stack) == 0
def stack_pop(stack):
return stack.pop()
Вместе они реализуют стек в виде встроенного списка. Пока вы не взаимодействуете со списком напрямую, они разрешают использовать только only , добавляя значения к одному концу, удаляя значения с того же конца и проверяя, пустой ли стек:
>>> s = []
>>> stack_push(s, 3)
>>> stack_push(s, 5)
>>> stack_push(s, 10)
>>> if not stack_is_empty(s): stack_pop(s)
10
>>> if not stack_is_empty(s): stack_pop(s)
5
>>> if not stack_is_empty(s): stack_pop(s)
3
>>> if not stack_is_empty(s): stack_pop(s)
>>>
... против методов
Обратите внимание, что каждая функция принимает один и тот же аргумент: список обрабатывается как стек. Это указывает на то, что вместо этого мы можем написать class the, представляющий стек, так что нам не нужно поддерживать list
, который потенциально может (неправильно) использоваться вне этих трех функций. Это также гарантирует, что мы начнем с пустого списка для нашего нового стека.
class Stack:
def __init__(self):
self.data = []
def push(self, value):
self.data.append(value)
def is_empty(self):
return len(self.data) == 0
def pop(self):
return self.data.pop()
Теперь мы не работаем с list
, который поддерживает все виды операций, не связанных со стеком, таких как индексация, итерация, и мутация в начале или в середине списка: мы можем только pu sh, щелкнуть и проверить пустоту.
>>> s = Stack()
Такие вещи, как s[3]
, s.insert(2, 9)
, et c не допускаются.
(Обратите внимание, что нам строго не запрещается использовать s.data
напрямую, но это считается плохой практикой, если только класс не скажет, что это нормально в документация. В этом случае мы не допускаем это.)
Мы используем эти методы так же, как мы использовали функции stack_*
.
>>> s.push(3)
>>> s.push(5)
>>> s.push(10)
>>> if not s.is_empty(): s.pop()
10
>>> if not s.is_empty(): s.pop()
5
>>> if not s.is_empty(): s.pop()
3
>>> if not s.is_empty(): s.pop()
>>>
Разница в том, что мы не можем «случайно» использовать другие методы списка, потому что Stack
не предоставляет их.
>>> s.insert(3, 9)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Stack' object has no attribute 'insert'
Наконец, обратите внимание, что мы не пишем наши оригинальные функции stack_*
и используйте их в определении класса Stack
: в этом нет необходимости; мы просто определяем методы явно внутри оператора class
.
# No.
class Stack:
def push(self, value):
stack_push(self.data, value)
Мы также не продолжаем использовать функции stack_*
в экземпляре Stack
.
# No no no!
>>> stack_is_empty(s.data)