2

I have made a simple, test program to experiment using classes. It creates a "person" class, which takes the arguments of name and age. I am now trying to create an interactive program that allows the user to manage a list of people, like a register or address book. They can create a new person, as shown in the function below.

def createnew():
    newname = input("What is their name?")
    newage = input("How old are they?")

    newperson = Person(newname, newage)

Of course the problem with the above is it assigns newname literally rather than the string value of "newname". So I tried

newperson.lower() = Person(newname, newage)
str(newperson) = Person(newname, newage)
newperson[0:] = Person(newname, newage)

but they all return the error, can't assign to function call. My question is how do I access the value of the variable newname and assign it to the Person, or any other class.

Note: I am a n00b/newb, meaning I have not come from another language, and am following a book. Please explain any answers given if they are not ridiculously obvious.

Many Thanks.

To make it slightly clearer, I am trying to make the user-inputted value for the new person's name the object name ( in my example it is newperson )

Update:

Thanks for all the answers, I gather it's not a great idea to allow the user to set variable names so I re-jigged my code. I made a dictionary which after the user has created a new person, writes the data given by the class str function to the key of the given name. While this means I can't then access the object later on, because newperson will have been overwritten, it allows me to build a list of people with a set of data which is what I wanted to do in the first place, I just mistakingly thought it would be easier to set the object name. Thanks again.

user1276048
  • 43
  • 1
  • 5

4 Answers4

5

If I understand you correctly, what you want is to create the Person object, then create a global variable with the name being the name of the person.

This is bad.

What you really want is a way to store people objects and retrieve them later by their names. So, use a dictionary:

people = {}

def createnew():
    ...
    people[newname] = Person(newname, newage)

Then later, you can access the Person in the dictionary:

print(people['name of the person'])

(I'm assuming that you're using Python 3, since you're using input() rather than raw_input() as in Python 2.x)

If you really must create a new variable (which is bad, since people's names aren't usually valid Python identifiers), use the globals() function:

>>> globals()['foo'] = 2
>>> foo
2

but I include this for the sake of completeness. Don't use this!

li.davidm
  • 11,736
  • 4
  • 29
  • 31
  • 3
    @user1276048, You don't want to do that. No, seriously. Don't do that. Don't ever do that. Under no circumstances should you be trying to use user input as the name of a variable. This answer is the correct approach to what you are trying to do it. – Winston Ewert Mar 17 '12 at 18:53
  • 2
    @user1276048: yes, that's what the person who wrote this answer thinks you meant. It is not a good idea. It complicates your life. You need to distinguish how you, as the programmer, think about the data from how the user thinks about the data. Having created the new `Person`, you need to know what it's called in order to write more code that uses it. If the user is in control of the variable name, you're kinda stuck. The user's information is already stored within the object. You don't need it to be reflected in the variable name. **That's not what variables are for**. – Karl Knechtel Mar 17 '12 at 20:41
1

Are you using Python 2 or Python 3? I'm guessing that maybe your book is written for Python 3 and you are using Python 2. I think your first program should work in Python 3, but in Python 2 the input function probably doesn't do what you expect it to. The raw_input function would be better. Let me know which version of Python you're using and I'll try to give you more specific help. You should see the version number any time you start the Python interpreter or when you run python -V at a command-line.

This version of your code should work in Python 2:

def createnew():
    newname = raw_input("What is their name?")
    newage = int(raw_input("How old are they?"))

    person = Person(newname, newage)

I changed input to raw_input. As voithos suggests below, I used the "int" function to convert the input (with is a string) into an integer number. I also changed the last line to store the Person instance in a new variable person instead of newname, because it can be quite confusing to re-use the same variable for two different types of value.


The reason input gives you surprising results becomes clear if you check the documentation for that function:

http://docs.python.org/library/functions.html#input

It reads input and then tries to evaluate it as a Python expression! When you type in a name you get an error because it's not a variable name. Because this is quite surprising and not often what you actually want, in Python 3 they changed it, but it does mean that books and tutorials for Python 2 and 3 need to be different, and can itself result in some confusion.

Weeble
  • 17,058
  • 3
  • 60
  • 75
  • To be more precise, in Python 2 `raw_input()` grabs a _string_ representation of the input, without modifying it (hence the "raw"). `input()`, on the other hand, is basically equivalent to `eval(raw_input())`, meaning that it tries to evaluate the string as a Python expression. So, if the input was a number like '31', then `input()` would return an int. If it was something like '5.4', it would return a float, etc. It's usually more readable and less error-prone to just convert type manually, a la `int(raw_input())` – voithos Mar 17 '12 at 18:07
  • I don't think I made myself very clear, I was trying to use the value assigned to newname as the name for the class. So, if I have Bob as the name for the input it would then create Bob as an object, of the class Person. – user1276048 Mar 17 '12 at 18:38
0

I'm not entirely sure what the problem is, but the code you show has some inconsistencies.

  • newname is a reference to a string object, you then bind this reference to a Person object in the last line. This is bad design because it confuses the reader. Better call your Person object something different, for example newPerson = Person( ... ).
  • newname.lower() calls the lower() function on the newname object - that would work if newname still was a string, but now it is a Person. Have you defined a def lower(self) member function in the Person class? How does the class look like?
  • str(newname) is a noop if newname is still a string. If it is a Person object you have to define a def __str__(self) member function that returns a string representation of your Person.

All in all I'm unsure what you really want, but a Person class might look like this:

class Person(object):
    def __init__(self):
        self.name=raw_input("What is their name? ").capitalize()
        self.age=int(raw_input("How old are they? "))

    def __str__(self):
        return "My name is %s and I'm %d years of age." % (
            self.name, self.age)

Usage:

p=Person()
print p

Sidenote: It's maybe a bad design to use raw_input inside of __init__, and the __str__ function might better return Person(name=%s, age=%d) % ..., but then this is just an example how it works.

hochl
  • 12,524
  • 10
  • 53
  • 87
  • I don't think I made myself very clear, I was trying to use the value assigned to newname as the name for the class. So, if I have Bob as the name for the input it would then create Bob as an object, of the class Person. And thanks for your example class, but I already have a similar one. – user1276048 Mar 17 '12 at 18:39
0

All of those function calls return values instead of variables, so they can't be altered. In math terms, its like trying to say 2 = 7 + 4. Since 2 isn't a variable and can't really be assigned/changed that way, it doesn't make much sense to do that and the poor interpreter is giving you its tragic plea for help. Variables on the other hand, as you probably already know, can be assigned that way in the form of x = 7 + 4. Changing the value contained in the variable x is perfectly fine because variables contain values, but trying to change the value of another value is impossible.

What you need to do is find the variable you want to change, put it to the left of the equals sign, and put the value you want to assign to it on the right side. When you say Person(newname, newage), you are creating a value, in this case an object, that needs to be assigned to a variable so it can be kept and used later on instead of just discarded instantly:

def createnew():
    newname = input("What is their name?") #remember to indent these if you want them 
    newage = input("How old are they?")    #to be part of the function!
    newPerson = Person(newname, newage) 
    return newPerson

Now that newPerson contains the value of the person you just created, you can access the variables inside it and assign their values just like any other. In order to do this, you need to know the names of the variables used, which are defined in the constructor you wrote that probably looks something like this:

class Person:
    def __init__(self, name, age):
        self.name = name      #the variable that contains the person's name is called 'name'
        self.age = age       #the variable that contains the person's age is called 'age'

def createnew():
    newname = input("What is their name?") #remember to indent these if you want them 
    newage = input("How old are they?")    #to be part of the function!
    newPerson = Person(newname, newage) 
    return newPerson

newperson = createnew() #will prompt you to enter name and age for this person and assign them

print( "person's old name: " + newperson.name )    
newperson.name = input("What's is their new name?") #second thought, you want to change Bob's name
print( "person's new name: " + newperson.name )
Gordon Gustafson
  • 40,133
  • 25
  • 115
  • 157
  • I think you understood what I wanted better than most, however is there a way so the user can assign the class object name thingy, in your example it is newperson. Thats what I have been trying to do. – user1276048 Mar 17 '12 at 18:40
  • How can I allow the user to set what "newperson" is, when you say newperson = Person(newname, newage) – user1276048 Mar 17 '12 at 18:49
  • @user1276048 If you're reffering to the name of the variable, the end user has no control over it whatsoever. When your program gets interpreted/ran, all the text that makes up the variable names is erased and converted to addresses in memory. The variable's name is just a shorthand so you as the programmer can refer to that address it's converted to and the value stored in it. You can't change the variable's name, but you can store their values and retrieve them as needed as others have suggested, which is probably what you really wanted to do. :D – Gordon Gustafson Mar 19 '12 at 00:57