Python: how to get error from list[-1]? - python

Is there a way to return an error for the index value [-1]?
>>>l=[1,2,3]
>>>l[-1]
error:list index out of range

Not for the built-in list type, but you can define your own class that has stricter indexing rules:
>>> class StrictList(list):
... def __getitem__(self, index):
... if index < 0:
... raise IndexError("negative integers are forbidden")
... return list.__getitem__(self, index)
...
>>> seq = StrictList([1,2,3])
>>> seq[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getitem__
IndexError: 'negative integers are forbidden'

Related

Cannot access class variable in class method

class Bin():
a=[]
def g(self,e):
self.a.append(e)
o=Bin()
o.g(3)
o.g(4)
o.g(5)
o.g(6)
Traceback (most recent call last):
File "<string>", line 28, in <module>
File "<string>", line 9, in bs
NameError: name 'a' is not defined
how to deal with this error? i wanna append the list inside the class with given elements and use the list 'a' in other class methods too.
Fix your indentation:
class Bin:
a = []
def g(self, e):
self.a.append(e)
o = Bin()
o.g(3)
o.g(4)
o.g(5)
o.g(6)
print(Bin.a)
Output : [3, 4, 5, 6]

Change builtin function - Print

I'm trying to change the print builtin function from python.
The reason I'm trying to achieve this is cause my application has an verbose sys.argv, and I want to use print to console out the message whether the verbose is True or False.
I've tried to use create a new function, but I get a recursion error:
>>> import builtins
>>> def new_print(*args, **kwargs):
... print('print:', *args, **kwargs)
...
>>> old_print = builtins.print
>>> old_print(1)
1
>>> builtins.print = new_print
>>> print(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in new_print
File "<stdin>", line 2, in new_print
File "<stdin>", line 2, in new_print
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
I've tried using sys.stdout():
>>> import builtins
>>> import sys
>>> def new_print(*args, **kwargs):
... sys.stdout(*args, **kwargs)
...
>>> old_print = builtins.print
>>> old_print(1)
1
>>> builtins.print = new_print
>>> print(1
... )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in new_print
TypeError: '_io.TextIOWrapper' object is not callable
Although using those options, none seemed to work properly.
I need the new print function to be accesible for all my module files, without needing to import it every time. That's why I'm trying to change the builtin function, but I'm not sure that changing this in my init.py file will make a difference for my other files.
Please, if you have any idea on what could help me, please leave it below.
You almost had it. Call old_print in your new function:
def new_print(*args, **kwargs):
old_print('print:', *args, **kwargs)
old_print = print
print = new_print

getting a python function of functionType for a nested function with recursion

I am trying to do unit testing for nested functions (function inside a function), I am using code("nested" is function name) from below link which would supply closures and returns a valid function that is callable from tests. It works for simple functions. I am trying to make it work for recursive functions.
As an example:
I am trying to get a valid function for "innerfunction" which has an entry in co_freevars as "innerfunction".
I want to get a function (FunctionType I believe) for "innerfunction" as a callable. To get this I need to call FunctionType with a tuple with a FunctionType for "innerfunction". This becomes a recursive "dependency". How can I resolve this dependency for parameters to be sent for "closures"
Function for
def toplevelfunction():
def innerfunction(a):
print ('val of a is ', a)
if a > 0:
innerfunction(a -1)
innerfunction(10)
Original code that I am using:
def freeVar(val):
def nested():
return val
return nested.__closure__[0]
codeAttribute = '__code__' if sys.version_info[0] == 3 else 'func_code'
def nested(outer, innerName, **freeVars):
if isinstance(outer, (types.FunctionType, types.MethodType)):
outer = outer.__getattribute__(codeAttribute)
for const in outer.co_consts:
if isinstance(const, types.CodeType) and const.co_name == innerName:
return types.FunctionType(const, globals(), None, None, tuple(
freeVar(freeVars[name]) for name in const.co_freevars))
https://code.activestate.com/recipes/580716-unit-testing-nested-functions/
How to add support for closures so below works:
func = nested(toplevelfunction, 'innerfunction')
func(5)
would return error need a closure of length 1.
Adding a closure referring to "const" shows up that it is of CodeType and not FunctionType.
Adding a closure value to refer itself seems tricky after reading through the documentation.
I do find innerfunction as:
{code} <code object innerfunction at 0x104b9bc00, file "/<filedirectory>/handle_results.py", line 44>
co_argcount = {int} 1
co_cellvars = {tuple} <class 'tuple'>: ()
co_code = {bytes} b"t\x00\x00d\x01\x00|\x00\x00\x83\x02\x00\x01|\x00\x00d\x02\x00k\x04\x00r'\x00\x88\x00\x00|\x00\x00d\x03\x00\x18\x83\x01\x00\x01d\x00\x00S"
co_consts = {tuple} <class 'tuple'>: (None, 'val of a is ', 0, 1)
co_filename = {str} '/<fildirectory>/handle_results.py'
co_firstlineno = {int} 44
co_flags = {int} 19
co_freevars = {tuple} <class 'tuple'>: ('innerfunction ',)
co_kwonlyargcount = {int} 0
co_lnotab = {bytes} b'\x00\x01\r\x01\x0c\x01'
co_name = {str} 'innerfunction '
co_names = {tuple} <class 'tuple'>: ('print',)
co_nlocals = {int} 1
co_stacksize = {int} 3
co_varnames = {tuple} <class 'tuple'>: ('a',)
Thank you for hinting me on this limitation on my ActiveState recipe you linked to in your question!
You tried to unit test a local recursive function; my minimal example for this looks like this:
def f(x):
def fac(n):
return fac(n-1) * n if n > 1 else 1
print "Faculty of", x, "is", fac(x)
So in a unit test you want to test the inner function fac(). Simply applying my recipe leads to this error:
nestedFac = nested(f, 'fac')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 7, in nested
File "<stdin>", line 7, in <genexpr>
KeyError: 'fac'
This is because fac is an identifier used within the inner function, and you must specify the value of each identifier used within the inner function. Callable identifiers are no exception:
nestedFac = nested(f, 'fac', fac=None)
This sets fac to the value None and the call to nested does not fail anymore.
Unfortunately, the resulting function will try to call None(...) when you call it:
nestedFac(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in fac
TypeError: 'NoneType' object is not callable
You would need to pass the function itself as the value for fac to avoid this. Unfortunately, you do not have it yet when you call nested(). A repeated wrapping could be done like this:
nestedFac = nested(f, 'fac', fac=None)
nestedFac = nested(f, 'fac', fac=nestedFac)
nestedFac = nested(f, 'fac', fac=nestedFac)
nestedFac = nested(f, 'fac', fac=nestedFac)
This would limit your recursion depth to the number of wraps you applied:
nestedFac(2)
2
nestedFac(3)
6
nestedFac(4)
24
nestedFac(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in fac
File "<stdin>", line 3, in fac
File "<stdin>", line 3, in fac
File "<stdin>", line 3, in fac
TypeError: 'NoneType' object is not callable
To avoid this, you can pass a local function as proxy:
def q(*args, **kwargs):
return nestedFac(*args, **kwargs)
nestedFac = nested(f, 'fac', fac=q)
Or as a lambda:
nestedFac = nested(f, 'fac', fac=lambda *args, **kwargs:
nestedFac(*args, **kwargs))
Or for the special case of just one parameter:
nestedFac = nested(f, 'fac', fac=lambda n: nestedFac(n))
An extension to the nested() recipe which does this automatically would be the better approach, though. Feel free to fork the recipe and add this aspect! :-)

Accessing instance variables using index

I have a class which keeps track of errors encountered during a search operation
class SearchError(object):
def __init__(self,severity=0,message=''):
self.severity = severity
self.message = message
My idea is to make the instance variables indexable.
So if I have
a=SearchError(1,"Fatal Error")
I get
>>> a[0]
1
>>> a[1]
'Fatal Error'
>>> a.severity
1
>>> a.message
'Fatal Error'
To do this I add a __getitem__ method to the class. The class now becomes
class SearchError(object):
def __init__(self,severity=0,message=''):
self.severity = severity
self.message = message
def __getitem__(self,val):
if isinstance(val,slice):
return [self.__getitem__(i) for i in xrange(val.start,val.stop,val.step)]
elif val==0:
return self.severity
elif val==1:
return self.message
else:
raise IndexError
This does what I want but fails in cases such as
>>> a[:2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 23, in __getitem__
TypeError: an integer is required
Or even
>>> a[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 29, in __getitem__
IndexError
I understand my implementation of __getitem__ is limited. What I need to know is -
Is this the way to make instance variables indexable (Without using a list as variable container)?
How do I make the object behave 'sanely' as far as indexing goes?
This does everything:
>>> from collections import namedtuple
>>> _SearchError = namedtuple("SearchError", "severity message")
>>> def SearchError(severity=0, message=''):
return _SearchError(severity, message)
xrange requires all its arguments to be integers, but slice objects have None for unspecified attributes.
The best way to implement what you're after is to use namedtuple:
from collections import namedtuple
class SearchError(namedtuple('SearchError', 'severity message')):
def __new__(cls, severity=0, message=''):
return super(SearchError, cls).__new__(cls, severity, message)
The problem here is that slice objects default to having None values as attributes. So, a[:2] passes in slice(None,2,None). When you break this apart and try to pass it to xrange, you'll get a TypeError:
>>> xrange(None,2,None)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: an integer is required
Try a[0:2:1] and your code will work. Ultimately, you could do something like:
val.start = 0 if val.start is None else val.start
val.stop = 2 if val.stop is None else val.stop
val.stop = 2-val.stop if val.stop < 0 else val.stop
val.step = 1 if val.step is None else val.step
to unravel your slices into useable indices (In the general case, it'd be better to use len(self) instead of 2, but I don't know if your object has defined __len__.
Or, even better:
start,stop,step = val.indices(len(self))
Similarly, in the case where you do a[-1], you're not passing in a slice, a 0 or a 1, so you hit the else clause where you to raise an IndexError.
I mucked around the code and found the following solution.
It uses lists but to only store the names of the variables - Not the actual values. Additionally it also provides the method add to add a new variable with a given name and value. The new variable will also be indexable. (The add function is not needed by my class, but is nice to have around)
Thanks to #mgilson for nudging me in this direction
class SearchError(object):
def __init__(self,severity=0,message=''):
self.severity = severity
self.message = message
self._length = 2
self._vars_list = ['severity','message',]
def __getitem__(self,val):
if isinstance(val,slice):
steps = val.indices(self._length)
return [self.__getitem__(i) for i in xrange(*steps)]
elif val < 0:
i = self._length + val
if i < 0:
raise IndexError,"Index Out of range for SearchError object"
else:
return self.__getitem__(i)
else:
try:
return getattr(self,self._vars_list[val])
except IndexError:
raise IndexError,"Index Out of range for SearchError object"
def add(self,var_name,value):
self._vars_list.append(var_name)
self._length += 1
setattr(self,var_name,value)
The results
>>> a=SearchError(1,"Fatal Error")
>>> a[-1]
'Fatal Error'
>>> a[-2]
1
>>> a[-3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 14, in __getitem__
IndexError: Index Out of range for SearchError object
>>> a[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 21, in __getitem__
IndexError: Index Out of range for SearchError object
>>> a[1]
'Fatal Error'
>>> a[0]
1
>>> a[:]
[1, 'Fatal Error']
>>> a.add('new_severity',8)
>>> a[:]
[1, 'Fatal Error', 8]
>>> a[3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 21, in __getitem__
IndexError: Index Out of range for SearchError object
>>> a[2]
8
>>> a.new_severity
8
>>> a[:3]
[1, 'Fatal Error', 8]
>>> a[:4]
[1, 'Fatal Error', 8]
>>> a[:2]
[1, 'Fatal Error']
As far as I can see, you need lists (to either store the actual variables or their names). If someone has a better alternative please do post

Python TypeErrors: "' list' object is not callable" and "'function' object is unsubscriptable"

I have the following code:
from random import randint,choice
add=lambda x:lambda y:x+y
sub=lambda x:lambda y:x-y
mul=lambda x:lambda y:x*y
ops=[[add,'+'],[sub,'-'],[mul,'*']]
def gen_expression(length,left,right):
expr=[]
for i in range(length):
op=choice(ops)
expr.append([op[0](randint(left,right)),op[1]])
return expr
def eval_expression (expr,x):
for i in expr:
x=i[0](x)
return x
def eval_expression2 (expr,x):
for i in expr:
x=i(x)
return x
[snip , see end of post]
def genetic_arithmetic(get,start,length,left,right):
batch=[]
found = False
for i in range(30):
batch.append(gen_expression(length,left,right))
while not found:
batch=sorted(batch,key=lambda y:abs(eval_expression(y,start)-get))
print evald_expression_tostring(batch[0],start)+"\n\n"
#combine
for w in range(len(batch)):
rind=choice(range(length))
batch.append(batch[w][:rind]+choice(batch)[rind:])
#mutate
for w in range(len(batch)):
rind=choice(range(length))
op=choice(ops)
batch.append(batch[w][:rind]+[op[0](randint(left,right)),op[1]]+batch[w][rind+1:])
found=(eval_expression(batch[0],start)==get)
print "\n\n"+evald_expression_tostring(batch[0],start)
When I try to call to call genetic_artihmetic with eval_expression as the sorting key, I get this:
Traceback (most recent call last):
File "<pyshell#113>", line 1, in <module>
genetic_arithmetic(0,10,10,-10,10)
File "/home/benikis/graming/py/genetic_number.py", line 50, in genetic_arithmetic
batch=sorted(batch,key=lambda y:abs(eval_expression(y,start)-get))
File "/home/benikis/graming/py/genetic_number.py", line 50, in <lambda>
batch=sorted(batch,key=lambda y:abs(eval_expression(y,start)-get))
File "/home/benikis/graming/py/genetic_number.py", line 20, in eval_expression
x=i[0](x)
TypeError: 'function' object is unsubscriptable
And when I try the same with eval_expression2 as the sorting,the error is this:
Traceback (most recent call last):
File "<pyshell#114>", line 1, in <module>
genetic_arithmetic(0,10,10,-10,10)
File "/home/benikis/graming/py/genetic_number.py", line 50, in genetic_arithmetic
batch=sorted(batch,key=lambda y:abs(eval_expression2(y,start)-get))
File "/home/benikis/graming/py/genetic_number.py", line 50, in <lambda>
batch=sorted(batch,key=lambda y:abs(eval_expression2(y,start)-get))
File "/home/benikis/graming/py/genetic_number.py", line 25, in eval_expression2
x=i(x)
TypeError: 'list' object is not callable
As far as i can wrap my head around this, my guess is that sorted() is trying to recursively sort the sublists,maybe? What is really going on here?
Python version is 2.6 - the one in the debian stable repos.
[snip] here:
def expression_tostring(expr):
expr_str=len(expr)*'('+'x '
for i in expr :
if i[1]=='*':
n=i[0](1)
else:
n=i[0](0)
expr_str+=i[1]+' '+str(n)+') '
return expr_str
def evald_expression_tostring(expr,x):
exprstr=expression_tostring(expr).replace('x',str(x))
return exprstr+ ' = ' + str(eval_expression(expr,x))
x=i[0](x) #here i is a function so you can't perform indexing operation on it
x=i(x) #here i is a list so you can't call it as a function
in both cases the value of i is fetched from expr, may be expr contains different type of object than what you're assuming here.
Try this modification:
def gen_expression(length,left,right):
expr=[]
for i in range(length):
op=choice(ops)
expr.append([op[0], randint(left,right),op[1]])
return expr
def eval_expression (expr,x):
for i in expr:
x=i[0](i[1])
return x
You had expr.append([op[0](randint(left,right)),op[1]]) which will put the return value of the calling the function into the 0th index.

Categories

Resources