Python String and Instance Object confusion - python

Inside a class, in the __repr__ constructor, python is confused about what is a string and what isn't. This is for a school project, don't worry, I won't actually be handling social security numbers here.
The code below does not work:
def __repr__(self):
return (
'\nName:\t'+self.getName()+':\t\t\tNurse\n'+
'\tPhone:\t\t\t\t\t\t('+str(self.getPhoneNumber())[0:3]+') '+
str(self.getPhoneNumber())[3:6]+'-'+str(self.getPhoneNumber())[6:10]+'\n'+
'\tOverseeing Doctor:\t\t\t'+self.getDoctor()+'\n'
'\tDescription:\t\t\t\t'+self.getDesc()+'\n'+
'\tBirthday:\t\t\t\t\t'+self.getBDay()+'\n'+
'\tSocial Security Number:\t\t***-**-'+str(round(self.getSocial()))[5:9]+'\n'+#error is in this line
str(self._cases[i] for i in range(len(self._cases)))
)
However, in a different class, I have nearly identical code that does work:
def __repr__(self):
return (
'\nName:\t'+self.getName()+':\t\t\tDoctor\n'+
'\tPhone:\t\t\t\t\t\t('+str(self.getPhoneNumber())[0:3]+') '+
str(self.getPhoneNumber())[3:6]+'-'+str(self.getPhoneNumber())[6:10]+'\n'+
'\tDepartment:\t\t\t\t\t'+self.getDepartment()+'\n'
'\tDescription:\t\t\t\t'+self.getDesc()+'\n'+
'\tBirthday:\t\t\t\t\t'+self.getBDay()+'\n'+
'\tSocial Security Number:\t\t***-**-'+str(self.getSocial())[5:9]+'\n'+
str(self._cases)+'\n'
)
Please tell me what is different between the two, and how to fix the initial code.

You claim there is an error in this part:
str(round(self.getSocial()))[5:9]
but did not tell us anything about your actual error; errors come with tracebacks and exception messages, but without those details we cannot tell you anything about what might go wrong there. Perhaps self.getSocial() returns a string, and round() only takes floating point numbers:
>>> round('123')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a float is required
You'll need to give us that error message as well as your inputs (the return value of self.getSocial()) and the expected output so we can help you solve that part; perhaps you misunderstood what round() does.
Next, you are trying to convert a generator expression to a string:
str(self._cases[i] for i in range(len(self._cases))
Everything between the parentheses is a lazy evaluating loop, but str() won't evaluate it for you.
If you wanted to produce a string of all cases, joined together with, say, tabs, use str.join() instead:
'\t'.join([str(self._cases[i]) for i in range(len(self._cases)])
You really should look into using str.format() templating; it'll make for much improved and readable code. Your 'working' example would translate to:
def __repr__(self):
phone = str(self.getPhoneNumber())
social = str(self.getSocial())
return (
'\n'
'Name:\t{name}:\t\t\tDoctor\n'
'\tPhone:\t\t\t\t\t\t({phone1}) {phone2}-{phone3}\n'
'\tDepartment:\t\t\t\t\t{dept}\n'
'\tDescription:\t\t\t\t{desc}\n'
'\tBirthday:\t\t\t\t\t{bday}\n'
'\tSocial Security Number:\t\t***-**-{social}\n'
'{cases}\n').format(
name=self.getName(),
phone1=phone[:3], phone2=phone[3:6], phone3=phone[6:10],
dept=self.getDepartment(), desc=self.getDesc(),
bday=self.getBDay(), social=social[5:9],
cases=self._cases)

Related

Python - Function - Argument said to be "undefined"

I'm currently taking a Python course, and got to the chapter in our book that talks about functions. (Please note, this is my first time learning any programming.)
One of the exercises I'm working on at the moment asks for me to turn a bunch of conditional statements into a function (i.e. generalization).
To make this brief, my problem is this:
After I define a function, let's say like so...
def count_letter(letter,string):
count = 0
for letter in string:
count += 1
print(count)
(That is the work, as far as I can recall, for what I typed up for the problem.)
I run the program, then call the function in the shell as usual...
(Example directly below)
>>> count_letter(a,bananana)
And I get the following output...
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
count_letter(a,bananana)
NameError: name 'a' is not defined
My teacher and everyone in our class can't figure out why we're getting such an error. We would understand if it was some other type of an error, but having the shell tell us an argument is 'undefined' (i.e. a variable, as we understand the error) is something we haven't been able to figure out.
We've been staring at the code for a week and still can't figure it out.
Any help would be very appreciated.
Afterthought: I'm trying to count the number of "a"s within "bananana" in the example. Thought I should clear the ambiguity there.
As written, a and bananana are the names of variables which should be defined in a similar way you defined the variable count. For example:
>>> character_to_search = 'l'
>>> text = 'Hello World'
>>> count_letter(character_to_search, text)
would be a correct syntax, because both character_to_search and text are undefined.
Another possibility is that instead of using actual variables, your intention was to pass strings directly to the function. In this case, your syntax is slightly incorrect. It should be (note the single quotes):
count_letter('a', 'bananana')

__class_ data member in python, how it is different from static data member in java

i am trying to execute following code to understand Class data member in python, but it is throwing StopIteration error,
class PizzaShop():
pizza_stock = 10
def get_pizza(self):
while not PizzaShop.pizza_stock:
PizzaShop.pizza_stock -= 1
yield "take yours pizza order, total pizzas left {}".format(PizzaShop.pizza_stock)
mypizza_shop = PizzaShop()
pizza_order = mypizza_shop.get_pizza()
print "{}".format(repr(pizza_order.next()))
i am expecting that it should first print some message and then any exception
i am using python 2.7, ubuntu 32bits os
output:
Traceback (most recent call last):
File "/home/scott/pythonfiles/core_python/pizza.py", line 10, in <module>
print "{}".format(repr(pizza_order.next()))
StopIteration
The problem is this line
while not PizzaShop.pizza_stock:
This will stop immediately if pizza_stock is nonzero. Which it always is. You probably intended to write
while PizzaShop.pizza_stock:
Anyway, if you want to find the details on how values, classes, etc. behave in Python, you should check the docs. It's very different from Java.
P.S. The following is unnecessary as str.format has a shorthand for calling repr. Also, you shouldn't call magic methods like .next directly. Use the builtin next() instead.
print "{}".format(repr(pizza_order.next()))
Should be
print "{!r}".format(next(pizza_order))

What is the difference between syntax error and runtime error?

For example:
def tofloat(i):
return flt(i)
def addnums(numlist):
total = 0
for i in numlist:
total += tofloat(i)
return total
nums = [1 ,2 ,3]
addnums(nums)
The flt is supposed to be float, but I'm confused whether it is a syntax error or a runtime error.
Actually, it is a runtime error, because Python will try to resolve the flt name during runtime (because it's a dynamic language), and it won't find it. When this happens, Python yields and exception saying that it couldn't find the symbol you were using flt and all this happens at runtime.
Syntax errors happen when the interpreter find something not compelling with Python's syntax. For example: The Python's grammar doesn't recognize the input syntax as a valid Python program. This may happen when:
You forgot to add : at the end of an if, def, class, etc expression
You forgot to close some parenthesis or brackets, etc.
A lot of places else when you don't adhere to python's grammar :)
In your example, there is nothing wrong with the grammar. For the interpreter, flt(i) is a very valid call to a flt method which had to be check at runtime within the scopes if it really exists. So the interpreter won't complaint and the syntax of your problem is good.
Actually, this can be seen as a disadvantage over compiled languages like C#, C++, etc. This kind of errors can be detected sooner at compile time, and the compiler screams loud when it find it so you can notice it.
With dynamic languages, you won't notice this until the actual method is called. Your program is simple, so you may find it quick. But, what about the missing o in float was inside some legacy framework within a subclass of a subclass of a class, as a property, inside some other module, etc. That would be harsh :)
UPDATE: The execution model in Python's docs are a great read if you're into how does Python internals works. This will clarify your doubt further and will give you a lot of knowledge :)
Hope this helps!
SyntaxError is raised by parser when it founds that your syntax is not correct, like missing colons, parenthesis, invalid statements etc. It'll not allow you to execute your code until you don't fix that the issue.
Your code will throw only error at runtime, i.e when the function tofloat(i) is called for the first time, so it is a runtime error. Specifically NameError.
Also a runtime error won't stop your program's execution until that buggy part is not executed. So, your code can actually run fine if you don't call tofloat ever.
The code below executes properly up to third line but then stops as NameError is raised.(a runtime error)
print 1
print 2
print 3
print foo
output:
1
2
3
Traceback (most recent call last):
File "so.py", line 4, in <module>
print foo
NameError: name 'foo' is not defined
This code won't execute as we made a SyntaxError, even though the first 3 lines are perfectly okay:
print 1
print 2
print 2
print (foo
Output:
$ python so.py
File "so.py", line 5
^
SyntaxError: invalid syntax
Note that there's also a RunTimeError in python, which is raised when an error is detected that doesn't fall in any of the other categories
You have a NameError, Your code should read:
def tofloat(i):
return float(i)
There is no flt method in Python, that is why it is not working for you.
Incidentally, you really don't need to wrap that float casting into a function, and your whole code can be written as:
def addnums(numlist):
return sum(map(float, numlist))
Using it:
>>> addnums(range(4))
6.0

What is the proper python way to write methods that only take a particular type?

I have a function that is supposed to take a string, append things to it where necessary, and return the result.
My natural inclination is to just return the result, which involved string concatenation, and if it failed, let the exception float up to the caller. However, this function has a default value, which I just return unmodified.
My question is: What if someone passed something unexpected to the method, and it returns something the user doesn't expect? The method should fail, but how to enforce that?
It's not necessary to do so, but if you want you can have your method raise a TypeError if you know that the object is of a type that you cannot handle. One reason to do this is to help people to understand why the method call is failing and to give them some help fixing it, rather than giving them obscure error from the internals of your function.
Some methods in the standard library do this:
>>> [] + 1
Traceback (most recent call last):
File "", line 1, in
TypeError: can only concatenate list (not "int") to list
You can use decorators for this kind of thing, you can see an example here.
But forcing parameters to be of a specific type isn't very pythonic.
Python works under the assumption that we are all intelligent adults that read the documentation. If you still want to do it, you should not assert the actual type, but rather just catch the exception when the argument does not support the operations you need, like that:
def foo(arg):
try:
return arg + "asdf"
except TypeError:
return arg
What does the default value have to do with it? Are you saying you want to return the default value in the case where the caller doesn't pass a str? In that case:
def yourFunc( foo ):
try:
return foo + " some stuff"
except TypeError:
return "default stuff"
Space_C0wb0y has the right answer if you want to return the arg unmodified if it's not a string, and there's also the option of making an attempt to convert something to a string:
def yourFunc2( bar ):
return str(bar) + " some stuff"
Which will work with a lot of different types.

need help-variable creation in Python (continuation)

That was helpful kgiannakakis.
I'm facing a problem as below:
a = ['zbc','2.3']
for i in range(0,5):
exec('E%d=%s' %(i,a[i]))
This results in:
Traceback (most recent call last):
File "", line 2, in
exec('E%d=%s' %(i,a[i]))
File "", line 1, in
NameError: name 'zbc' is not defined
It looks like the code you're generating expands to:
E0=zbc
E1=2.3
At the next iteration through the loop, you'll get an IndexError exception because a is only two elements long.
So given the above, you are trying to assign the value of zbc to E0. If zbc doesn't exist (which it seems that it doesn't), then you will get the NameError you mention.
It's hard to determine what you're actually trying to do with this code, so I'm not sure what to recommend. You could assign strings instead:
exec('E%d="%s"' %(i,a[i]))
This would expand to:
E0="zbc"
E1="2.3"
You would still get the IndexError because your array a is not 5 elements long. That should be an easy fix for you.
Okay. this code is very weird.
As a one liner like this, it's not syntactically correct, but I suspect you're missing line breaks for some reason. But then it becomes
a = ['zbc','2.3']
for i in range(0,5):
exec('E%d=%s' %(i,a[i]))
But that will result in an index error on the reference to a[i] as shown:
>>> a
['zbc', '2.3']
>>> for i in range(0,5):
... print a[i]
...
zbc
2.3
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
IndexError: list index out of range
If you avoided that issue, you'd get
exec("E2.3=1")
on the second pass through the lopp, and that's a syntax error too.
It seems you are trying to use the solution marked in this question.
If your goal is access values in a loop, you should just use a list. This weird concept of variable names with numbers in them is not one that should be used in any language. Try this.
vals = ['foo', 'bar', 'blah', 67, -0.4, 'your mom']
for i in range(len(vals)):
print(vals[i])
That is the correct way to have a list of values indexed by an integer, not putting it in the variable name.
Just keep in mind that 'exec' executes whatever string you pass in to it as if you typed it in your .py file or the interpreter.
When debugging exec() related code, it's helpful to log whatever you're about to 'exec' when you run into trouble, if you did that you'd easily have noticed that E0 wasn't being assigned to the string "zbc" but to the non-existent object zbc.
Aside from that, this code sample is really weird.  There are some legitimate uses for parsing strings into instance variables, or objects in other namespaces, most notably when you're coding a highly dynamic class that needs to do sensible stuff with messy input, or needs to setup a bunch of instance variables from a dict or string.  But without context, the code in your question looks like you're avoiding, or don't understand how, to use list() and dict() objects..
I'd recommend telling a bit more about what you're trying to achieve next time you ask a question around something as peculiar as this.  That would give people a good opportunity to suggest a better solution, or –if you're approaching a particular problem in a completely sensible way– prevent a bunch of answers telling you that you're doing something completely wrong.

Categories

Resources