How to handle python exception inside if statement - python

For example I got this if statement:
if user.address.streetname == 'Target':
pass
elif:
(...)
else:
(...)
But not all users have enough money to have an address so it could raise an exception
In my case a django DoesNotExist exception. In this case it should assume false.
How to handle exception in this place without breaking if elif else flow?

If user.address is a model instance, you can do
if user and user.address and user.address.streetname and user.address.streetname == 'Target':
#Do something/
Or, you can also do:
address = getattr(user, 'address', None) if user else None
if address and getattr(address, 'streetname', '') == 'Target':
#do something

Use duck typing and create a sentinel object that is guaranteed to have a non-matching streetname attribute to use in place of an unavailable user.address.
poor_user_address = type('', (), {'streetname': None})()
if getattr(user, 'address', poor_user_address).streetname == "Target":
...
The call to type creates a minimal class with a class variable streetname; the rest of the details of the class are irrelevant. With duck typing, it doesn't matter that poor_user_address is an instance of a different class, as long as it exhibits the same behavior. In this case, the only expected behavior is to have a streetname attribute that can be compared to "Target".

Here's another stackoverflow question that answers this
The relevant part would be: hasattr(user, 'address')
If you add that to your if before accessing the property you can maintain the if/else flow.

try:
streetname = user.address.streetname
except DoesNotExist:
streetname = None
# or:
# streetname = NonexistenceSentinel()
if streetname == 'Target':
pass
elif:
...
else:
...
But probably what you are really looking for is some syntactic sugar to allow you to not put this in everywhere. Here's a recipe that lets you do that:
# 'Stupid' object that just returns itself.
# Any attribute will just return itself.
class SentinelObject(object):
__slots__ = []
def __init__(self):
pass
def __getattr__(self, key):
return self
def __nonzero__(self):
return False
def delegate_specials(specials):
specialnames = ['__%s__'%s for s in specials.split()]
def wrapit(cls, method):
return lambda self, *args, **kwargs: getattr(self._original_obj, method)(*args, **kwargs)
def dowrap(cls):
for n in specialnames:
setattr(cls, n,
wrapit(cls, n))
return cls
return dowrap
#delegate_specials('getitem setitem iter add sub mul div repr str len')
class SafeLookupObject(object):
__slots__ = ['_original_obj', '_sentinel_default']
__original_names__ = ['_original_obj', '_sentinel_default']
def __init__(self, original_obj, sentinel_default=SentinelObject()):
self._original_obj = original_obj
self._sentinel_default = sentinel_default
def __getattr__(self, key):
if key in self.__original_names__:
return object.__getattr__(self, key)
else:
try:
val = getattr(self._original_obj, key)
if callable(val):
return val
else:
return SafeLookupObject(val, self._sentinel_default)
except AttributeError:
return self._sentinel_default
def __setattr__(self, key, value):
if key in self.__original_names__:
return object.__setattr__(self, key, value)
else:
return setattr(self._original, key, value)
May not be perfect, looks OK at a first pass.
What this does: You pass in an original object, and a default val. The default val is a special SentinelObject (more on that in a minute). Only for getattr, if it doesn't exist, it returns the sentinel value. If it does exist, it checks to see if it's callable or not. If it's callable (i.e. a function), it returns it directly. If not, it wraps it in a SafeLookupObject and returns it.
The intention is that if you want to lookup x.y.z, you can just wrap x in the SafeLookupObject, and then x.y will automatically be wrapped as well, all the way down, so if it fails anywhere in the list, that value will be replaced with the sentinel object.
Therefore the special SentinelObject, which returns itself for whatever attribute you pass in. This with the above makes it fully recursive.
I.e. let's say you look up a.b.c.d with a as safe. a.b is OK, but then c does not exist in b. With a default of None, a.b.c returns None, but then a.b.c.d raises an exception.
If you use the SentinelObject as the default, then a.b.c instead returns a SentinelObject which both is boolean False, and can be matched against to determine a non-existent attribute. a.b.c.d also returns the same SentinelObject, and so it's now completely safe.

Related

Return self in python class just returns NoneType

I create a linked list in python and want to build a function to find the last item, but when I design as following, the function returns "None" type. There must be something wrong with "return self" because I print "self" before return it looks fine.
class LinkNode():
def __init__(self,value=0,next=None):
self.val=value
self.next=next
def findlast(self):
if self.next == None:
return self
else:
self.next.findlast()
The following is to create instances
node3=LinkNode(3,None)
node2=LinkNode(2,node3)
chain=LinkNode(1,node2)
x=chain.findlast()
type(x)
NoneType
def findlast(self):
if self.next == None:
return self
else:
self.next.findlast()
That last line is a problem since it doesn't return anything from the function, which is why you get None. You should use (also without the superfluous else, and using is with None):
def findlast(self):
if self.next is None:
return self
return self.next.findlast()
However, just keep in mind this is not the ideal use case for recursion, it may be better written as:
def findlast(obj):
if obj is not None: # only needed if you may pass in None as self.
while obj.next is not None:
obj = obj.next
return obj

How do I make a subclass of "dict" that returns a fallback value when it can't find a value for a key?

I want to create SafeDict, a subclass of dict.
When asked to retrieve a value for a non existing key, SafeDict should return a fallback value.
(I know there are other ways to do this, but I'm practicing my OOP skills.)
Right now I have:
class SafeDict(dict):
def __getitem__(self, key):
try:
super().__getitem__(key)
except KeyError:
return "Beetle"
a = {"Ford": "Mustang"}
b = SafeDict({"Ferrari": "Enzo"})
print(a["Ford"]) # This prints "Mustang" (good)
#print(a["Aston"]) # This raises KeyError (good)
print(b["Ferrari"]) # This should print "Enzo", but it prints "None" (bad)
print(b["Aston"]) # This prints "Beetle" (good)
Maybe print(b["Ferrari"]) prints None beacuse super() runs the __getitem__ method on the list superclass, and that class has no dictionary with "Ferrari": "Enzo" in it?
I tried to remove the super(), and use self, but I ran into recursion problems.
Help?
You forgot to return the super() value:
class SafeDict(dict):
def __getitem__(self, key):
try:
return super().__getitem__(key)
except KeyError:
return "Beetle"
When a method has no explicit return statement, the function implicitly returns None

hasattr returns attribute error even after exception is captured

Here is my sample code to check if the given attribute is present in the class or not.
class EmpDict:
def __init__(self, data):
self.data = data
try:
self.first_name = data['first_name']
self.age = data['age']
self.last_name = data['last_month']
except:
pass
def is_attr_available(self, attr):
try:
hasattr(EmpDict, attr)
return True
except:
return False
Here is the test:
>> emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}
>> a = EmpDict(emp)
>> print(a.is_attr_available(a.first_name))
True
>> print(a.is_attr_available(a.age))
print(a.is_attr_available(a.age))
AttributeError: 'EmpDict' object has no attribute 'age'
I expected False for the last statement, instead I get an AttributeError even though I also captured the exception in is_attribute_available method.
Any leads on what I am doing wrong here?
That's not how you use hasattr.
First, you use hasattr when you have the attribute name as a string value:
attrname = 'age'
hasattr(a, attrname)
You can't pass it a.age—that's already trying to look up a.age, and then pass the result of that as the attribute name. That will be false if there is an age (because you don't have an attribute named 23), and it won't even get to hasattr if there isn't one.
But there are two other problems with your code.
First, hasattr returns True if the attribute is there, False if it isn't. It only raises an exception if there's a typo in your code or a serious bug in your class (and you don't want an except: to catch those and just make the problem impossible to debug).
Second, EmpDict is the class. The class doesn't have any of these attributes, so that's always going to return false. You want to know if the instance, self, has them.
So:
def is_attr_available(self, attr):
return hasattr(self, attr)
And then, you could change your code to call
print(a.is_attr_available('age'))
But really, why do you even want this function? Why not just:
try: the a.age?
… or provide a default value like None so the attribute always exists?
Agree with #blhsing, but I changed your code around a little bit,(there are some little things that can be better) one thing is that the second argument of hasattr should be a string not a attribute,
Example:
class EmpDict:
def __init__(self, data):
self.data = data
try:
self.first_name = data['first_name']
self.age = data['age']
self.last_name = data['last_month']
except:
()
def is_attr_available(self, attr):
return hasattr(self,attr)
emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}
a = EmpDict(emp)
print(a.is_attr_available('age'))
Output:
False
Also:
You don't need an try-except for hasattr (otherwise why is it called hasattr)
From the documentation:
hasattr(object, name)
The arguments are an object and a string. The result is True if the string is the name of one of the object’s attributes, False if not. (This is implemented by calling getattr(object, name) and seeing whether it raises an exception or not.)
Here is a much better code for it:
class EmpDict:
def __init__(self, data):
self.data = data
self.first_name = data.get('first_name')
self.age = data.get('age')
self.last_name = data.get('last_month')
def is_attr_available(self, attr):
return hasattr(self, attr) and getattr(self,attr)!=None
emp = {'first_name' : 'Tom', 'last_name' : 'Jose'}
a = EmpDict(emp)
print(a.is_attr_available('age'))
hasattr takes the attribute name as a string as the second argument, so you should pass to it the name of the attribute instead:
print(a.is_attr_available('age'))
Otherwise you would raise the AttributeError exception by trying to evaluate a.age.
Also, hasattr does not raise any exception, but simply returns True if the object has the attribute, so you should modify your is_attr_available function to:
def is_attr_available(self, attr):
return hasattr(self, attr)

Deferring a computation in custom object until data available

I have a custom class like the below. The idea, as the naming suggests, is that I want to evaluate a token stream in a parser-type tool. Once a bunch of constructs have been parsed out and put into data structures, certain sequences of tokens will evaluate to an int, but when the data structures aren't available yet, a function just returns None instead. This single complex data structure 'constructs' gets passed around pretty much everywhere in the program.
class Toks(list):
def __init__(self, seq, constructs=Constructs()):
list.__init__(self, seq)
self.constructs = constructs
#property
def as_value(self):
val = tokens_as_value(self, self.constructs)
return val if val is not None else self
At points in the code, I want to assign this maybe-computable value to a name, e.g.:
mything.val = Toks(tokens[start:end], constructs).as_value
Well, this gives mything.val either an actual int value or a funny thing that allows us to compute a value later. But this requires a later pass to actually perform the computation, similar to:
if not isinstance(mything.val, int):
mything.val = mything.val.as_value
As it happens, I can do this in my program. However, what I'd really like to happen is to avoid the second pass altogether, and just have access to the property perform the computation and give the computed value if it's computable at that point (and perhaps evaluate to some sentinal if it's not possible to compute).
Any ideas?
To clarify: Depending on the case I get "value" differently; actual code is more like:
if tok.type == 'NUMBER':
mything.val = tok.value # A simple integer value
else:
mything.val = Toks(tokens[start:end], constructs).as_value
There are additional cases, sometimes I know I know the actual value early, and sometimes I'm not sure if I'll only know it later.
I realize I can defer calling (a bit more compactly than #dana suggests) with:
return val if val is not None else lambda: self.as_value
However, that makes later access inconsistent between mything.val and mything.val(), so I'd still have to guard it with an if to see which style to use. It's the same inconvenience whether I need to fall back to mything.val.as_value or to mything.val() after the type check.
You could easily do something like:
class NaiveLazy(object):
def __init__(self, ctor):
self.ctor = ctor
self._value = None
#property
def value(self):
if self._value is None:
self._value = ctor()
return self._value
mything = NaiveLazy(lambda: time.sleep(5) and 10)
And then always use mything.value (example to demonstrate evaluation):
print mything.value # will wait 5 seconds and print 10
print mything.value # will print 10
I've seen some utility libraries create a special object for undefined in case ctor returns None. If you eventually want to extend your code beyond ints, you should think about that:
class Undefined(object): pass
UNDEFINED = Undefined()
#...
self._value = UNDEFINED
#...
if self._value is UNDEFINED: self._value = ctor()
For your example specifically:
def toks_ctor(seq, constructs=Constructs()):
return lambda l=list(seq): tokens_as_value(l, constructs) or UNDEFINED
mything = NaiveLazy(toks_ctor(tokens[start:end], constructs))
If you're using Python3.2+, consider a Future object. This tool lets you run any number of calculations in the background. You can wait for a single future to be completed, and use its value. Or, you can "stream" the results one at a time as they're completed.
You could return a callable object from as_value, which would allow you automatically check for the real return value automatically. The one drawback is you'd need to use mything.val() instead of mything.val:
def tokens_as_value(toks, constructs):
if constructs.constructed:
return "some value"
else:
return None
class Constructs(object):
def __init__(self):
self.constructed = False
class Toks(list):
def __init__(self, seq, constructs=Constructs()):
list.__init__(self, seq)
self.constructs = constructs
#property
def as_value(self):
return FutureVal(tokens_as_value, self, self.constructs)
class FutureVal(object):
def __init__(self, func, *args, **kwargs):
self.func = func
self._val = None
self.args = args
self.kwargs = kwargs
def __call__(self):
if self._val is None:
self._val = self.func(*self.args, **self.kwargs)
return self._val
Just for the purposes of the example, Constructs just contains a boolean that indicates whether or not a real value should be returned from tokens_as_value.
Usage:
>>> t = test.Toks([])
>>> z = t.as_value
>>> z
<test.FutureVal object at 0x7f7292c96150>
>>> print(z())
None
>>> t.constructs.constructed = True
>>> print(z())
our value

python: method depends on whether param is int or string

Is there a more pythonic way to write __getitem__ than the following? The issue is checking type and doing different things depending on the type of the parameter in the call.
class This():
def __init__(self, name, value):
self.name, self.value = name, value
class That():
def __init__(self):
self.this_list = []
def add_this(self, this):
self.this_list.append(this)
def __getitem__(self, x):
if isinstance(x, int):
return self.this_list[x] # could wrap in try/except for error checking
elif isinstance(x, str):
for this in self.this_list:
if this.name == x:
return this
return None
a = This('a', 1)
b = This('b', 2)
c = That()
c.add_this(a)
c.add_this(b)
print c[1].name
print c['a'].name
There are quite a few options, but I think there is not one best choice. It depends on your use case and preferences. Just to give you a few hints:
Do you really have to store the data in a list? In your example you could use a dictionary and insert the object twice: Once using the integer as key and once using the string as a key. That would make your __getitem__ quite simple. ;-)
Another option would be to make your interface more explicit and use byInt/byString methods. You should choose better names of course.
If you give more details about what you really want to do, I could propose more alternatives.
You are almost always better off testing the behavior of the kind of item you want rather than explicitly testing for type. In your case, I'd simply try to get the desired item by index first and catch TypeError to check by name.
def __getitem__(self, key):
try:
return self.this_list[key]
except TypeError:
try:
return next(item for item in self.this_list if item.name == key)
except StopIteration:
raise KeyError("key `%s` not found" % key)
Note that this will automatically work with slices too, since in this case the key will be a slice object and that will work fine with the [...] notation.
You should probably be using a dict rather than a list inside your class, though, rather than searching a list for an object attribute. Exceptions would be if you really need slicing or if the names can be changed by code outside your class.
Another (perhaps slightly unconventional) possibility is to implement the special method __eq__() on your This class, allowing it to be compared to a string, so that if the class's name attribute is (say) "Jerry", then This("Jerry", 0) == "Jerry". Then you don't actually need the container class and can just use a regular list:
class This(object):
def __init__(self, name, value):
self.name, self.value = name, value
def __eq__(self, other):
return self.name == other
thislist = [This("Jerry", 42), This("Amy", 36)]
"Jerry" in thislist # True
thislist.index("Amy") # 1
The syntax for accessing an item by name is still a little hairy:
thislist[thislist.index("Amy")]
But you can simply subclass list and combine this with my previous suggestion, which becomes simpler and more generic, since it works with any object that knows how to compare itself to whatever kind of key you're using:
class That(list):
def __getitem__(self, key):
try:
return list.__getitem__(self, key)
except TypeError:
return list.__getitem__(self, self.index(key))
thislist = That([This("Jerry", 42), This("Amy", 36)])
thislist["Amy"].value # 36
Is there a more pythonic way to write getitem in the following?
Only slightly. __getitem__ is used by both sequences, where int's and slice's are used, and by mappings, where pretty much anything can be used. It looks like you are implementing both sequence-type and mapping-type interfaces, so you're stuck with checking type.
Missing two things:
support for slices (but only put it in if you want your That to support it)
raising an exception for failure (returning None in this case is not pythonic)
Here's an updated __getitem__:
def __getitem__(self, x):
if isinstance(x, int):
return self.this_list[x]
elif isinstance(x, slice):
return self.this_list[slice]
elif isinstance(x, str):
for this in self.this_list:
if this.name == x:
return this
return None
raise KeyError("invalid key: %r" % x)
At this point you have two possible exceptions being raised
IndexError (if x is outside the range of this_list)
KeyError (if the name is not found, or something besides str or int was passed in)
This may be fine for you, or you might want to create a custom Exception that gets returned in all cases:
class LookupError(Exception):
"x is neither int nor str, or no matching This instance found"
Here's the updated code (Python 2.x):
class LookupError(IndexError, KeyError):
"x is neither int nor str, or no matching This instance found"
class This():
def __init__(self, name, value):
self.name, self.value = name, value
class That(object):
def __init__(self):
self.this_list = []
def add_this(self, this):
self.this_list.append(this)
def __getitem__(self, x):
try:
if isinstance(x, int):
return self.this_list[x]
elif isinstance(x, slice):
return self.this_list[slice]
elif isinstance(x, str):
for this in self.this_list:
if this.name == x:
return this
raise KeyError("invalid key: %r" % x)
except (IndexError, KeyError), err:
raise LookupError(err.message)
a = This('a', 1)
b = This('b', 2)
c = That()
c.add_this(a)
c.add_this(b)
print c[1].name
print c['a'].name
try:
print c[2.0]
except LookupError, e:
print e
try:
print c['c']
except LookupError, e:
print e
You can define two private methods __getitem_int() and __getitem_str(). Then you can use getattr() to get handle to proper method depending of type(x).__name__ and call type-specific method.
See how KantGenerator.parse() is implemented in dive into python parsing xml example.

Categories