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
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.
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.
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.
So I have a class, which I'm using as a local namespace. I have some static functions in the class, but they can't access the class scope variables. Why is this?
class Foo:
foo_string = "I am a foo"
#staticmethod
def foo():
print foo_string
>>> Foo.foo()
[Stack Trace]
NameError: global name 'foo_string' is not defined
Any thoughts?
Python doesn't let class variables fall into scope this way, there are two ways to do this, the first is to use a class method:
#classmethod
def foo(cls):
print(cls.foo_string)
Which I would argue is the best solution.
The second is to access by name:
#staticmethod
def foo():
print(Foo.foo_string)
Do note that in general, using a class as a namespace isn't the best way to do it, simply use a module with top-level functions instead, as this acts more as you want to.
The reason for the lack of scoping like this is mainly due to Python's dynamic nature, how would it work when you insert a function into the class? It would have to have special behaviour added to it conditionally, which would be extremely awkward to implement and potentially fragile. It also helps keep things explicit rather than implicit - it's clear what is a class variable as opposed to a local variable.
Reading the documentation I came across the following paragraph:
A scope defines the visibility of a name within a block. If a local
variable is defined in a block, its scope includes that block. If the
definition occurs in a function block, the scope extends to any blocks
contained within the defining one, unless a contained block introduces
a different binding for the name. The scope of names defined in a
class block is limited to the class block; it does not extend to the
code blocks of methods – this includes comprehensions and generator
expressions since they are implemented using a function scope.
I decided to try accessing class variable from a method myself:
>>> class A():
i = 1
def f(self):
print(i)
>>> a = A()
>>> a.i
1
>>> a.f()
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
a.f()
File "<pyshell#4>", line 4, in f
print(i)
NameError: global name 'i' is not defined
I know that the variable i may be accessed by explicitly pointing to the class name A.i:
>>> a = A()
>>> class A():
i = 1
def f(self):
print(A.i)
>>> a = A()
>>> a.f()
1
The question is why the developers of the language made class variables not visible from methods? What is the rationale behind it?
A class block is syntactic sugar for building a dictionary, which is then passed to the metaclass (usually type) to construct the class object.
class A:
i = 1
def f(self):
print(i)
Is roughly equivalent to:
def f(self):
print(i)
attributes = {"f": f, "i": 1}
A = type("A", (object,), attributes)
Seen that way, there is no outer scope the i name to come from. However there obviously is a temporary scope for you to execute the statements in the class block. It would be possible for that class block to desugar to something more like:
def attributes():
i = 1
def f(self):
print(i)
return locals()
A = type('A', (object,), attributes())
In this case the outer reference to i would work. However, this would be going "against the grain" of Python's object system philosophy.
Python has objects, which contain attributes. There's not really any concept of "variables" other than local variables in functions (which can be nested to create a scope chain). A bare name is looked up as a local variable, then in outer scopes (which come from functions). Attributes are looked up, using the dotted name syntax, on other objects, and you always specify which object to look in.
There is a protocol for resolving attribute references, which says that when attribute is not found on obj, obj.attribute can be resolved by looking in the class of obj (and its base classes, using the method resolution order). This is actually how methods are found; when in your example you executed a.f(), the a object contains no attribute f, so the class of a (which is A) is searched, and the method definition is found.
Having class attributes automatically available in an outer scope for all methods would be weird, because no other attribute works this way. It would also have the following drawbacks:
Functions defined outside the class and assigned to it later would have to use different syntax to refer to the class attribute than functions defined as part of a class.
Because it's shorter, it would encourage reference to class attributes including staticmethods and classmethods as bare names: thing rather than using Class.thing or self.thing. This makes them look like module globals when they're not (method definitions are usually short enough that you can easily see they're not defined locally).
Note that looking for the attributes on self allows them to play nicer with subclasses, as it allows subclasses to override the attribute. That probably isn't as big a deal for "class constants", but it's very important for staticmethods and classmethods.
Those are the main reasons I see, but ultimately it's just a choice the designers of Python made. You find it weird that you don't have this implicit ability to reference class variables, but I find implicit class and instance variable access in languages like C++ and Java to be weird. Different people have different opinions.
This seems to be related to the use of an explicit self parameter, and the requirement that all method calls and instance attribute accesses explicitly use self. It would be at least strange if the uncommon case of accessing a class scope function as a normal function would be much easier than the common case of accessing it as a method via self. Class variables are usually also accessed via the instance in Python.
In C++, in contrast, the class scope is visibile in all methods, but calling a method implicitly passes this. This seems to be the other sane choice.