Python throws exception on bypassing True as method parameter - python

I have the following concern - Why does the following code throw exception on param2?:
def paramcheck(param1, param2):
try:
if param1:
print('param1: ' + param1)
if param2:
print('param2: ' + param2)
except:
print('error')
paramcheck(False, True)
I'm using python 3.4.
Thanks!

If you hadn't quashed the error message you would have gotten a helpful message:
>>> param1 = True
>>> print('param1: ' + param1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'bool' objects
As the error says, you can't concatenate strings with booleans in Python. You have to convert the boolean manually:
print('param1: ' + str(param1))
Or you can use formatting operators:
print('param1: %s' % (param1,))
print('param1: {}'.format(param1))

Related

Syntax error with exec call to an object in Python 3

I really don't understand what causes the problem, could someone point it out for me please?
with shelve.open(obj_path) as obj:
for as_num in obj['as_number_list']: # ignore warning, obj['as_number_list'] is a list
temp = charge_as(obj['as_' + str(as_num)]) # temp is an object
as_test = temp # doing like this is ok
print(type(as_test))
exec("as_{}_obj = {}".format(as_num, temp)) # **error here**
And it gives syntax error like this:
<class 'instruments.AS'>
Traceback (most recent call last):
File "...", line 45, in <module>
exec("as_{}_obj = {}".format(as_num, temp))
File "<string>", line 1
as_1_obj = <instruments.AS object at 0x000002A86732E290>
^
SyntaxError: invalid syntax
I tried
exec("as_{}_obj = {}".format(as_num, temp.__dict__))
no error is shown but now as_{}_obj is of class 'dict' instead of class 'instruments.AS'
line 45:
exec("as_{}_obj = temp".format(as_num))

Python Try and Except Statements Custom and Normal Exception Output

When throwing an exception how do I get the compiler to throw my custom exception AND the compiler exception.
Here is an example of what I want to happen
def func_A(int)
try:
ans = 1 + int
print(ans)
except:
print('Oops your input was wrong')
def func_B(int)
ans = 1 + int
print(ans)
Input_A:
func_A('Hello_World')
Output_A:
'Oops your input was wrong'
Input_B:
func_B('Hello_World')
Output_B:
File "<ipython-input-5-fe7d28575c18>", line 2
def func_B(int)
^
SyntaxError: invalid syntax
Desired Output:
'Oops your input was wrong'
File "<ipython-input-5-fe7d28575c18>", line 2
def func_B(int)
^
SyntaxError: invalid syntax
Try adding a raise to the end of your except to raise the exception again, like this:
def func_A(int):
try:
ans = 1 + int
print(ans)
except:
print('Oops your input was wrong')
raise
func_A('Hello_World')
Output:
Oops your input was wrong
Traceback (most recent call last):
File "/home/ashish/s.py", line 15, in <module>
func_A('Hello_World')
File "/home/ashish/s.py", line 3, in func_A
ans = 1 + int
TypeError: unsupported operand type(s) for +: 'int' and 'str'

Distributed system: Raise error thrown on server side on client side

I have just started to create a distributed system that now got a single server and a bunch of clients. The language used is python and communication is done using sockets and JSON. When an error occurs on the server-side I send the error class-name and the error arguments to the client-side like this:
except Exception as e:
jsonResult = {"error":
{
"name":e.__class__.__name__,
"args": e.args
}
}
jsonResult = json.dumps(jsonResult)
jsonResult += "\n"
return jsonResult
And then try to raise it on the client-side like this:
errorFunc = decodedReply["error"]["name"]
args = decodedReply["error"]["args"]
print (args)
# Builds and appends the argumentstring to the error class-name.
errorFunc += '('
for arg in args:
# Handles when the argument is a string.
if isinstance(arg, str):
errorFunc += '\'' + arg + '\','
else:
errorFunc += arg + ','
# Removes the extra ',' from the string before adding the last ')'.
errorFunc = errorFunc[:-1]
errorFunc += ')'
# Debugging print.
print ("Here: " + errorFunc)
raise exec(errorFunc)
When I do this I get the error
TypeError: exceptions must derive from BaseException
From what I read here: Error exception must derive from BaseException even when it does (Python 2.7)
it looks like I have to declare it as a class. Is there anyway to get around that?
According to python you are raising something which is not an exception:
>>> type(exec("ValueError('ABC')"))
<class 'NoneType'>
You need to rewrite your code to have this:
>>> errorFunc = "ValueError('ABC')"
>>> exec('raise ' + errorFunc)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 1, in <module>
ValueError: ABC

Adding method to Python's NoneType

I'm using BeautifulSoup to do some crawling, and want to chain find calls, for example:
soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
Of course, this breaks whenever one of the divs cannot be found, throwing an
AttributeError: 'NoneType' object has no attribute 'find'
Is there a way to modify NoneType to add a find method such as
class NoneType:
def find(*args):
return None
so that I can do something like
thing = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
if thing:
do more stuff
instead of
thing1 = soup.find('div', class_="class1")
if thing1:
thing2 = thing1.find('div', class_="class2")
if thing2:
thing3 = thing2.find('div', class_="class3")
etc.
I think I might be able to do something similar by using a parser with XPath capabilities, but the question is not specific to this use case and is more about modifying/overriding built in classes.
Why not use a try/except statement instead (since you cannot modify NoneType)?
try:
thing = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
do more stuff
except AttributeError:
thing = None # if you need to do more with thing
You can't modify builtin class such as NoneType or str:
>>> nt = type(None)
>>> nt.bla = 23
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'NoneType'
For some of them (eg str), you can inherit from:
>>> class bla(str):
... def toto(self): return 1
>>> bla('2123').toto()
1
It's not possible with NoneType. And it won't help you either:
>>> class myNoneType(nt):
... def find(self): return 1
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
type 'NoneType' is not an acceptable base type
You cannot modify the class and the real question is why you would try? NoneType means there is no data there so when you attempt a .find() on that type even if it did exist you would only get null or no values from it. I would reccomend something like this.
try:
var = soup.find('div', class_="class1").find('div', class_="class2").find('div', class_="class3")
except AttributeError:
do something else instead or message saying there was no div
You can't inherit from None:
>>> class Noneish(type(None)):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'NoneType' is not an acceptable base type
An approach might be to have a
class FindCaller(object):
def __init__(self, *a, **k):
self.a = a
self.k = k
def __call__(self, obj):
return obj.find(*self.a, **self.k)
def callchain(root, *fcs):
for fc in fcs:
root = fc(root)
if root is None: return
return root
and then do
thing = callchain(soup,
FindCaller('div', class_="class1"),
FindCaller('div', class_="class2"),
FindCaller('div', class_="class3"),
)
You can't. For good reasons...
In fact, NoneType is even less accessible than other built-in types:
type(None).foo = lambda x: x
# ---------------------------------------------------------------------------
# TypeError Traceback (most recent call last)
# <ipython-input-12-61bbde54e51b> in <module>()
# ----> 1 type(None).foo = lambda x: x
# TypeError: can't set attributes of built-in/extension type 'NoneType'
NoneType.foo = lambda x: x
# ---------------------------------------------------------------------------
# NameError Traceback (most recent call last)
# <ipython-input-13-22af1ed98023> in <module>()
# ----> 1 NoneType.foo = lambda x: x
# NameError: name 'NoneType' is not defined
int.foo = lambda x: x
# ---------------------------------------------------------------------------
# TypeError Traceback (most recent call last)
# <ipython-input-14-c46c4e33b8cc> in <module>()
# ----> 1 int.foo = lambda x: x
# TypeError: can't set attributes of built-in/extension type 'int'
As suggested above, use try: ... except AttributeError: clause.

Implementing C-like assert

I'm trying to implement an assert function. How can I get the text of the failing condition into the error message? If I have to parse it from the backtrace, can I portably rely on anything about the format of frames?
AssertionError is just like any other exception in python, and assert is a simple statement that is equivalent to
if __debug__:
if not expression: raise AssertionError
or
if __debug__:
if not expression1: raise AssertionError(expression2)
so you can add a second parameter to your assertion to have additional output
from sys import exc_info
from traceback import print_exception
# assertions are simply exceptions in Python
try:
assert False, "assert was false"
except AssertionError:
print_exception(*exc_info())
outputs
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
AssertionError: assert was false
If you're sure the expression to test is secure you could do something like this:
File my_assert.py:
import sys
def my_assert(condition):
caller = sys._getframe(1)
if not eval(condition, caller.f_globals, caller.f_locals):
raise AssertionError(repr(condition) + " on line " +
str(caller.f_lineno) + ' in ' +
caller.f_code.co_name)
File test_my_assert.py:
from my_assert import my_assert
global_var = 42
def test():
local_var = 17
my_assert('local_var*2 < global_var') # OK
my_assert('local_var > global_var')
test()
Output:
Traceback (most recent call last):
File "test_my_assert.py", line 10, in <module>
test()
File "test_my_assert.py", line 8, in test
my_assert('local_var > global_var')
File "my_assert.py", line 8, in my_assert
caller.f_code.co_name)
AssertionError: 'local_var > global_var' on line 8 in test
My very hackish solution:
def my_assert(condition):
if not eval(condition):
# error stuff
Then use it by placing the condition in quotation marks. It is then a string that can be printed in the error message.
Or, if you want it to actually raise an AssertionError:
def my_assert(condition):
if not eval(condition):
raise AssertionError(condition)

Categories

Resources