2
class UserInput(): users=[] def __init__(self, name,lista,listb,listc,listd): self.name="" self.lista=lista self.listb=listb self.listc=listc self.listd=listd @staticmethod def create_new_user(x): x=userinput("x","","","","") users.append(x) 

Im intending on making a function where new users are generated, only returning a name to the user and no lists yet, hence x in the name slot.

My Question: is this the correct usage of @staticmethod or did I miss the entire point of it?

To my understanding, it allows the user to use,in this case, userinput.create_new_user('tim') without having the class already pre-defined, tim=userinput("foo","","","","");it creates it on the spot.

What I was trying to turn the function create_new_users into:

@staticmethod def create_new_user(): print("how many users do you want to create") x=int(input()) y=0 while y < x: print("assign the users names") name = input("") if name == "" or "None,none": raise SyntaxError("name cannot be None or empty") break name=userinput("","","","","") userinput.users.append(name) y+=1 
6
  • Please correct you indentation. Commented Jan 4, 2014 at 5:15
  • There are also syntax errors here Commented Jan 4, 2014 at 5:16
  • sorry I forget everytime Commented Jan 4, 2014 at 5:17
  • @qwwqwwq now that I fixed indentation as well as some obvious syntax,append(x) to nothing changed to users.append(x), it is working Commented Jan 4, 2014 at 5:21
  • tim=userinput("foo","","","",""); does not create a class, but an instance of it. The class is created as soon as the class ...: body is executed. Commented Jan 4, 2014 at 7:01

2 Answers 2

3

in a static method you could not use the class variable, your code should get

NameError: global name 'users' is not defined 

edit:

use userinput.users.append

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

6 Comments

Right, but how is that an answer?
yes that does happen, then it would be better to use class method in this case? @staticmethod must not allow references to any class variables.That would mean id have to have a a global list already created for my function to work; would it be more beneficial then to just turn the @staticmethod and the function under it into a @classmethod?
that is the correct usage, I just needed to refer to the list within the class. Thanks
@TimLayne I'd definitely use a @classmethod here.
@glglgl why do you think @classmethod would work better in this situation? if I use @classmethod I have to have class created before I can even use that function, where as in my case I can use that function right off the bat.
|
1

Using a @classmethod will be the easiest alternative for that.

class UserInput: # capitals! Look at PEP 8. users = [] # rearranged to the top for better readability def __init__(self, name, lista, listb, listc, listd): self.name = "" self.lista = lista self.listb = listb self.listc = listc self.listd = listd @classmethod def create_new_user(cls): # no need for x if you overwrite it immediately x = cls("x", "", "", "", "") cls.users.append(x) # easier access to this static attribute return x # for the caller having access to it as well. 

It works as well if we subclass UserInput as it uses the new class then.

But note that x = cls("x", "", "", "", "") won't be very useful, though; better do

 @classmethod def create_new_user(cls, *a, **k): # no need for x if you overwrite it immediately x = cls(*a, **k) # pass the arguments given by the caller to __init__. cls.users.append(x) # easier access to this static attribute return x # for the caller having access to it as well. 

I can use that now this way:

a = UserInput("foo", "whatever", "is", "needed", "here") 

or, if I choose to,

a = UserInput.create_new_user("foo", "whatever", "is", "needed", "here") 

which additionally appends the new user to the list.

If you want to be able to shorten the arguments list, you can do so as well:

 def __init__(self, name, lista=None, listb=None, listc=None, listd=None): self.name = name self.lista = lista if lista is not None else [] self.listb = listb if listb is not None else [] self.listc = listc if listc is not None else [] self.listd = listd if listd is not None else [] 

if they are really lists. If they are strings, another name would be appropriate and, as strings are immutable, you can simply do

 def __init__(self, name, lista='', listb='', listc='', listd=''): self.name = name self.lista = lista self.listb = listb self.listc = listc self.listd = listd 

and call the stuff with

a = UserInput.create_new_user("foo", listc=...) # all others are left empty b = UserInput("bar") # all are left empty c = UserInput.create_new_user("ham", lista=..., listd=...) # all others are left empty 

Now that you come up with a different task, I'll try to cope with that as well:

@classmethod def create_new_users(cls): # several users! print("how many users do you want to create") num = int(input()) for _ in range(num): # simpler iteration print("enter the user's name") name = input("") # in 3.x, this is always a string, so it cannot be None... # if name == "" or "None,none": # That won't work as you think. if name == '' or name.lower() == 'none': # but why disallow the string 'None'? # raise SyntaxError("name cannot be None or empty") raise RuntimeError("name cannot be None or empty") # or ValueError or alike # break not needed. raise jumps out without it as well. user = cls(name, "", "", "", "") # name is an input, not an output. cls.users.append(name) 

But I wonder if the class is really the right place to store new users, and only those created with this function. Maybe it would be better to feed the users list directly in __init__ and let this function be at a higher level.


The advantage of using a @classmethod here is that you always work on the corret basis.

Imagine you have a UserInput with a __init__() method as above. Then you can subclass it and do

UserInput.create_new_users()Using a @classmethod will be the easiest alternative for that.

class UserInputStoring(UserInput): users = [] # this is only here, not at the parent. def __init__(self, *a, **k): super(UserInputStoring, self).__init__(*a, **k) # pass everything up as it was used self.users.append(self) 

Now you can have your create_new_users() in the base class and be a @classmethod and it will pick the right __init__ to call depending on how you call it.

8 Comments

the not capitalizing was mainly due to laziness, once I'm finished ill go back and correct capitalization and such
I added that answer just to show to show you the code that it ended up being since when I tried adding it into a comment it kept removing the structure and organizing it into paragraph form
Im not understanding the difference between our examples, both seem to return the some information to the same list, can you explain how ours differ other than the fact one is @classmethod, the other @staticmethod. Both are accessed by userinput.create_new_users();yours uses the required cls argument. So in your example userinput is returned as the cls argument, where mine doesn't require a cls.In both examples I can use userinput parent class to use the function and it appears both return the same values.What is our differences?Other than the fact yours is shortened down in some areas
it uses cls implicitly is what I mean. Unless the same @staticmethod can be used in other classes I cannot see the major differences in our example other than one using the cls implicitly
@TimLayne There is no big difference, but a @classmethod works as well with subclasses. One example: You might separate the storing in the list into the __init__ of a subclass. Then the caller can choose if he uses UserInput.create_new_users() for not storing the list or UserInputStoring.create_new_users() for storing the list.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.