I'm trying to understand when Python code will refer to module-level variables versus class level variables. I have the following code in a module, main.py'
## main.py
# global variable x
x = "I am global and I love it!"
class SomeClass:
x = "I am a class attribute, and life is good!"
print(x) # prints "I am a class attribute, and life is good!"
def __init__(self):
print(x) # prints "I am global and I love it!" Why?
print(x) # prints "I am global and I love it!"
SomeClass()
When I import this module, the output is:
I am a class attribute, and life is good!
I am global and I love it!
I am global and I love it!
Why does the print inside the SomeClass.__init__ method print the global variable, while the print inside the class body prints the class attribute x?
This was paraphrased from a question on the Python mailing list: https://mail.python.org/pipermail/python-list/2015-December/701167.html
Class definitions in Python create a namespace, but they do not create a new scope. This means that functions defined inside the class cannot access variables of the containing class directly. Instead they must access them as attributes of the class or an instance.
So, rather than accessing x in your example's __init__ function, you can get the class variable by using SomeClass.x or self.x.
The reason that print(x) works in the class body is that that code is running with the class namespace as its local namespace. There are a number of issues you can run into if you try to do more complicated stuff at class level though, as the scopeless namespace is a rather weird environment. For example, this will not work:
class Foo:
x = 1
dct = {i: x for i in range(10)}
You'll get a NameError about the x variable because the dictionary comprehension runs in its own scope and cannot see the class variable x, which is defined in the scopeless class namespace.
Importing a module
Whenever you import a module, Python executes all the module-level code in the order the module is written. It attaches all the defined names to the module object, and the importer of the module can access all the defined names through the module object. That way you can import the module, and the names in the module don't clobber your namespace.
import main # executes the script main.py, then creates a module
print(main.x)
Defining a class
You can think of the way that Python creates the class as similar to how it creates a module: it executes all the code in the class body, then assigns the defined names to the class. The __init__ method just becomes an attribute of the class, as well; by the time the function is called, the class has been constructed and within the function you can only refer to the x class attribute as SomeClass.x (or self.x inside of __init__). The namespace for the class definition is different than the namespace for the module, so the print(x) inside the class finds the class namespace first, since the print is in the same namespace.
Aside
Just as you can't refer to the current module when you're in, you cannot refer to the current class either. For example:
class SomeOtherClass:
x = 5
SomeOtherClass.x = 6 # This fails!
You can't refer to the class for the same reason you cannot refer to the module you are in from within a module: the name has not been created yet.
This answer was inspired by ChrisA's answer on the Python mailing list.
Related
Forgive me if this question is obvious, but from what I've read on Python's OOP tutorials none of them mention how to have a static variable store a static method. In my code I tried:
class Features:
a_static_variable = 1
a_static_variable_that_references_a_static_function = Features.func1
#staticmethod
def func1(blah):
print(blah)
When trying to run this I received:
NameError: name 'Features' is not defined
Is it possible for a class method to reference a static method in its own class? If so, how do I do this. I tried replacing Features with nothing and self but as I expected those made no sense as well.
This is simply a case of func1 not being defined yet.
It should work if you reorder:
class Features:
a_static_variable = 1
#staticmethod
def func1(blah):
print(blah)
a_static_variable_that_references_a_static_function = func1
Yes, just define the function first:
class Features:
#staticmethod
def func1(blah):
print(blah)
a_static_variable = 1
a_static_variable_that_references_a_static_function = func1
Features.a_static_variable_that_references_a_static_function('test')
Your code has two errors (explained in the other answers). This example may help you understand what's going on.
class Example:
class_variable = 'class_variable'
#staticmethod
def static_method():
print('static_method')
class_method = static_method
print(locals())
def instance_method(self):
print(instance_method)
print(locals())
When this code is run, without instantiating a member of this class, the output is:
creating the class:
{'class_variable': 'class_variable',
'__module__': '__main__',
'static_method': <staticmethod object at 0x0135E5F0>,
'class_method': <staticmethod object at 0x0135E5F0>
}
So, while creating the class, a scope is created in which all of the names in that dictionary are accessible.
Now let's look at what happens when we do this:
example = Example()
example.instance_method()
Nothing happens when you instantiate an object, but calling instance_method will print the local variable(s) accessible to that scope.
instance_method
{'self': <__main__.Example instance at 0x01810210>}
Now, you are probably used to creating instance methods that reference class variables.
def other_instance_method(self):
print(Example.class_variable)
Here, Example is not present in the local scope. In order to find it, the global scope needs to be searched (i.e. globals). Note that instead of explicitly referencing Example, we could access the the class variable from the self object itself.
def other_instance_method(self):
print(self.class_variable)
You can do some testing yourself by printing locals() and globals() from various places to get a grip on how the scope changes.
CODE
class MyClass(object):
def MyMethod(self):
print(self)
MyObject = MyClass()
print(MyObject.MyMethod())
OUTPUT
<__main__.MyClass object at 0x0000000002B70E10 >
What does this __main__ mean? And what is being passed in the self parameter?
What does this __main__ mean?
The script invoked directly is considered the __main__ module. It can be imported and accessed the same way as any other module.
And what is being passed in the self parameter?
The reference contained in MyObject.
__main__ is the name of the current module if you run directly from the commandline. If you would import the module from another module import my_module, it will known by this name. Accordingly, the print would say:
< my_module.MyClass object at 0x0000000002B70E10 >
__main__ is the name of the module that your script is running in. You didn't define a library, so it's not a module with a name.
As for self, it's the equivalent of this in C++ or Java, but Python requires you to name it explicitly. See a tutorial.
First:
__main__ indicates that the class running the method is the primary file being run - the file that you clicked on or that you typed into terminal is the one where the class presides. That's why it's good practice to write
if __name__ == "__main__":
#do stuff
on your test code - this guarantees that your test code will only run if the code is being run from the originally called file. It's also why you should never write top level code, especially if you want to multi-thread later on!
Self is a key word that identifies the class. Every method needs to have the first parameter"self" - watch out, if you don't, an error will NOT be thrown, your code will just fail. Calling self.variable indicates a look-up to a class variable as opposed to a local variable (just within that method) or a global variable (avaliable to everyone). Similarly, calling self.methodName() calls a method belonging to that class.
So:
class Foo: #a new class, foo
def __init__( self ):
#set an object variable to be accessed anywhere in this object
self.myVariable = 'happy'
#this one's a local variable, it will dissapear at the end of the method's execution
myVaraible = sad
#this calls the newMethod method of the class, defined below. Note that we do NOT write self when calling.
self.newMethod( "this is my variable!" )
def newMethod (self, myVariable):
#prints the variable you passed in as a parameter
print myVariable
#prints 'happy', because that's what the object variable is, as defined above
print self.myVariable
I resolved it.You can use list.
For example →
print(list(your object))
There is this code:
class A:
__x = 2
def f(self):
print(dir(self)) # there is attribute _A__x, but not __x
print(self.__x) # prints 2
print(self._A__x) # prints 2
x = A()
x.f()
print(x.__x) # AttributeError: 'A' object has no attribute '__x'
Why access to __x variable is allowed inside method like self.__x but not outside this method? I know that name with two underscores is mangled, but the question is what is special so that this unmangled version works inside the method altough self has only mangled version as attribute.
Edit:
I noticed that if some attribute is added to the class with name of form _A__name for example:
class A:
_A__y = 3
def f(self):
print(self.__y) # prints 3
print(self._A__y) # prints 3
x = A()
x.f()
then inside class it seems that when for example interpreter looks for variable __y he can take also _A__y name, so it seems that prefix _A works something similar like scope resolution in C++ like A::. But I am not sure about details how it works.
So the original question can be extended why in this case self.__y has the same effect as self._A__y altough only _A__y is defined?
An attribute which is named with two leading underscores is "hidden" for use outside of the class (not really see below). It is a similar thing as private attributes in other languages.
An important thing is that you can't access the attribute from outside of the class with x.__x but you can access it with x._A__x. Inside of the class you can use (as you showed in the example) both ways.
In other languages like C++ you would declare your __x as private and than you can use it inside the class as __x and outside you can't. In python it is similar, because you use it inside also as __x and outside you shouldn't use it.
Look here for the documentation of this behavior.
self.__x will be mangled and turned in to self._A__x, that's why it works. Mangling is only done in code inside the class definition.
There is code:
class A:
#staticmethod
def g():
A.__z = 4
print(dir(A))
A.g()
print(dir(A)) # A has attribute _A__z
A.__m = 5
print(dir(A)) # A has attribute _A__z and __m
Why the name __m is not mangled to _A__m but __z is?
As the Python tutorial puts it:
This mangling is done without regard to the syntactic position of the identifier, as long as it occurs within the definition of a class.
Name mangling occurs at compilation time for code that is lexically inside of a class statement. It doesn't occur for code outside of class statements. It doesn't occur for code in functions that are defined outside a class statement and then added to the class object. It doesn't occur for code dynamically executed by a exec or eval call inside a class statement.
Exactly because you declared it outside the class, and name mangling happens inside classes.
I have this:
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
print i # self.i will work just fine
return 'hello world'
When I do:
>>> x = MyClass()
>>>
>>> x.f()
I get an error, as expected.
My question is:
Why do I get the error?
Why is there no namespace between the namespace of the function(or method) definition and the global namespace of the module containing the class?
Is there any other way to reference i inside f in this case other than using self?
You've got an error because print i is trying to print a global (for the module) variable i. If you want to use the member of the class you should write self.i.
Because Guido Van Rossum decided not to use namespaces. Actually, I don't know how to answer anymore.
Yes, but no. Yes, because you can use "reflection" (I can't remember how it is called in python) and access any member of the class. No, because using self is the only usable way.
Why do I get the error?
Answer: This is because the variable i & the symbol/level f which points to a function/method code are in MyClass namespace where as the value/callable code/body of the function f lies in global namespace.
Why is there no namespace between the namespace of the function(or
method) definition and the global namespace of the module containing
the class?
Answer: Not sure why the python designer decided to put function name/symbol in the class but its body in global namespace.
Is there any other way to reference i inside f in this case other than
using self?
Answer: I don't think so, but even if it is then it might not be easier logic/code