This question already has answers here:
How can I access "static" class variables within methods?
(6 answers)
Closed 12 days ago.
Suppose I have this code:
class Example(object):
def the_example(self):
itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
When I try it, I get an error that says:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Example' object has no attribute 'itsProblem'
How do I access this attribute? I tried adding another method to return it:
def return_itsProblem(self):
return itsProblem
but the problem persists.
The answer, in a few words
In your example, itsProblem is a local variable.
Your must use self to set and get instance variables. You can set it in the __init__ method. Then your code would be:
class Example(object):
def __init__(self):
self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
But if you want a true class variable, then use the class name directly:
class Example(object):
itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
print (Example.itsProblem)
But be careful with this one, as theExample.itsProblem is automatically set to be equal to Example.itsProblem, but is not the same variable at all and can be changed independently.
Some explanations
In Python, variables can be created dynamically. Therefore, you can do the following:
class Example(object):
pass
Example.itsProblem = "problem"
e = Example()
e.itsSecondProblem = "problem"
print Example.itsProblem == e.itsSecondProblem
prints
True
Therefore, that's exactly what you do with the previous examples.
Indeed, in Python we use self as this, but it's a bit more than that. self is the the first argument to any object method because the first argument is always the object reference. This is automatic, whether you call it self or not.
Which means you can do:
class Example(object):
def __init__(self):
self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
or:
class Example(object):
def __init__(my_super_self):
my_super_self.itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
It's exactly the same. The first argument of ANY object method is the current object, we only call it self as a convention. And you add just a variable to this object, the same way you would do it from outside.
Now, about the class variables.
When you do:
class Example(object):
itsProblem = "problem"
theExample = Example()
print(theExample.itsProblem)
You'll notice we first set a class variable, then we access an object (instance) variable. We never set this object variable but it works, how is that possible?
Well, Python tries to get first the object variable, but if it can't find it, will give you the class variable. Warning: the class variable is shared among instances, and the object variable is not.
As a conclusion, never use class variables to set default values to object variables. Use __init__ for that.
Eventually, you will learn that Python classes are instances and therefore objects themselves, which gives new insight to understanding the above. Come back and read this again later, once you realize that.
You are declaring a local variable, not a class variable. To set an instance variable (attribute), use
class Example(object):
def the_example(self):
self.itsProblem = "problem" # <-- remember the 'self.'
theExample = Example()
theExample.the_example()
print(theExample.itsProblem)
To set a class variable (a.k.a. static member), use
class Example(object):
def the_example(self):
Example.itsProblem = "problem"
# or, type(self).itsProblem = "problem"
# depending what you want to do when the class is derived.
If you have an instance function (i.e. one that gets passed self) you can use self to get a reference to the class using self.__class__
For example in the code below tornado creates an instance to handle get requests, but we can get hold of the get_handler class and use it to hold a riak client so we do not need to create one for every request.
import tornado.web
import riak
class get_handler(tornado.web.requestHandler):
riak_client = None
def post(self):
cls = self.__class__
if cls.riak_client is None:
cls.riak_client = riak.RiakClient(pb_port=8087, protocol='pbc')
# Additional code to send response to the request ...
Implement the return statement like the example below! You should be good. I hope it helps someone..
class Example(object):
def the_example(self):
itsProblem = "problem"
return itsProblem
theExample = Example()
print theExample.the_example()
If you have a #classmethod static method, you always have the class as the first parameter:
class Example(object):
itsProblem = "problem"
#classmethod
def printProblem(cls):
print(cls.itsProblem)
Example.printProblem()
Related
I want a program to call a specific class based on a parameter/variable value. However, I don't want to use any clunky if-statements. My first thought was to use the globals() function, but I couldn't get it to work. Here's an example:
class SomeClass:
def __init__():
print("Hello, world!")
class OtherClass:
def runClass(className):
# Call class based on variable className
The reason I want to do this is because there is a wide variety of classes may need to be called, and so just piling up if-statements in my code won't do it. Any help would be greatly appreciated. Thanks!
Here's how you can call a class via globals
class SomeClass:
def __init__(self):
print("Hello, world!")
def __call__(self):
return "SomeClass called"
class OtherClass:
def runClass(self, className):
globals()[className]()()
o = OtherClass()
result = o.runClass("SomeClass")
print(result)
Notice, I am instantiating and then calling it via the __call__ special method, which is the closest match to your description I could think of.
Use a dict.
name_to_class = dict(some=SomeClass,
other=OtherClass)
def factory(name):
klass = name_to_class(name)
return klass()
some_obj = factory("some")
other_obj = factory("other")
One way to solve this problem is to use a dictionary to map the values of the variable className to the corresponding class.
Try this exemple :
class SomeClass:
def init(self):
print("Hello, world!")
class OtherClass:
def init(self):
print("Goodbye, world!")
classNameToClass = {
"SomeClass": SomeClass,
"OtherClass": OtherClass
}
def runClass(className):
# Call class based on variable className
cls = classNameToClass[className]
return cls()
runClass("SomeClass") # prints "Hello, world!"
runClass("OtherClass") # prints "Goodbye, world!"
Here, the dictionary classNameToClass maps the string names of the classes (e.g. "SomeClass") to the corresponding class objects (e.g. SomeClass). Then, in the runClass function, we look up the class object using the value of the className variable, and call it to create an instance of the class.
I've found an answer. The parameter that governs the called class can just be assigned elsewhere. At first, I thought it would need some complex function, but in reality, I guess the question didn't give enough details. The class itself only uses items from whatever object is given. So, instead of having to dynamically call a class, it's as simple as:
class SomeClass:
def printHelloWorld():
print("Hello, world!")
class OtherClass:
def __init__(self, usingClass):
self.object = usingClass
def doThis():
usingClass.printHelloWorld()
x = OtherClass(SomeClass())
x.doThis()
It's on me for not giving enough information. Thank you all for your help.
I have the habit to initialize the properties of an instance of a class in the constructor of that class but, in case the properties are very tight to the class, I also declare them and initialize them to None ([] or some other base value) as properties in the class.
For instance:
class AClass(object):
aprop = None
def __init__(self):
self.aprop = "avalue"
Which in most of the cases it won't make much of a difference from just doing:
class AClass(object):
def __init__(self):
self.aprop = "avalue"
However, if somebody gets the scope of the AClass will notice that an instance of this class is expected to have an attribute named aprop. I think of it as a placeholder for the property aprop in the class.
This looks to me more as a question of style, but I would like to know whether this is a good practice. Would you recommend it? Is it something common? or should I try to get rid of it?
When you do self.aprop = "avalue" in the __init__ function, every instance of AClass will have the aprop property since __init__ is called when you initiate an instance. This makes aprop an instance variable.
When you do aprop = None you add a class variable to AClass. This means that the class itself will have this property.
For Example:
>>> class AClass(object):
... def __init__(self):
... self.aprop = "avalue"
...
>>> AClass.aprop
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'AClass' has no attribute 'aprop'
And:
>>> class AClass(object):
... aprop = None
... def __init__(self):
... self.aprop = "avalue"
...
>>> AClass.aprop
>>> print AClass.aprop
None
So if you want your class to have this property you should define it as a class variable. If you only use it in instances, the only case you should define a class property is if you don't always redefine it (hide it) in __init__:
class AClass(object):
aprop = None
def __init__(self):
self.bprop = "bvalue"
Unless you ever access the property on the class itself (e.g. as AClass.aprop) rather than on an instance, there's no need to make it a class member if you always populate it on an instance in the __init__ method.
My vote is to always write the least amount of code necessary to clearly convey the intent. Adding an extra member to the class obscures the intent (since your actual goal here is for it to be an instance property) and is unnecessary: that sounds like two strikes against it.
After using Django for a while, I got use to using classes without def __init__(self): ... when declaring variables. I used to declare my variables in the __init__ function, I now realize that there are cases where don't need to, I'm just unclear on when to use it or not. It seems there is a problem when trying to pass a class to a variable, should I use init in these cases?
I know I could just use __init__ for all cases, but it just makes my short classes like cleaner without it, so I would like to know when I can and cannot use it.
example:
class BaseScraper(object):
# whithout __init__, passing Site() to site wont work.
# site = Site()
# parser = None
def __init__(self):
self.site = Site()
self.parser = None
class Site(object):
# no trouble declaring url as a str
url = ""
def set(self, url):
self.url = url
def get(self):
return self.url
if __name__ == "__main__":
scraper = BaseScraper()
scraper.site.set('http://www.google.com')
print scraper.site.get()
Attributes declared in the class are owned by the class rather than by individual instances of the class. In your site example, url is no more a property of individual Site objects than set or get are. For this kind of example, you want instance data - which you can initialize in __init__.
Python: Difference between class and instance attributes has a good discussion of the differences.
This fails because Site class is not defined yet.
And (as #Peter DeGlopper) said, there is a big difference between class variables and instance variables.
class BaseScraper(object):
# This fails!
site = Site()
parser = None
class Site(object):
# no trouble declaring url as a str
url = ""
def set(self, url):
self.url = url
def get(self):
return self.url
When the virtual machine compile a python module, read and compile everything in class declaration, but on method declaration (like def __init__(...):) only read this line, ignoring the method body.
Example:
class Foo(object):
bar1 = "bar"
foo1 = "foo"
def __init__(self):
self.bar2 = "BAZ"
foo = Foo #Put a class in a veriable? yes, you can.
foo.bar1 # returns "bar"
foo.foo1 # returns "foo"
foo.bar2 # fails!!!! This will be a instance variable, but doesn't exist yet
foo2 = Foo() # Here the __init__ is called
foo2.bar2 # returns "BAZ"
foo2.bar1 #Returns "bar" because all class variables are availables from instances
Hope this helps =)
Should I write
class MyClass:
def __init__(self):
self.field = 0
or
class MyClass:
def __init__(self):
field = 0
Is there any difference between these statements?
Yes, you must use the self variable to set the properties of Python objects/instances.
In the second case, you're just creating a local variable in __init__, not defining a property.
class MyClass:
def __init__(self):
field = 0
print MyClass().field # an error! it's not defined!
You may be misled by the way that you can just use raw assignments in class blocks to set class properties:
class MyClass:
a = 2
print MyClass.a # 2
The behaviour in class blocks is unusual, and you don't get similar behaviour inside methods.
The first chunk of code creates an instance attribute that can be accessed once an instance of the class has been created:
>>> a = MyClass()
>>> a.field
0
The scope of the second chunk's field variable is only within the __init__ function, so accessing the variable outside of that scope won't work:
>>> a = MyClass()
>>> a.field
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: MyClass instance has no attribute 'field'
The former sets the value as a property of the class. The latter, as simply a local variable.
If elsewhere in your program you do
foo = MyClass();
print foo.field;
The print statement above will only work with the first code snippet, not with the second.
I am not very experienced with class inheritance. Please help me and have a look at the code below:
class Handle(STAFHandle):
def __init__(self, HandleName):
handle = STAFHandle.__init__(self, HandleName)
self.initLogger(handle)
def initLogger(self, handle):
self.logger = Logging(handle, 'Test')
handle = Handle('test')
handle.logger.info('test')
it says submit method is not defined:
result = handle.submit(system, service, logRequest)
AttributeError: 'NoneType' object has no attribute 'submit'
but if I change it to:
class Handle(STAFHandle):
def __init__(self, HandleName):
handle = STAFHandle.__init__(self, HandleName)
def initLogger(self, handle):
self.logger = Logging(handle, 'Test')
handle = Handle('test')
handle.initLogger(handle)
handle.logger.info('test')
it works. Why there is a difference? Thanks a lot!!
Cheers,
Zhe
STAFHandle.__init__ returns None. You probably want:
class Handle(STAFHandle):
def __init__(self, handle_name):
super(Handle, self).__init__(handle_name)
self.initLogger()
def initLogger(self):
self.logger = Logging(self, 'Test')
handle = Handle('test')
Remember that __init__ methods take as their first argument an object, and modify that object. So when you call super(Handle, self).__init__(handleName) you are changing the properties of self instead of returning a new object. The difference between your two examples is that the variable handle in the two calls to initLogger refers to different things.
Notice that I have replaced the explicit STAFHandle.__init__ call with a super proxy; this is equivalent in this case but allows for more flexibility, since you can now change the inheritance of the class without breaking its __init__.
I've also changed HandleName to handle_name to conform with Python conventions (CamelCase refers to classes).