I apologise if I seem stupid here, but I am stumped... as stated I need to have this program that evaluates infix notation expressions using stacks, but I cannot for the life of me get this thing to work out appropriately.
If anyone could help me fix my code and possibly explain where I went wrong then I would be very appreciative. Also, sorry for the wonky formatting, this is my first post and I don't fully understand the code input format.
import operator
def Main():
#In main, necessary stacks are generated and
#all calculations and methods are called and preformed.
opStack = ArrayStack()
numStack = ArrayStack()
opList = ['*', '/', '+', '-']
nums = '1234567890'
parn = ['(', ')']
toEval = input('Enter the Expression: ')
toEval = toEval.split()
#print(toEval)
for each in toEval:
if each in nums:
numStack.push(each)
if each == parn[0]:
opStack.push(each)
if each in opList:
if each == opList[2] or opList[3]:
opStack.push(each)
if each == opList[0] or opList[1]:
while opStack.top() == (opList[2] or opList[3]) and len(opStack) > 0 and len(numStack) >= 2:
ans = Eval(numStack.pop(),numStack.pop(),opStack.pop())
numStack.push(ans)
opStack.push(each)
if each == parn[1]:
while opStack.top() != "(":
ans = Eval(numStack.pop(),numStack.pop(),opStack.pop()) # this line is poping the empty stack
numStack.push(ans)
opStack.pop()
while opStack.is_empty() != True:
ans = Eval(numStack.pop(),numStack.pop(),opStack.pop())
numStack.push(ans)
print(ans)
def Eval(num1, num2, op):
#two numbers and an op are pulled from stacks, op checked against dict
#dict should supply necessary
ops2 = {"+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.truediv}
op_char = op
op_func = ops2[op_char]
res = op_func(float(num1), float(num2))
return res
class ArrayStack:
# LIFO Stack implementation using a Python list as underlying storage.
def __init__(self):
# Create an empty stack.
self._data = [] # nonpublic list instance
def __len__(self):
# Return the number of elements in the stack.
return len(self._data)
def is_empty(self):
# Return True if the stack is empty.
return len(self._data) == 0
def push(self, e):
# Add element e to the top of the stack.
self._data.append(e) # new item stored at end of list
def top(self):
# Return (but do not remove) the element at the top of the stack.
# Raise Empty exception if the stack is empty.
if self.is_empty():
raise Empty( 'Stack is empty' )
return self._data[-1] # the last item in the list
def pop(self):
#Remove and return the element from the top of the stack (i.e., LIFO).
#Raise Empty exception if the stack is empty.
if self.is_empty():
raise Empty( 'Stack is empty' )
return self._data.pop() # remove last item from list
Main()
These two if statements are always true:
if each == opList[2] or opList[3]:
if each == opList[0] or opList[1]:
You want something more like this:
if each == opList[2] or each == opList[3]:
And so on.
There may be other problems but that one certainly will keep your program from working.
Related
I am trying to build a max stack in python, I am not sure what I am doing wrong.
Here is the question>
Design a max stack data structure that supports the stack operations
and supports finding the stack's maximum element.
Implement the MaxStack class:
MaxStack() Initializes the stack object.
void push(int x) Pushes element x onto the stack.
int pop() Removes the element on top of the stack and returns it.
int top() Gets the element on the top of the stack without removing it.
int peekMax() Retrieves the maximum element in the stack without removing it.
int popMax() Retrieves the maximum element in the stack and removes it.
If there is more than one maximum element, only remove the top-most one.
class MaxStack:
def __init__(self):
self.stack = []
self.stack_max = []
def push(self, x: int) -> None:
self.stack.append(x)
if not self.stack_max or x > self.stack_max[-1][0]:
self.stack_max.append([x, 1])
elif x == self.stack_max[-1][0]:
self.stack_max[-1][1] += 1
else:
self.stack_max.append(self.stack_max[-1])
def pop(self) -> int:
if not self.stack_max or self.stack:
return
if self.stack_max[-1][0] == self.stack[-1]:
self.stack_max[-1][1] -= 1
if self.stack_max[-1][1] == 0:
del self.stack_max[-1]
return self.stack.pop()
def top(self) -> int:
return self.stack[-1]
def peekMax(self) -> int:
if self.stack_max:
return self.stack_max[-1][0]
def popMax(self) -> int:
if self.stack_max:
return self.stack_max.pop()[0]
Example code:
obj = MaxStack()
obj.push(6)
param_2 = obj.pop()
param_3 = obj.top()
param_4 = obj.peekMax()
param_5 = obj.popMax()
Input :
["MaxStack","push","push","push","top","popMax","top","peekMax","pop","top"] [[],[5],[1],[5],[],[],[],[],[],[]]
Output:
[null,null,null,null,5,5,5,5,None,5]
Expected:
[null,null,null,null,5,5,1,5,1,5]
Reference: Leetcode 716. Max Stack
class MaxStack:
def __init__(self,value):#taking some value to avoid empty obj
self.stack=[value]
self.max_=[value,0]
self.length=1
def push(self,value):
self.stack.append(value)
self.length+=1
if value>self.max_[0]:
self.max_[0],self.max_[1]=value,self.length-1
def pop(self):
if self.length==0:
return
elif self.stack[-1]==self.max_[0]:
self.popMax()
else:
self.stack.pop()
self.length-=1
def top(self):
print(self.stack[-1])
def peekMax(self):
print(self.max_[0])
def popMax(self):
if self.length==0 or self.max_[1]==-1:
return
self.stack.pop(self.max_[1])
self.length-=1
self.max_[0],self.max_[1]=-1,-1
for i in range(self.length):
if self.stack[i]>self.max_[0]:
self.max_[0],self.max_[1] = self.stack[i],i
Sorry for the improper indentations, I tried a lot to fix it. Anyways this should work and I wanted to try it out on leetcode but it needs a login. Let me know if there is any issue.
To me, it seems a little confusing to track the count in the tuple of the value, when you could just continue adding to the max stack and counting them from the list if you need that.
class MaxStack:
def __init__(self):
self.stack = []
self.maxes = []
def push(self, n):
self.stack.append(n)
if not self.maxes or n >= max(self.maxes):
self.maxes.append(n)
def pop(self):
if self.stack:
val = self.stack.pop()
if val in self.maxes:
self.maxes.remove(val)
def top(self):
if self.stack:
return self.stack[-1]
def peek_max(self):
if self.maxes:
return self.maxes[-1]
def pop_max(self):
if self.maxes:
return self.maxes.pop()
Then if you need the count of the number of each, just use count():
def max_count(self):
if self.maxes:
return self.maxes.count(max(self.maxes))
One function that I am having trouble with is split_list, where I have to split a list into three tuples, with each containing a strlist, through recursion. The first tuple with strings must start with a vowel, the second tuple with strings must start with a consonant, and the third tuple with strings should not start with an alpha character.
class Node:
def __init__(self, value, rest):
self.value = value
self.rest = rest
def __eq__(self, other):
return ((type(other) == Node)
and self.value == other.value
and self.rest == other.rest
)
def __repr__(self):
return ("Node({!r}, {!r})".format(self.value, self.rest))
# a StrList is one of
# - None, or
# - Node(string, StrList)
def split_list(strlist):
if strlist is None:
return (None, None, None)
res = split_list(strlist.rest)
if strlist.value or res(strlist.value) == 'AEIOUaeiou':
return (Node(strlist.value, res[0]), res[1], res[2])
if strlist.value or res(strlist.value) != 'AEIOUaeiou':
return (res[0], Node(strlist.value, res[1]), res[2])
if strlist.value.isalpha() or res(strlist.value) == False:
return (res[0], res[1], Node(strlist.value, res[2]))
This is what I have currently, but the main problem is that I am not getting the correct output when I run my unit tests. The problem I have is AssertionError.
Examples:
strlist = Node("xyz", Node("Abc", Node("49ers", None)))
self.assertEqual(split_list(strlist),(Node('Abc', None), Node('xyz', None), Node('49ers', None)))
strlist = Node("Yellow", Node("abc", Node("$7.25", Node("lime", Node("42", Node("Ethan", None))))))
self.assertEqual(split_list(strlist),(Node('abc', Node("Ethan", None)), Node('Yellow', Node("lime", None)), Node('$7.25', Node("42", None))))
Output:
AssertionError: Tuples differ: (Node('Yellow', Node('abc', Node('$7.25', Node('[50 chars]None) != (Node('abc', Node('Ethan', None)), Node('Yellow'[50 chars]ne)))
Can somebody figure out the problem? I would be thankful.
You should use recursion only for the traversal part. The recursive function should not contain 3 specific and distinct process conditions.
What you could do is write generic a node filter function that will build a new node chain and use it to assemble your tuple. Without the specific conditions, this function would be very simple and easy to test:
def filter(self,condition): # on the Node class
nextFound = self.rest.filter(condition) if self.rest else None
return Node(self.value,nextFound) if condition(self) else nextFound
Then you can build your tuple using this filter function with different parameters:
def split_list(strlist):
return ( strlist.filter(lambda n:n.value[:1].upper() in "AEIOU"),
strlist.filter(lambda n:n.value[:1].upper() in "BCDFGHJKLMNPQRSTVWXYZ"),
strlist.filter(lambda n:not n.value[:1].isalpha()) )
[EDIT] if you must do it all in a single function, you could combine the two (unwieldy as it may be):
def split_list(strlist):
nextFound = split_list(strlist.rest) if strlist.rest else (None,None,None)
return ( Node(strlist.value,nextFound[0]) if strlist.value[:1].upper() in "AEIOU" else nextFound[0],
Node(strlist.value,nextFound[1]) if strlist.value[:1].upper() in "BCDFGHJKLMNPQRSTVXYZ" else nextFound[1],
Node(strlist.value,nextFound[2]) if not strlist.value[:1].isalpha() else nextFound[2] )
if this for a homework, I sincerely hope your teacher will promote separation of concerns and not require questionable coding practices
def str_tree(atree,indent_char ='.',indent_delta=2):
def str_tree_1(indent,atree):
if atree == None:
return ''
else:
answer = ''
answer += str_tree_1(indent+indent_delta,atree.right)
answer += indent*indent_char+str(atree.value)+'\n'
answer += str_tree_1(indent+indent_delta,atree.left)
return answer
return str_tree_1(0,atree)
def build_balanced_bst(l):
if len(l) == 0:
return None
else:
mid = (len(l)-1)/2
if mid >= 1:
build_balanced_bst(l[:mid])
build_balanced_bst(l[mid:])
else:
return
I am working on the build_balanced_bst(l), the build_balanced_bst(l) takes a list of unique values that are sorted in increasing order. calling build_ballanced_bst( list(irange(1,10)) returns a binary search tree of height 3 that would print as:
......10
....9
..8
......7
....6
5
......4
....3
..2
....1
the str_tree function is used to print what the build_balanced_bst() function returns. my str_tree function is correct, I cannot change it. I can only change the build_balanced_bst() function.
I used the middle value in the list as the root’s value. when I try to call the build_balanced_bst(l) in the below, it does not print anything.
l = list(irange(1,10))
t = build_balanced_bst(l)
print('Tree is\n',str_tree(t),sep='')
can someone help me to fix my build_balanced_bst(l) function? many thanks.
str_tree() doesn't do anything: It just defines a nested function and implicitly returns None.
As a start, you can have str_tree do something:
def str_tree(atree, indent_char ='.', indent_delta=2):
def str_tree_1(indent, atree):
# Note that str_tree_1 doesn't use the indent argument
if atree == None:
return ''
return str_tree_1(indent_delta, atree)
But this is just a start.
I want to generate all possible expressions involving +, -, *, and / from a given ordered set of numbers:
class Node:
def __init__(self, data):
self.left = None
self.right = None
self.data = data
def is_leaf(self):
if self.left is None:
assert self.right is None
return True
return False
def __repr__(self):
if self.is_leaf():
return repr(self.data)
return '(%s%s%s)' % (self.left, self.data, self.right)
def enumerate_trees(numbers):
n = len(numbers)
if n == 1:
yield Node(numbers[0])
else:
for i in range(1, n):
left_subtrees = enumerate_trees(numbers[:i])
right_subtrees = enumerate_trees(numbers[i:])
for left in left_subtrees:
for right in right_subtrees:
for op in ['+', '-', '*', '/']:
root = Node(op)
root.left = left
root.right = right
yield root
if __name__ == '__main__':
for tree in enumerate_trees([5, 7, 10, 1]):
print(repr(tree)[1:-1])
The output is:
5+(7+(10+1))
5-(7+(10+1))
5*(7+(10+1))
5/(7+(10+1))
5+(7-(10+1))
5-(7-(10+1))
5*(7-(10+1))
5/(7-(10+1))
5+(7*(10+1))
5-(7*(10+1))
5*(7*(10+1))
5/(7*(10+1))
5+(7/(10+1))
5-(7/(10+1))
5*(7/(10+1))
5/(7/(10+1))
5+(7+(10-1))
5-(7+(10-1))
5*(7+(10-1))
5/(7+(10-1))
5+(7-(10-1))
5-(7-(10-1))
5*(7-(10-1))
5/(7-(10-1))
5+(7*(10-1))
5-(7*(10-1))
5*(7*(10-1))
5/(7*(10-1))
5+(7/(10-1))
5-(7/(10-1))
5*(7/(10-1))
5/(7/(10-1))
5+(7+(10*1))
5-(7+(10*1))
5*(7+(10*1))
5/(7+(10*1))
5+(7-(10*1))
5-(7-(10*1))
5*(7-(10*1))
5/(7-(10*1))
5+(7*(10*1))
5-(7*(10*1))
5*(7*(10*1))
5/(7*(10*1))
5+(7/(10*1))
5-(7/(10*1))
5*(7/(10*1))
5/(7/(10*1))
5+(7+(10/1))
5-(7+(10/1))
5*(7+(10/1))
5/(7+(10/1))
5+(7-(10/1))
5-(7-(10/1))
5*(7-(10/1))
5/(7-(10/1))
5+(7*(10/1))
5-(7*(10/1))
5*(7*(10/1))
5/(7*(10/1))
5+(7/(10/1))
5-(7/(10/1))
5*(7/(10/1))
5/(7/(10/1))
5+((7+10)+1)
5-((7+10)+1)
5*((7+10)+1)
5/((7+10)+1)
5+((7+10)-1)
5-((7+10)-1)
5*((7+10)-1)
5/((7+10)-1)
5+((7+10)*1)
5-((7+10)*1)
5*((7+10)*1)
5/((7+10)*1)
5+((7+10)/1)
5-((7+10)/1)
5*((7+10)/1)
5/((7+10)/1)
(5+7)+(10+1)
(5+7)-(10+1)
(5+7)*(10+1)
(5+7)/(10+1)
(5+7)+(10-1)
(5+7)-(10-1)
(5+7)*(10-1)
(5+7)/(10-1)
(5+7)+(10*1)
(5+7)-(10*1)
(5+7)*(10*1)
(5+7)/(10*1)
(5+7)+(10/1)
(5+7)-(10/1)
(5+7)*(10/1)
(5+7)/(10/1)
(5+(7+10))+1
(5+(7+10))-1
(5+(7+10))*1
(5+(7+10))/1
There are at least two problems I can see from the output:
Some trees are not reached, for example (((5 7) 10) 1).
For a certain tree, it is possible that not all the expressions are covered. For example for the tree ((5 (7 10)) 1), only
(5+(7+10))+1
(5+(7+10))-1
(5+(7+10))*1
(5+(7+10))/1
are reached.
What is the reason? Thanks.
Your recursive calls look like this:
left_subtrees = enumerate_trees(numbers[:i])
right_subtrees = enumerate_trees(numbers[i:])
for left in left_subtrees:
for right in right_subtrees:
#...
enumerate_trees returns a generator object, which can only be iterated over once. So the for loop over right_subtrees will only work the first time, and give no results on the next iterations of the outer for loop.
To fix this, you can either put the recursive calls directly in the for statements so that they are executed each time, or you can use list(enumerate_trees(...)) to copy the results into a list.
Here is a quote from https://stackoverflow.com/users/893/greg-hewgill answer to Explain Python's slice notation.
Python is kind to the programmer if there are fewer items than you ask
for. For example, if you ask for a[:-2] and a only contains one
element, you get an empty list instead of an error. Sometimes you
would prefer the error, so you have to be aware that this may happen.
So when the error is prefered, what is the Pythonic way to proceed ? Is there a more Pythonic way to rewrite this example ?
class ParseError(Exception):
pass
def safe_slice(data, start, end):
"""0 <= start <= end is assumed"""
r = data[start:end]
if len(r) != end - start:
raise IndexError
return r
def lazy_parse(data):
"""extract (name, phone) from a data buffer.
If the buffer could not be parsed, a ParseError is raised.
"""
try:
name_length = ord(data[0])
extracted_name = safe_slice(data, 1, 1 + name_length)
phone_length = ord(data[1 + name_length])
extracted_phone = safe_slice(data, 2 + name_length, 2 + name_length + phone_length)
except IndexError:
raise ParseError()
return extracted_name, extracted_phone
if __name__ == '__main__':
print lazy_parse("\x04Jack\x0A0123456789") # OK
print lazy_parse("\x04Jack\x0A012345678") # should raise ParseError
edit: the example was simpler to write using byte strings but my real code is using lists.
Here's one way that is arguably more Pythonic. If you want to parse a byte string you can use the struct module that is provided for that exact purpose:
import struct
from collections import namedtuple
Details = namedtuple('Details', 'name phone')
def lazy_parse(data):
"""extract (name, phone) from a data buffer.
If the buffer could not be parsed, a ParseError is raised.
"""
try:
name = struct.unpack_from("%dp" % len(data), data)[0]
phone = struct.unpack_from("%dp" % (len(data)-len(name)-1), data, len(name)+1)[0]
except struct.error:
raise ParseError()
return Details(name, phone)
What I still find unpythonic about that is throwing away the useful struct.error traceback to replace with a ParseError whatever that is: the original tells you what is wrong with the string, the latter only tells you that something is wrong.
Using a function like safe_slice would be faster than creating an object just to perform the slice, but if speed is not a bottleneck and you are looking for a nicer interface, you could define a class with a __getitem__ to perform checks before returning the slice.
This allows you to use nice slice notation instead of having to pass both the start and stop arguments to safe_slice.
class SafeSlice(object):
# slice rules: http://docs.python.org/library/stdtypes.html#sequence-types-str-unicode-list-tuple-bytearray-buffer-xrange
def __init__(self,seq):
self.seq=seq
def __getitem__(self,key):
seq=self.seq
if isinstance(key,slice):
start,stop,step=key.start,key.stop,key.step
if start:
seq[start]
if stop:
if stop<0: stop=len(seq)+stop
seq[stop-1]
return seq[key]
seq=[1]
print(seq[:-2])
# []
print(SafeSlice(seq)[:-1])
# []
print(SafeSlice(seq)[:-2])
# IndexError: list index out of range
If speed is an issue, then I suggest just testing the end points instead of doing arithmetic. Item access for Python lists is O(1). The version of safe_slice below also allows you to pass 2,3 or 4 arguments. With just 2 arguments, the second will be interpreted as the stop value, (similar to range).
def safe_slice(seq, start, stop=None, step=1):
if stop is None:
stop=start
start=0
else:
seq[start]
if stop<0: stop=len(seq)+stop
seq[stop-1]
return seq[start:stop:step]
Here is a more pythonic, more general rewrite of your code:
class ParseError(Exception):
pass
def safe_slice(data, start, end, exc=IndexError):
"""0 <= start <= end is assumed"""
r = data[start:end]
if len(r) != end - start:
raise exc()
return r
def lazy_parse(data):
"""extract (name, phone) from a data buffer.
If the buffer could not be parsed, a ParseError is raised."""
results = []
ptr = 0
while ptr < len(data):
length = ord(data[ptr])
ptr += 1
results.append(safe_slice(data, ptr, ptr + length, exc=ParseError))
ptr += length
return tuple(results)
if __name__ == '__main__':
print lazy_parse("\x04Jack\x0A0123456789") # OK
print lazy_parse("\x04Jack\x0A012345678") # should raise ParseError
Most of the changes are in the body of lazy_parse -- it will now work with multiple values instead of just two, and the correctness of the whole thing still depends on the last element being able to be parsed out exactly.
Also, rather than have safe_slice raise an IndexError which lazy_parse changes into a ParseError, I have lazy_parse give the desired exception to safe_slice to be raised in case of error (lazy_parse defaults to IndexError if nothing is passed to it).
Finally, lazy_parse isn't -- it's processing the entire string at once and returning all the results. 'Lazy' in Python means doing only what is needed to return the next piece. In the case of lazy_parse it would mean returning the name, then on a later call returning the phone. With only a slight modification we can make lazy_parse lazy:
def lazy_parse(data):
"""extract (name, phone) from a data buffer.
If the buffer could not be parsed, a ParseError is raised."""
ptr = 0
while ptr < len(data):
length = ord(data[ptr])
ptr += 1
result = (safe_slice(data, ptr, ptr + length, ParseError))
ptr += length
yield result
if __name__ == '__main__':
print list(lazy_parse("\x04Jack\x0A0123456789")) # OK
print list(lazy_parse("\x04Jack\x0A012345678")) # should raise IndexError
lazy_parse is now a generator that returns one piece at a time. Notice that we had to put list() around the lazy_parse call in the main section get lazy_parse to give us all the results in order to print them.
Depending on what you're doing this might not be the desired way, however, as it can be more difficult to recover from errors:
for item in lazy_parse(some_data):
result = do_stuff_with(item)
make_changes_with(result)
...
By the time the ParseError is raised you may have made changes that are difficult or impossible to back out. The solution in a case like this would be to do the same as we did in the print part of main:
for item in list(lazy_parse(some_data)):
...
The list call completely consumes lazy_parse and gives us a list of the results, and if an error was raised we'll know about it before we process the first item in the loop.
Here is a complete SafeSlice class re-using https://stackoverflow.com/users/107660/duncan and
https://stackoverflow.com/users/190597/unutbu answers.
The class is quite big because it have full slice support (start, stop and step). This may be overkill for the simple job done in the example but for a more complete real life problem, it might prove useful.
from __future__ import division
from collections import MutableSequence
from collections import namedtuple
from math import ceil
class ParseError(Exception):
pass
Details = namedtuple('Details', 'name phone')
def parse_details(data):
safe_data = SafeSlice(bytearray(data)) # because SafeSlice expects a mutable object
try:
name_length = safe_data.pop(0)
name = safe_data.popslice(slice(name_length))
phone_length = safe_data.pop(0)
phone = safe_data.popslice(slice(phone_length))
except IndexError:
raise ParseError()
if safe_data:
# safe_data should be empty at this point
raise ParseError()
return Details(name, phone)
def main():
print parse_details("\x04Jack\x0A0123456789") # OK
print parse_details("\x04Jack\x0A012345678") # should raise ParseError
SliceDetails = namedtuple('SliceDetails', 'first last length')
class SafeSlice(MutableSequence):
"""This implementation of a MutableSequence gives IndexError with invalid slices"""
def __init__(self, mutable_sequence):
self._data = mutable_sequence
def __str__(self):
return str(self._data)
def __repr__(self):
return repr(self._data)
def __len__(self):
return len(self._data)
def computeindexes(self, ii):
"""Given a slice or an index, this method computes what would ideally be
the first index, the last index and the length if the SafeSequence was
accessed using this parameter.
None indexes will be returned if the computed length is 0.
First and last indexes may be negative. This means that they are invalid
indexes. (ie: range(2)[-4:-3] will return first=-2, last=-1 and length=1)
"""
if isinstance(ii, slice):
start, stop, step = ii.start, ii.stop, ii.step
if start is None:
start = 0
elif start < 0:
start = len(self._data) + start
if stop is None:
stop = len(self._data)
elif stop < 0:
stop = len(self._data) + stop
if step is None:
step = 1
elif step == 0:
raise ValueError, "slice step cannot be zero"
length = ceil((stop - start) / step)
length = int(max(0, length))
if length:
first_index = start
last_index = start + (length - 1) * step
else:
first_index, last_index = None, None
else:
length = 1
if ii < 0:
first_index = last_index = len(self._data) + ii
else:
first_index = last_index = ii
return SliceDetails(first_index, last_index, length)
def slicecheck(self, ii):
"""Check if the first and the last item of parameter could be accessed"""
slice_details = self.computeindexes(ii)
if slice_details.first is not None:
if slice_details.first < 0:
# first is *really* negative
self._data[slice_details.first - len(self._data)]
else:
self._data[slice_details.first]
if slice_details.last is not None:
if slice_details.last < 0:
# last is *really* negative
self._data[slice_details.last - len(self._data)]
else:
self._data[slice_details.last]
def __delitem__(self, ii):
self.slicecheck(ii)
del self._data[ii]
def __setitem__(self, ii, value):
self.slicecheck(ii)
self._data[ii] = value
def __getitem__(self, ii):
self.slicecheck(ii)
r = self._data[ii]
if isinstance(ii, slice):
r = SafeSlice(r)
return r
def popslice(self, ii):
"""Same as pop but a slice may be used as index."""
self.slicecheck(ii)
r = self._data[ii]
if isinstance(ii, slice):
r = SafeSlice(r)
del self._data[ii]
return r
def insert(self, i, value):
length = len(self._data)
if -length <= i <= length:
self._data.insert(i, value)
else:
self._data[i]
if __name__ == '__main__':
main()