0

Preface: I've spent many HOURS trying to read similar posts like this one and try lots of different things, but for the life of me, I can't understand what I'm doing wrong, or why this doesn't work. Can someone please give me an ELI5 answer as to either what I'm doing wrong, or why this doesn't work the way I'm expecting?

class User:

    def __init__(self, first, last, age):
        self.firstname = first
        self.lastname  = last
        self.age       = age


dict = {
    'User1': {'id': 'id001', 'firstname': 'User', 'lastname': 'One', 'age': 11},
    'User2': {'id': 'id002', 'firstname': 'User', 'lastname': 'Two', 'age': 22},
    'User3': {'id': 'id003', 'firstname': 'User', 'lastname': 'Three', 'age': 33}
}


for user in dict:
    u    = dict[user]
    user = User(u['firstname'], u['lastname'], u['age'])


try:
    print(User1.lastname)
except Exception as e:
    print(e)
finally:
    print(user.lastname)

Which returns:

name 'User1' is not defined
Three

Clearly user is getting instantiated three times with the data from dict, with User3's data being the last of it.

If I do a:

for user in dict:
    print(user)

it prints out:

User1
User2
User3

So my expectation would be that the for loop would run, and then I'd be able to call User1.firstname, User2.lastname, or User3.age, and it'd give me the same data that's in dict (User, Two, 33, respectively), but that's clearly not the case.

Help?

6
  • 3
    Don't use dict as an object name. That is a built in module. Change it to something like dict1. Commented Jun 1, 2018 at 19:54
  • 2
    You do not have a variable named User1. You have a key in a dictionary with that name, and can access that user's variables with print(dict['User1']['lastname']. There is a not a good way in python to convert a dictionary key directly to a variable/class name without eval (don't use eval), meaning there is not a good way to get a variable called User1 unless you manually say User1 = User(...). If you want your users in classes, you can make a dictionary or list of users as g.d.d.c. has done. Commented Jun 1, 2018 at 19:58
  • @Rthomas529 yeah, poor use in my example. thanks. Commented Jun 1, 2018 at 20:14
  • 1
    @jeremysprofile gotcha, and that's what I was trying to achieve - having the key be the object's name, which clearly doesn't work and/or isn't easy to do. Still learning... Commented Jun 1, 2018 at 20:15
  • @thisAaronMdev, it's not necessarily that it doesn't work, it's that it's the wrong way to think about it. You want your program to be able to handle all users, not just User3. If you want to do something special with a certain user, you can add a self.userid field to your User class, and then when you're looping through your list with of for user in users you can check if user.userid == User3. Commented Jun 1, 2018 at 20:24

2 Answers 2

2

You're not storing the instances you create.

for user in dict:
    u    = dict[user]
    user = User(u['firstname'], u['lastname'], u['age'])

^^ Create a bunch of User's, but assign each one to the same name, user. That means that users 1 and 2 are lost as as you continue iterating through your loop.

If you want to have access to each of these users, you need to store the reference to the created instance:

users = []
for user in dict:
    u    = dict[user]
    user = User(u['firstname'], u['lastname'], u['age'])
    users.append(user)

Then, to print results:

for user in users:
    print(user)

*PS: When you write for user in dict you are iterating over the keys of dict, which is why you get User1, User2, User3.

**PPS: You should absolutely not use dict as a name, that shadows the builtin dict() function, and will cause you problems later.

Sign up to request clarification or add additional context in comments.

3 Comments

First, thank you! That makes sense, though I guess I was expecting the instantiation within the for loop to be stored in the variable's (user) value (User1, User2, etc), rather than to the variable name itself. What I was trying to do was instantiate the user data to an object/variable named with the key name, so that I could then work with User#.attribute, but it's looking like once it's in the list, I can only reference them now as users[index]?
Also, once the objects are stored in the list, is the only way to see all the objects' info with [print(vars(i)) for i in users] or is there a better way?
@thisAaronMdev, you can add a specific method to your class: def __str__(): and have it return whatever you want it to print, such as print all the fields in your class, or just say "this is a user. goodluck" if you want. Then when you call print(users[0]) it will print exactly what you want it to print.
1

For completeness - it is possible to create global variables in python thanks to globals()[key] = value - but everyone with a bit of experience would never advise you to do that - if not for very specific and well-thought-out reasons there is no justification for doing so. Nonetheless here you can see how it is achieved given your example:

https://repl.it/repls/InternationalShamelessBug

4 Comments

So I just got around to playing with your answer, and your answer gave me EXACTLY what I was looking for. BUUUUUUUUT you said that this is not the way to go about it. Why is that?
Shortsaid, that makes everything unpredictable and potentially unstable - For more read stackoverflow.com/a/19158418/3820185 and the linked resources, so use this only if you are aware of the implications.
So I read through a lot of those, and it sounds like, in my example, if I instantiated User1 from my User class, and it's available globally, further down the line, another function/method/whatever, could bork it up, and because it's available globally, it could potentially be difficult to track down where that happened? How is that different than storing objects within a list or dictionary that's available globally? Or should the list and/or dict not be accessible globally either?
It has so many downsides it's hard to start somewhere, but for instance: an IDE will not know where the global was declared so before compiling a lookup/introspection for those globals is not possible. In general you want to work with imports whenever you want to re-use something, for instance: repl.it/repls/LovelyPersonalOpengroup

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.