1

It looks like this:

I define a class:

class Boy():
    def __init__(self):
        self.age    = input()
        self.height = input()

Then I define a list with the names of the boys that I want to be object instances of the above 'class Boy':

boys = [input(), input()]

(for example: john & frank, so that boys = ['john', 'frank'])

I want now to iterate over my list 'boys' and use each name to make an object of the 'class Boy':

for value in boys:
    value = Boy()

Of course, it does not work :-) but is there a way to achieve it ?? I have been using Python since 1 week, if the question sounds silly :-) If someone could help me, will be very thankful

Thank you all for the help, I implemented the proposed solutions:

thank_you_people = ['Makoto','L3viathan','Rcynic','Pythonic','Paul Rooney', 'st.eve']

:-)

for person in thank_you_people:
print('Thank you, %s' % person)
Mario Christov
  • 141
  • 1
  • 8
  • 2
    You're going to want additional arguments. You don't want to be capturing `input()` on instantiation; you want that value to be provided to you before the object needs to be instantiated. – Makoto Apr 21 '15 at 22:27
  • I want to specify the values manually while creating the object instances, this is the idea. But I want to give the objects their names automatically (by looping), feeding the names into the class from a list of names. If I give the object a name manually it works perfectly, for example: john = Boy() then I enter for example 5 for age and 100 for height. then I have what I want john.age = 5; john.height = 100. But I don't want to write all the names of the boys manually, I want to automate this by a loop. Is there any possibility ? – Mario Christov Apr 21 '15 at 22:37
  • 1
    possible duplicate of [Use loop to name variables](http://stackoverflow.com/questions/22923481/use-loop-to-name-variables) – Makoto Apr 21 '15 at 22:46

5 Answers5

1

I would highly recommend changing your class up a bit, to remove input() calls from the constructor. You could use an __init__ method that has optional arguments for age and height, and a forced one for name:

class Boy():
    def __init__(self, name, age=None, height=None):
        self.age    = age
        self.height = height
        self.name   = name

You then can instantiate with a name, and assign the attributes later:

boys = [Boy(input("New boy: ")), Boy(input("New boy: "))] # e.g. "John", "Frank"
for boy in boys:
    boy.age = input("Age of",boy.name + "?")
    boy.height = input("Height of",boy.name + "?")

edit: To have the boys in a dictionary for easier access:

boys = {}
for _ in range(2):
    name = input("New boy:")
    boys[name] = Boy(name)
for boy in boys:
    boys[boy].age = input("Age of",boys[boy].name + "?")
    boys[boy].height = input("Height of",boys[boy].name + "?")
L3viathan
  • 26,748
  • 2
  • 58
  • 81
  • Thanks, L3viathan, this works as a solution, at the end i can get the values for each child with for example "boys[0].height" and "boys[1].height". But I still need to keep track of which child which number is in the list of objects "boys" (which I want to avoid). My initial desire was (I don't know if possible, as I use Python since a week) to have for each child an object whose name corresponds to the child name, so that for the child John I have an object called john, and to get the age of john I will only need to type john.age instead of boys[0].age So my initial question was more like.. – Mario Christov Apr 22 '15 at 12:11
  • Ah. Possible, although a bit hacky. This will depend on the user entering the correct name though, right? You basically want the object to be assigned to a variable of the same name that the user enters? What would be trivial, is to create a dictionary of boys, so that you can do `boys["john"].age`. I will add that to my answer. – L3viathan Apr 22 '15 at 12:14
  • (from above)...my initial question was more like could I cheat Python somehow to use/execute strings within a list as names for objects of a given class, as you cannot make an assignement of a string to a class like: 'john' = Boy() --> SyntaxError: can't assign to literal. I remember doing 'magics' like this in MATLAB with eval, so I was wondering if i can do something like (very simple example): define a list with strings ['john', 'ben'] and then use the string as name for the object john --> something like eval(''john'') = Boy()') so that Python thinks 'john' is not a string ? – Mario Christov Apr 22 '15 at 12:23
  • Yes, you can do that, but you shouldn't. In case you really want to, `locals()["john"] = Boy("john")` should work. – L3viathan Apr 22 '15 at 12:25
  • (to your 1st reply above) --> exactly, L3viathan, this is pretty much all I want and all I meant !! the user types in the names of the children and the script generates for each input an object with the same name The attributes of this object should be 'age', 'height' and so on and the values of the attributes will again be entered by the user (based on the object names) --> my idea was to make a simple GUI out of this but as I use python from last week, I don't know when I am going to make it happen :-) :-) as my ideas cause such discussions :-) :-) hehe – Mario Christov Apr 22 '15 at 12:35
  • otherwise the idea with the dictionary seems to be a decent variant in python for my wishes as many of the replies from the other guys mentioned it also. I met this locals() in the book, need to read again to get it, thanks a lot, L3viathan – Mario Christov Apr 22 '15 at 12:42
0

To not use just anything as an object name, you can use the input as keys for a dict. Something like this:

    class Boy():
        def __init__(self):
            self.age = input()
            self.height = input()

    boys = [input(), input()] # this is probably a bad idea

    b = {}
    for boy in boys:
        b[boy] = Boy()
st.eve
  • 114
  • 1
  • 4
  • thanks, st.eve, I tried it out, it works, it's almost 100% what I wanted, with your suggestion I can get the age or height of a given boy by typing the name of the dictionary and providing the name within [], e.g. b['john'].age will return me the age that I will have provided while looping. to get it to the 100% just want to ask is there anything I could modify so that I get the age of for example john with only: john.age (my initial idea) ? even if not, I am pretty thankful for your reply, as it is the simplest for me as a beginner :-) I'll check now the others :-) cheers – Mario Christov Apr 21 '15 at 23:26
  • Off the top of my head I can't think of an easy solution for your 100%. However, mixing data and code is considered a very _very_ bad idea. – st.eve Apr 21 '15 at 23:34
  • OK, :-), thanks, your answer was helpful, by the way, I assume mixing data and code = input() in the class definition, I need some time to advance in this terminology, I just started with Python last week and pretty much all looks new to me :-) – Mario Christov Apr 21 '15 at 23:39
  • It's more a problem depending on where the `input()` is written: On the right side of an assignment is OK (although not very beautiful in your example), on the left side is bad. In the best case, your user could input the same name as some internal variables, thus crashing your program. – st.eve Apr 22 '15 at 12:53
0

I'd suggest to i) use a dictionary for creating variables with the name contained in a string and ii) pass age and height as args, **kwargs or *args in the class, as already suggested by Makoto. Something along these lines:

class Boy():
    def __init__(self, name, age=0, height=0):
        self.age    = age
        self.height = height

boys = ['finn', 'jake']
ages = [16, 33]
height = [165, 120]

boys_objects = {}

for i, b in enumerate(boys):
    boys_objects[b] = Boy(age=ages[i], height=heights[i]) 
Community
  • 1
  • 1
Pythonic
  • 2,091
  • 3
  • 21
  • 34
  • class Boy(name, age=0, height=0): produces NameError: name 'name' is not defined, I guess you meant to put them inside the _init_ method: def _init__(self, age=0, height=0) then it works, I get the age of finn with boys_objects['finn'].age. it's a solution,Thanks, Pythonic. I was wondering if it is possible to use the list values to directly name the objects of the class (without a dict) so that to get the age of 'finn' I would just type finn.age (this works if I type the names manually) cause inside the list the names are strings which is unacceptable as object name, s.th. like eval in MATLAB – Mario Christov Apr 22 '15 at 01:03
  • 1) correcte on the passing of params, edited accordingly, 2) see [here](http://stackoverflow.com/questions/1373164/how-do-i-do-variable-variables-in-python) for comments on naming variables from strings – Pythonic Apr 22 '15 at 08:02
0

Don't use the input function in your __init__ method, as it restricts how your Boy class can be used. Instead define a separate function that creates a Boy and pass those parameters to your Boy constructor. Then you could store your Boys in a dict, keyed by the boys name.

e.g.

class Boy():
    def __init__(self, age, height):
        self.age    = age
        self.height = height
    def __str__(self):
        return 'age=%d height=%d' % (self.age, self.height)

def create_boy(name):
    age = int(input('enter age for %s: ' % name))
    height = int(input('enter height for %s: ' % name))
    return Boy(age, height)

boynames = []

while(True):
   name = input('enter boy name: ')      
   if name == '':
       break
   boynames.append(name)

boys = {}
for boyname in boynames:
    boys[boyname] = create_boy(boyname)

for name, boyinfo in boys.items():
    print('name=%s %s' % (name, boyinfo))

Later on you could query a particular boys name like so

if 'paul' in boys:
    print(boys['paul'].age)
    print(boys['paul'].height)
else:
    print('no boy called paul')

This isn't designed to work if you can have Boys with the same name. In that case you could have each dictionary entry hold a list of Boys and find some other parameter to distinguish between the Boys of the same name.

Paul Rooney
  • 20,879
  • 9
  • 40
  • 61
  • thanks, Paul, tried out your code and works pretty nice :-) I find the chaining between the class, function and the loops really GREAT ! thanks once again :-) – Mario Christov Apr 22 '15 at 14:18
  • No probs. feel free to accept this or one of the other answers which helped you most. – Paul Rooney Apr 25 '15 at 10:51
0

Use the zip function. You'll have to change your class constructor a little bit though.

class Boy(object):
    def __init__(self, (name, age, height)):
        self.name = name
        self.age = age
        self.height = height

Then get the input values into lists

names = ['a','b','c']
ages = [10, 20, 30]
heights = [155, 160, 165]
boys = zip(names, ages, heights)
for guy in boys:
    b = Boy(guy)
    print b.name, b.age, b.height

I don't know wha you want to do with the objects - but you can change that in the for loop.

EDIT: In response to the error OP is getting in the comments:

I cannot reproduce the init error. I tried with python and iPython both. Alternatively you could try

def __init__(self, guy_tuple):
    self.name = guy_tuple[0]
    self.age = guy_tuple[1]
    self.height = guy_tuple[2]

If that doesn't work either, you can change the constructor to take in name, age and height individually. Like is working for you.

def __init__(self, name, age, height):
    self.name = name
    ... 

then the for loop must change accordingly. Since guy is a tuple with all three elements, you'll have to get each one by index within the tuple.

for guy in boys:
    b = Boy(guy[0], guy[1], guy[2])

Yes object b will be overwritten, you'll have to change it to do what you need it to do once you get the object. So after b is instantiated, pass it to another function to do what you want with it, or append it to a list. Once b is an object, you continue with the logic you want.

Rcynic
  • 392
  • 3
  • 10
  • Hi, Rcynic, I have the follwoing problems with your suggestion: class Boy(object): def __init__(self, name, age, height) self.name = name self.age = age self.height = height raises an Exception: File "", line 2 def __init__(self, (name, age, height)): ^ SyntaxError: invalid syntax it seems that the __init__() method has some issues accepting a tuple as an argument – Mario Christov Apr 22 '15 at 11:21
  • I could rewrite it like this (without the brackets for the tuple): class Boy(object): def __init__(self, name, age, height): ... then the class definition works, but then I have a problem with the loop: for guy in boys: b = Boy(guy) print(b.name, b.age, b.height) TypeError: __init__() missing 2 required positional arguments: 'age' and 'height' in this case it seems that the __init__ method takes the tuple guy as its name argument only – Mario Christov Apr 22 '15 at 11:28
  • and the 3rd thing that confuses me: in the loop the obejct ('b') will be overwritten for each 'guy' in 'boys', won't it ? I actually need an iterator for the names of the obejcts too, so that each unique obejct name saves the data for each boy – Mario Christov Apr 22 '15 at 11:46
  • the answer to your question at the end: I wanted to have the data for each kid in a separate object and then for each attribute (e.g. height) plot all kids with the mean and then make an automatic report with reg. expr. that was the initial idea, but as I started Python last week and and I am already stuck it might take some time :-) :-) :-) – Mario Christov Apr 22 '15 at 11:59
  • I've edited the original answer addressing your comments. Hope it helps:) – Rcynic Apr 22 '15 at 16:21
  • def __init__(self, (name, age, height)): The reason why it produces a SynthaxError might probably be an issue with the Pyhton version, I don't know. I saw that you use "print b.name ..." which seems to be Python 2, I am trying with Python 3.4 from Anaconda, so there might be some change that affects the synthax ??? Otherwise, thanks a lot for your reply and additional comments, Rcynic, all was very helpful and helped me make my code better :-) – Mario Christov Apr 22 '15 at 21:47