From the docs, all is equivalent to:
def all(iterable):
for element in iterable:
if not element:
return False
return True
Then why do I get this output:
# expecting: False
$ python -c "print( all( (isinstance('foo', int), int('foo')) ) )"
Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'
When:
# expecting: False
$ python -c "print( isinstance('foo', int) )"
False
One (fairly ugly) way to get the behaviour you want is via lambdas:
all(f() for f in (lambda: isinstance('foo', int), lambda: int('foo')))
Arguments are evaluated before calling a function. In this case first you have to create the tuple you pass to all.
all never had a chance to check them, the exception was thrown before that.
>>> int('foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: invalid literal for int() with base 10: 'foo'
Your intuition regarding all is correct; you only need to work a little harder to set up a lazy sequence. For example:
def lazy():
yield isinstance("foo", int) # False
yield int("foo") # raises an error, but we won't get here
>>> all(lazy())
False
>>> list(lazy())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in lazy
ValueError: invalid literal for int() with base 10: 'foo'
If the desire to stop evaluation after the first False condition is specifically to perform type checking, something like this will work better:
if not isinstance(other, MyClass):
return False
else:
return all((self.attr1 == other.attr2,
self.attr2 == other.attr2)) # etc.
Simplified version from #catchmeifyoutry:
return isinstance(other, MyClass) and all((self.attr1 == other.attr2,
self.attr2 == other.attr2)) # etc.
Related
What I want to do
I would like to fix my current code to pass the coding challenge, Codewars Prefill an Array.
I hope to learn how to throw TypeError with message with if statement in this case.
Create the function prefill that returns an array of n elements thatall have the same value v. See if you can do this without using a loop.
You have to validate input: v can be anything (primitive orotherwise) if v is ommited, fill the array with undefined if n is 0, return an empty array if n is anything other than an integer or integer-formatted string (e.g. '123') that is >=0, throw a TypeError
When throwing a TypeError, the message should be n is invalid, where
you replace n for the actual value passed to the function.
Code Examples
prefill(3,1) --> [1,1,1]
prefill(2,"abc") --> ['abc','abc']
prefill("1", 1) --> [1]
prefill(3, prefill(2,'2d'))
--> [['2d','2d'],['2d','2d'],['2d','2d']]
prefill("xyz", 1)
--> throws TypeError with message "xyz is invalid"
Problem
I have passed 4 sample tests among 5 sample tests, but I cannot pass the below one.
prefill("xyz", 1)
--> throws TypeError with message "xyz is invalid"
Error Message
Traceback (most recent call last): File "main.py", line 8,
in <module> prefill('xyz', 1) File "/home/codewarrior/solution.py",
line 3, in prefill if int(n): ValueError: invalid literal for int() with base 10: 'xyz'
Current code
def prefill(n,v):
if int(n):
result = [0] * int(n)
for i in range(len(result)):
result[i] = v
return result
else:
return TypeError, str(n) + "is invalid"
Developing Environment
Python 3.4.3
You can use a try-except to catch the error, and throw for example another one:
def prefill(n,v):
try:
n = int(n)
except ValueError:
raise TypeError("{0} is invalid".format(n))
else:
return [v] * n
For example:
>>> prefill(3,1)
[1, 1, 1]
>>> prefill(2,"abc")
['abc', 'abc']
>>> prefill("1", 1)
[1]
>>> prefill(3, prefill(2,'2d'))
[['2d', '2d'], ['2d', '2d'], ['2d', '2d']]
>>> prefill("xyz", 1)
Traceback (most recent call last):
File "<stdin>", line 1, in prefill
ValueError: invalid literal for int() with base 10: 'xyz'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 1, in prefill
TypeError: xyz is invalid
You do not per se need to specify an exception to raise. In case you want to re-raise the exception, simply writing raise is sufficient. You can furthermore specify a tuple of exceptions to catch, and make v optional here, for example:
def prefill(n,v=None):
try:
n = int(n)
except (TypeError, ValueError):
raise TypeError("{0} is invalid".format(n))
else:
return [v] * n
Use the raise keyword to raise an exception, rather than return it. raise is used to generate a new exception:
>>> raise TypeError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError
In this example I raised the TypeError by using the exception class directly. You can also create instances of the error like this:
>>> t=TypeError()
>>> raise t
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError
Doing it that way allows various properties to be set on the object before using raise. The problem posted includes this requirement:
When throwing a TypeError, the message should be n is invalid, where you replace n for the actual value passed to the function.
That is an example of a situation where it is necessary to create an instance of the error and set a message property on it before using raise. That can still be done in one line:
>>> raise TypeError("foo")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: foo
To catch exceptions, use a try-except block, rather than an if block:
x = 'hello, world!'
try:
y = x / 2
except TypeError as e:
e.args = (*e.args, str(x) + " is not valid")
raise
This will raise an error:
TypeError: ("unsupported operand type(s) for /: 'str' and 'int'", 'hello, world! is not valid')
note that you can check the datatype of a variable using type():
>>> x = 5
>>> type(x)
<class 'int'>
>>> if type(x) == int:
... print("it's an int")
...
it's an int
Also, the code sample could be simplified to:
return [v for _ in range(n)]
What to do with functions which are numerically valid, but physically out of range?
The reason, I would like my programm to tell me and stop, if the physically correct range is left.
I thought about using the ValueError exception for this error handling.
Example:
def return_approximation(T):
#return T only if it is inbetween 0 < T < 100
return T
Python has the assert-statement for this kind of argument restrictions.
def return_approximation(T):
assert 0 < T < 100, "Argument 'T' out of range"
return T
You should raise an exception called ValueError.
if 0 < T < 100:
raise ValueError('T must be in the exclusive range (0,100)')
I'm not sure about what you mean by physically.
Generally speaking, if the out-of-range error is caused by external data, you're supposed to raise an exception; if the error comes from your own data, you may use assert to abort the current execution.
You can simply, restrict the returned value to T if it matches your conditions else return None, like so:
>>> def f(T):
return T if 0 < T < 100 else None
>>> f(100)
>>> f(99)
99
>>> f(0)
>>> f(1)
1
EDIT: solution with exceptions:
>>> def f(T):
if 0 < T < 100:
return T
else:
raise ValueError
>>> f(100)
Traceback (most recent call last):
File "<pyshell#475>", line 1, in <module>
f(100)
File "<pyshell#474>", line 5, in f
raise ValueError
ValueError
>>> f(99)
99
>>> f(0)
Traceback (most recent call last):
File "<pyshell#477>", line 1, in <module>
f(0)
File "<pyshell#474>", line 5, in f
raise ValueError
ValueError
>>> f(1)
1
You can even output your own message for more clarity:
>>> def f(T):
if 0 < T < 100:
return T
else:
raise Exception('T is out of Range')
>>> f(100)
Traceback (most recent call last):
File "<pyshell#484>", line 1, in <module>
f(100)
File "<pyshell#483>", line 5, in f
raise Exception('T is out of Range')
Exception: T is out of Range
I was trying to understand a recursive function and in order to do that I felt like I needed to create a smaller example for myself. My own code, however, is throwing me a NoneType error. I don't really have a purpose with my function, I just want to know why the error occurs?
def recursive(seq):
if not seq:
return [seq]
else:
seq2=seq[1:]
print('seq2= ',seq2)
print('Type seq2 = ',type(seq2))
for i in recursive(seq2):
print('hi')
Input:
recursive('123')
Output:
seq2= 23
Type seq2 = <class 'str'>
seq2= 3
Type seq2 = <class 'str'>
seq2=
Type seq2 = <class 'str'>
hi
Traceback (most recent call last):
File "<pyshell#12>", line 1, in <module>
recursive('123')
File "C:/Python34/myreqursive(del).py", line 8, in recursive
for i in recursive(seq2):
File "C:/Python34/myreqursive(del).py", line 8, in recursive
for i in recursive(seq2):
TypeError: 'NoneType' object is not iterable
Your else branch doesn't return anything, so the default return value None is given instead.
Rather than just print, at least return the recursive result:
def recursive(seq):
if not seq:
return [seq]
else:
seq2=seq[1:]
print('seq2= ',seq2)
print('Type seq2 = ',type(seq2))
recursive_result = recursive(seq2)
for i in recursive_result:
print('hi')
return recursive_result
In the code below, s refers to a string (although I have tried converting it to a list and I still have the same problem).
s = "".join(s)
if s[-1] == "a":
s += "gram"
I the last item in the string is the letter "a", then the program needs to add the string "gram" to the end of the string 's' represents.
e.g. input:
s = "insta"
output:
instagram
But I keep getting an IndexError, any ideas why?
If s is empty string s[-1] causes IndexError:
>>> s = ""
>>> s[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Instead of s[-1] == "a", you can use s.endswith("a"):
>>> s = ""
>>> s.endswith('a')
False
>>> s = "insta"
>>> s.endswith('a')
True
If s is empty, there is no last letter to test:
>>> ''[-1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IndexError: string index out of range
Use str.endswith() instead:
if s.endswith('a'):
s += 'gram'
str.endswith() does not raise an exception when the string is empty:
>>> 'insta'.endswith('a')
True
>>> ''.endswith('a')
False
Alternatively, using a slice would also work:
if s[-1:] == 'a':
as slices always return a result (at minimum an empty string) but str.endswith() is more self-evident as to what it does to the casual reader of your code.
e.g. I defined an function which needs several input arguments, if some keyword arguments not being assigned, typically there be an TypeError message, but I want to change it, to output an NaN as the result, could it be done?
def myfunc( S0, K ,r....):
if S0 = NaN or .....:
How to do it?
Much appreciated.
Edited:
def myfunc(a):
return a / 2.5 + 5
print myfunc('whatever')
>python -u "bisectnewton.py"
Traceback (most recent call last):
File "bisectnewton.py", line 6, in <module>
print myfunc('whatever')
File "bisectnewton.py", line 4, in myfunc
return a / 2.5 + 5
TypeError: unsupported operand type(s) for /: 'str' and 'float'
>Exit code: 1
What I want is, the myfunc(a) only accpets an number as the input, if some other data type like a string = 'whatever' inputed, I don't want to just output an default error message, I want it to output something like return 'NaN' to tell others that the input should be an number.
Now I changed it to this, but still not working,
btw, is none the same as NaN? I think they're different.
def myfunc(S0):
if math.isnan(S0):
return 'NaN'
return a / 2.5 + 5
print myfunc('whatever')
>python -u "bisectnewton.py"
Traceback (most recent call last):
File "bisectnewton.py", line 8, in <module>
print myfunc('whatever')
File "bisectnewton.py", line 4, in myfunc
if math.isnan(S0):
TypeError: a float is required
>Exit code: 1
Thanks!
You can capture the TypeError and do whatever you want with it:
def myfunc(a):
try:
return a / 2.5 + 5
except TypeError:
return float('nan')
print myfunc('whatever')
The Python Tutorial has an excellent chapter on this subject.
def myfunc(S0 = None, K = None, r = None, ....):
if S0 is None or K is None or r is None:
return NaN
Yes, to generate a NaN you do float('nan'):
>>> import math
>> float('nan')
nan
>>> math.isnan(float('nan'))
True
So you can return float('nan') wherever you want to return the nan. I recommend you just raise the exception, though.
If you don't want to use TypeError, then how about using AttributeError?
def myfunc(a):
try:
return a / 2.5 + 5
except AttributeError:
return float('nan')
print myfunc('whatever')