How do class methods affect instance variables in Python? - python

I've read throughly many posts here on the difference between class methods and instance methods. I understand them conceptually, but now I'm trying to figure out the more subtle nuances. In the example below, if I call User.createUser('xyz'), where does userId get stored? does it go to (*) below, i.e. on the instance? Or would it be as if I inserted userId = None where I have the comment # placeholder and the userId passed in from User.createUser('xyz') then assigns the class variable userId with 'xyz'?
class User():
# placeholder
def __init__(self, userId):
self.userId = userId # (*)
#classmethod
def createUser(cls, userId):
if not isValid(userId): # isValid may or may not be part of the class
return False
else:
return cls(userId)
# ... other methods

Your classmethod createUser returns a new instance of the User object. The parameter passed to it is stored as an attribute on this new User instance.

The userId parameter is stored in the __init__ method.
The call to cls(userId) is equivalent to a call to User(userId)

In your case, neither. The return cls(userId) returns a new object*, and the userId is assigned to the self of the new object. So, it's neither a class nor an instance variable, it's an instance variable of another object.

Related

How to get class instanced using variable inside of the class

I am trying to access a class instance. I can't assign the class to a variable when I load it and then use it because I need to access the class based on what the user enters.
i.e: user goes to link website.com/classes/y, I need to access the instance with the name y.
I already handle the link and can get "y" or whatever the user entered by itself.
I have the class code as follows:
class LoadModel:
existing_models = []
def __init__(self, model_path):
self.name = model_path.parent.name
self.__class__.existing_models.append(self.name)
For now, I can verify if the class exists using the existing_models list, but how will I be able to access it using the self.name?
I want to access it using LoadModel.name.
It sounds like you want to keep a dictionary of model names to instances. You could do that with something like:
class LoadModel:
modelsByName = {}
def __init__(self, model_path):
self.name = model_path.parent.name
self.modelsByName[self.name] = self
Furthermore if you wanted to access an instance named name as LoadModel.name you could could add
setattr(self.__class__, self.name, self)
to __init__. Or if you were looking up by string (which it sounds like you might be) then you would just do LoadModel.modelsbyName[name].
Note also that you don't need to use self.__class__ when accessing members of the class that you have not assigned within the instance, and since you're only accessing the dictionary object defined in the class, you can use the reference inherited by the instance (self.modelsByName) instead of accessing the class explicitly (self.__class__.modelsByName).

Python Function that creates class instances

Hello i want to create a function which creates instances of a class
def make_instance(name_instance)
name_instance=puppy()
class puppy:
def __init__(self,name):
self.name =name
make_instance(cloud)
# when i pass an argument it says the variable is undefined and i use #isinstance() it return False.
Your puppy class needs to take a name value into its constructor, and you're currently not passing in anything.
Also your function doesn't return the instance at all. It simply re-assigns the instance to the variable name_instance that you pass in (losing your input). The return value of make_instance right now is None
My guess is that you want your implementation to look like the following
def make_instance(name_instance)
return puppy(name_instance)
I do want to point out though that this function isn't useful unless it does more than just create the instance, you're just adding wrapper code around the constructor

Getting None type for object when running method outside of __init__

For the following class
class Member(object):
def __init__(self, fields, scouts, id):
self.id = id
self.fields = fields
self.scouts = scouts
self.routes = [Route(s) for s in self.scouts ]
self.routeBreak = []
self.numScouts = len(self.scouts)
I run this method
def createMember(self):
random.shuffle(self.fields)
self.routeBreak = self.createBreaks(len(self.fields))
self.assignRoutes()
Example:
Member.createMember()
However, after doing so, the object Member comes back as "None". I tried adding createMember() to the init method
class Member(object):
def __init__(self, fields, scouts, id):
self.id = id
self.fields = fields
self.scouts = scouts
self.routes = [Route(s) for s in self.scouts ]
self.routeBreak = []
self.numScouts = len(self.scouts)
random.shuffle(self.fields)
self.routeBreak = self.createBreaks(len(self.fields))
self.assignRoutes()
And then everything is fine. I can run my other methods on the object no problem. I have no idea why this is happening and I need to figure out how to run createMember() outside of the init method. I am fairly new to using Classes and Methods so any explanation would be helpful. Thanks!
Expanding on Tim's question, when using classes, you have the class definition, a type, and then an instance of the class, the object.
createMember should be called as a method of an instance, not of the class itself (there is a type for that - a staticmethod or classmethod, and they do not have a "self").
So you need to create the instance:
m = Member()
Note - you will need the parameters to do that. If you want it to not need the parameters, that requires a bit more code.
Then access that method in it:
m.createMember()
You could also call it inside _init__ (known as the constructor), where "self" is the instance:
self.createMember()
As createMember needs an argument self which should be the instance itself, you can't call it by Member.createMember() because this makes it a unbound method without Member instance as the required argument. Member is a class not an instance. You have to call it by Member.createMember(memberInstance) to explicitly provide the instance itself.
Member().createMember() doesn't need to give the argument is because Member() has created an instance which will implicitly serves as the first argument self.

Getter and Setter for member variable in Python

I know that it is not recommended to write getter and setter for class member variables in Python. Still I need to do it because I have a complex object which internally contains a lot of objects in depth. I need to expose a property/function in container object that will get and/or set member of inner object. How can I do this in Python?
def responseoperationcode(self,operationcode=None):
if operationcode:
self.innerobject.operationcode=operationcode
else:
return self.innerobject.operationcode
Above given function can act as a getter and setter but the syntax to use it would be confusing. My requirement is that user should get its value without using parenthesis and to set values he should pass parameters. Something like this
objectname.responseoperationcode ##this should return the value
and
objectname.responseoperationcode("SUCCESS")##this should set the value
Please suggest.
Python supports properties. You can change your code to:
#property
def responseoperationcode(self):
return self.innerobject.operationcode
#responseoperationcode.setter
def responseoperationcode(self, value):
self.innerobject.operationcode = value
Now you can use the responseoperationcode function like a field, e.g.:
objectname.responseoperationcode # this returns the value
objectname.responseoperationcode = "SUCCESS" # this sets the value
Well, if you have access to the definition of the inner objects, you could write a getter method there. Then whole thing would look similar to this:
class OuterObject:
innerObject
def getInnerField(self, field=None):
if field == None:
return self.innerObject.getField()
else:
self.innerObject.setField(field)
class InnerObject:
field
def getField(self):
return self.field
def setField(self, field):
self.field = field

Constructing from a classmethod

Suppose I am creating a class representing and object in a KV-datastore. Creating the constructor is pretty straightforward...
class KVObject:
def __init__(self, key, value, add=True):
self.key = key
self.value = value
if add == True:
kv_create(key, value)
Now, let's say I want to retrieve a KV-object... and construct a class instance from it. I figure I'll add this class method onto my DataBaseObject class.
#classmethod
def get_kv_object(cls, key):
value = kv_get(key)
cls.__init__(key, value, add=False)
... but when calling init from the class method (cls.__init__), Python asks for an argument for self!
Any ideas? Many thanks! I know this is a bit of a simple example, but it definitely applies to some more complex, interesting situations!
Edit: Thanks for the responses. I learned something helpful while researching this, which is that object.__new__ calls __init__ on an object when calling MyClass(...), effectively providing an uninitialized instance of the class to MyClass.init with the args called from within MyClass. Likewise, it makes sense to call cls(...), as suggested in your answers. Thank you.
Think about how you would create a new database object normally, it would be something like the following:
instance = DatabaseObject(key, value, add=False)
Well within your class method the first parameter (cls in this case) is just another name for DatabaseObject, so to create an instance you would do the following:
instance = cls(key, value, add=False)
#classmethod
def get_kv_object(cls, key):
value = kv_get(key)
return cls(key, value, add=False)
__init__ does not created new instances of the cls class! It's a method that's called right after the object has been created.

Categories

Resources