How to set class attributes in python - python

I have class attributes in my class, that I want to set dynamically, here's a code example
class Something:
attribute1 = 42 # this is shared between all class instances
def _init_(self, value):
self.value = value
my question is: Is there a way to set that class attribute (attribute1) to some value, the same way that I can set my object instance attributes like this:
something = Something(value)

Yes just do
Something.attribute1 = "some value"
Class attributes can be accessed via the class name. You can do this inside any function defined in the class or even outside of it.

Related

Access Class method and variable using self

In below example Test class has two instance method and one classmethod
In set_cls_var_1 method I set class variable using self.
In set_cls_var_2 method I call class method using self.
class Test():
#class variable
cls_var = 10
def __init__(self):
obj_var=20
def set_cls_var_1(self,val):
#second method to access class variable
print "first "
self.cls_var = val
def set_cls_var_2(self):
print "second"
self.task(200)
#classmethod
def task(cls,val):
cls.cls_var = val
t=Test()
#set class variable by first method
t.set_cls_var_1(100)
print Test.cls_var
#set class variable by second method
t.set_cls_var_2()
print Test.cls_var
Output
first
10
second
200
Expected Output
first
100
second
200
My question is:
why only classmethod can call by self, Why not class variable
When you attempt to access an object's attribute using self, Python first searches the object's attributes. If it cannot find it there, then is searches the object's class's attributes. That is what's happening in your case;
Python first searches t's attributes. It doesn't find cls_var, so it then searches the T class's attributes. It finds cls_var so it stops, and returns cls_var's value.
However, when assigning attributes to self, Python always assigns them directly to the object, and never the object's class unless explicitly told to do so. That's why assinging self.cls_var to 100 didn't affect Test's cls_var attrbiute.
I find something else that always use following way to access classmethod or variable in instance method
class Test():
#class variable
cls_var = 10
def __init__(self):
obj_var=20
def set_cls_var_1(self,val):
#first method to access class variable
print "first type"
cls = self.__class__
cls.cls_var = val
t=Test()
#set class variable by first method
t.set_cls_var_1(100)
print Test.cls_var
When defining the Test class like you did, python creates a class object called Test which has an attribute cls_var equal to 10. When you instantiate this class, the created object doesn't have cls_var attribute. When calling self.cls_var it is actually the class' attribute that is retrieved due to the way python resolves attributes.
However when set self.cls_var the value is set at the object level! So further call to self.cls_var will give you the value of the object's attribute, and not the class' anymore!
Maybe this bit of code will make this clearer:
class A(object):
a = 1
a = A()
print a.a # prints 1
A.a = 2
print a.a # prints 2
You see that even though when set the value at the class level, the changes are repercuted on the object, because, python will look up for the attribute in the class when it is not found at the object level.
When calling Test.cls_var it is the cls_var attribute of the class you are accessing! Not the one of the object you just modified.

error when using method defined parent class

I have the following classes:
class A:
def name(self):
return self.__label
class B(A):
def __init__(self, name)
self.__label = name
ex1 = B('Tom')
print ex1.name()
What I get is:
AttributeError: B instance has no attribute '_A__label'
What's wrong and how to correct it?
When you prefix an attribute with a double underscore, Python uses 'name mangling' to access the attribute. This means it will store the attribute on the class in the format: _<class name>__<attr name>. In your example self.__label will be stored as self._B__label because you set it in the B class method. But when you try to use the attribute in the A class it converts self.__label into self._A__label and finds that it isn't set.
The use case for double underscores is when you want to ensure that your variable is always on your class even if a subclass derives your class. Because what could happen is that the subclass redefines your variable to something else, using double underscored variables makes this that much harder.

Class variable access in all class method

I want to have a class variable, so that the value can be access in all instances, but I also want to access the variable in methods inside the class. Is that possible? I have tried this, but it didn't work at all.
class myClass:
myvariable = 1
def add():
myvariable+= 1
def print1():
print myvariable
I want to make two instances, one only do add method, the other only do print1 method
Yes, just access the variable on the class object:
class myClass(object):
myvariable = 1
def add(self):
myClass.myvariable += 1
def print1(self):
print myClass.myvariable
or if you want to set it per sub-class, use type(self):
class myClass(object):
myvariable = 1
def add(self):
type(self).myvariable += 1
def print1(self):
print type(self).myvariable
The difference is that the latter will create a separate attribute on any subclass when set, masking the base class attribute. This is just like setting an attribute on an instance would mask the class attribute.
Although you can get the class attribute via self as well (print self.myvariable), explicit is better than implicit here, and avoids accidentally being masked by an instance attribute of the same name. Setting class attributes always has to be done on the class; setting it on self would create or update an instance attribute instead (not shared).
Do inherit your classes from object though; using new-style classes has many advantages, not in the least that type(self) will then actually return the class. In old-style classes (not inheriting from object) you'd have to use self.__class__ instead.
Using object as a base also gives you a third option, class methods with the #classmethod decorator; use these when you only need to access the class object, not the instance. These methods are bound to the current (sub)class, so their effect on class attributes is the same as using type(self):
class myClass(object):
myvariable = 1
#classmethod
def add(cls):
cls.myvariable += 1
#classmethod
def print1(cls):
print cls.myvariable

Python property not working

I have an object which inherits from ndb.Model (a Google App Engine thing). This object has a property called commentid:
class Comment(ndb.Model):
commentid = ndb.StringProperty()
Reading a bunch of articles, they all say this is the way to implement a property:
#property
def commentid(self):
if not self._commentid:
self._commentid = "1"
return self._commentid
but I get an error saying Comment object has no attribute _commentid. What am I doing wrong?
Edit: Ok obviously I'm a bit confused here. I come from Objective-C, where if you have a property called x then you automatically get a variable called _x in your getters and setters. So I thought this is what was happening here in Python too. But apparently I need to manually set a value for the variable with an underscore prefix.
All I want is to implement a getter where I do some checking of the value before returning it. How would I do this?
Implementing a property like that requires you to define the attribute for your object. What you're doing there, is defining a class called Comment but you don't define any attributes for it's objects, you define them for the class itself.
Let me demonstrate with a small example:
class ExampleClass:
name = "Example Object"
a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # a doesn't own an attribute called "name"
print(ExampleClass.name) # --> "Example Object"
In the above example, I define class ExampleClass and give it a variable name with a value Example Object. After that, I create an object a = ExampleClass(), however it does not get the name attribute, cause the attribute is defined for the class itself, not for it's objects.
To fix this problem, you define the name inside __init__ -method, which gets called whenever an object of that class is created.
class ExampleClass:
def __init__(self):
self.name = "Example Class"
a = ExampleClass() # Init new instance of ExampleClass
print(a.name) # --> "Example Class"
print(ExampleClass.name) # --> ERROR: Exampleclass.name doesn't exist
There I define the ExampleClass again, but I also define __init__ method for it. Init method takes only one parameter, self, which will be automatically given to the function. It's the object which is being created. Then I set self.name = "Example Class", and since self is the object itself, we set the object's attribute name.
Creating the property
To implement setter and getter for your attribute, you add the following:
class ExampleClass:
def __init__(self):
self.name = "Example Class"
#property
def name(self):
if not self._name:
pass #blabla code here
return self._name
#name.setter
def name(self, value):
#blabla more code
self._name = value
Also, you should edit the __init__ method to take name as a parameter too.
def __init__(self, name="Example Object"):
self.name = name
If you access self._commentid directly, it needs to be defined or it'll raise an exception. Since you're instead checking if _commentid is defined at all (to give it a default value), I'd use hasattr:
#property
def commentid(self):
if not hasattr(self, "_commentid"):
self._commentid = "1"
return self._commentid

Create Python class where the attributes is defined dynamically

Sorry if this has been asked before. Is it possible to create class in Python dynamically where attributes is not defined in the __init__ method of the class.
For example with this class
class Person(object):
def __init__(self):
...
I can dynamically put in the attributes during initialization like this:
person = Person(name='Joe')
and access it like this:
person.name
>>> Joe
Thank you
The easiest way to do this is to assign the keyword argument dict to the __dict__ attribute of the class:
class Person(object):
def __init__(self, **kw):
self.__dict__ = kw
person = Person(name='Joe')
print person.name
prints
Joe
To add attributes after object creation, use
def add_attributes(self, **kw):
self.__dict__.update(kw)
You could also use .update() in the constructor.
This can be achieved by using descriptors (detailed explanation). This also enables you to add attributes after the object has been created.

Categories