Access static method from static variable
There are plenty answers for how to access static variables from static methods (like this one, and that one, and the great info on the subject here), however I’m having trouble with the other direction: How can you use static methods to initialize static variables. E.g.:
import os, platform class A(object): @staticmethod def getRoot(): return 'C:\\' if platform.system() == 'Windows' else '/' pth = os.path.join(A.getRoot(), 'some', 'path')
The last line gives an exception: NameError: name ‘A’ is not defined . The same error happens if I use @classmethod instead of @staticmethod . Is it possible to access a static method from a class variable?
3 Answers 3
The problem is that the class «A» doesn’t exist yet at the moment your variable path is declared, so the evaluation fails. How about declaring it right after?
import os, platform class A(object): @staticmethod def getRoot(): return 'C:\\' if platform.system() == 'Windows' else '/' A.pth = os.path.join(A.getRoot(), 'some', 'path')
An uglier alternative would be:
import os, platform class A(object): @staticmethod def getRoot(): return 'C:\\' if platform.system() == 'Windows' else '/' pth = os.path.join(getRoot.__func__(), 'some', 'path')
. but it’s pretty unreadable (and depends on implementation details of @staticmethod, which is bad).
For this specific case I’d do something like this (which doesn’t really answer your question, instead it sidesteps the need for it):
import os, platform class A(object): _root = 'C:\\' if platform.system() == 'Windows' else '/' @staticmethod def getRoot(): return A._root pth = os.path.join(_root, 'some', 'path')
. because your platform is pretty unlikely to change while your program is still running, right? 🙂 If you have a better reason to do something like that, maybe use one of the methods above.
How can I access «static» class variables within methods?
Instead of bar use self.bar or Foo.bar . Assigning to Foo.bar will create a static variable, and assigning to self.bar will create an instance variable.
bedwyr, «print self.bar» will not create any instance variables (although assigning to self.bar will).
when using static variables, it’s a good idea to read the gotchas from here: stackoverflow.com/questions/68645/… . @Constantin gives one of the many gotchas.
class Foo(object): bar = 1 @classmethod def bah(cls): print cls.bar
Now if bah() has to be instance method (i.e. have access to self), you can still directly access the class variable.
class Foo(object): bar = 1 def bah(self): print self.bar
@Mk12: When you’ve got class inheritance, a «class variable»could be in a base class or a subclass. Which do you want to refer to? Depends on what you’re trying to do. Foo.bar would always refer to an attribute of the specified class—which might be a base class or a subclass. self.__class__.bar would refer to whichever class the instance is a type of.
Now we have reached that unfortunate point when we become so aware of the details of the language that we can discriminate between two finely attuned use cases. It does indeed depend what you want to do, but many people won’t attend to such subtleties.
BTW, this is a RARE usage of «class variable». Much more common to have it defined in a specific class, here Foo. This is useful information for some advanced programming situations. But almost certainly not what the original question wanted as an answer (anyone who needs THIS answer will already know how to do Foo.bar). +1 because I learned something from this.
I’m learning about when to use class variables and methods (as opposed to instance variables and methods). When you want to access a class variable in an instance method, is it necessary to use self.__class__.bar? I noticed that self.bar works even though bar is a class variable not an instance variable.
As with all good examples, you’ve simplified what you’re actually trying to do. This is good, but it is worth noting that python has a lot of flexibility when it comes to class versus instance variables. The same can be said of methods. For a good list of possibilities, I recommend reading Michael Fötsch’ new-style classes introduction, especially sections 2 through 6.
One thing that takes a lot of work to remember when getting started is that python is not java. More than just a cliche. In java, an entire class is compiled, making the namespace resolution real simple: any variables declared outside a method (anywhere) are instance (or, if static, class) variables and are implicitly accessible within methods.
With python, the grand rule of thumb is that there are three namespaces that are searched, in order, for variables:
There are limited exceptions to this. The main one that occurs to me is that, when a class definition is being loaded, the class definition is its own implicit namespace. But this lasts only as long as the module is being loaded, and is entirely bypassed when within a method. Thus:
>>> class A(object): foo = 'foo' bar = foo >>> A.foo 'foo' >>> A.bar 'foo'
>>> class B(object): foo = 'foo' def get_foo(): return foo bar = get_foo() Traceback (most recent call last): File "", line 1, in class B(object): File "", line 5, in B bar = get_foo() File "", line 4, in get_foo return foo NameError: global name 'foo' is not defined
In the end, the thing to remember is that you do have access to any of the variables you want to access, but probably not implicitly. If your goals are simple and straightforward, then going for Foo.bar or self.bar will probably be sufficient. If your example is getting more complicated, or you want to do fancy things like inheritance (you can inherit static/class methods!), or the idea of referring to the name of your class within the class itself seems wrong to you, check out the intro I linked.
Populate once static variable from static method Python within a class
I have a Class A in Python and I would like to populate the a static variable calling a static method like:
Class A: arr = [] @staticmethod def FillArr(): #do more stuff but for semplicity. A.arr = [[2,2,2,]] FillArr.__func__()
when I run the code I got ‘NameError: name A not defined’ so essentially I can’t initialize the arr static variable. Essentially once the the class has been instantiated once I would like to populate the static variable
2 Answers 2
This runs flawlessly on Python 3.6:
class A: arr = [] @staticmethod def fillArr(): #do more stuff but for simplicity. A.arr = [[2,2,2,]] A.fillArr() print (A.arr)
Or, with the extra info in your comment:
class A: arr = [] @staticmethod def fillArr(): #do more stuff but for simplicity. A.arr = [[2,2,2,]] def __init__ (self): if not A.arr: A.fillArr () A () print (A.arr)
I’ve retested it, but on my system (win10, python3.6 it runs unmodified, printing [[2, 2, 2]]. Curious where you had to add the boolean.
class A(object): arr = [] @classmethod def FillArr(cls): cls.arr = [[2,2,2]] A.FillArr() print A.arr
/edit/ the using normal method example I mention in my comment below (based on Jacques explanation):
class A arr=[] def FillArr(self): self.arr = [[2,2,2,]] def __init__(self): self.FillArr() a = A() print a.arr
nope.. I need to populate within the class not out of it. essentially once the the class has been instantiated once I would like to populate the static variable
@Jacques: lol I was already looking surprised when I suddenly saw the edit on my own post without doing a thing 😉
@ai2016: What Jacques posts with his staticmethod solution can also done with classmethod. It is just what you like: Do you want to use the name of the class in the method explictly than use staticmethod, if instead you want to use cls (not to be confused with self, which is reserved for instanciated classes), use classmethod. But you can even do it with a normal method by replacing cls with self and call self.FillArr in init
To be honest I like the classmethod better, since it doesn’t depend upon the name of the class, which may easily change, while the first param is by convention almost always named cls. Just took the question literally.