I am trying to learn OO Python, and I have a doubt regarding the scope of object attributes once it has been instantiated. So, I decided to write a very simple program:
class Struct:
def __init__(self):
self.resadd=[]
self.ressub=[]
self.resmul=[]
class MathStruct:
def mathss(self,x,y):
add=x+y
sub=x-y
mul=x*y
resstruct.resadd.append(add)
resstruct.ressub.append(sub)
resstruct.resmul.append(mul)
if __name__=='__main__':
resstruct=Struct()
for i in range(10,20):
mathsstuff=MathStruct()
mathsstuff.mathss(i,5)
print len(resstruct.resadd),resstruct.resadd
print len(resstruct.ressub),resstruct.ressub
print len(resstruct.resmul),resstruct.resmul
As you can see, the program is quite straightforward - but, here is my question - I instantiate the "result" object using:
resstruct=Struct()
and then use the resstruct.resadd, resstruct.ressub and resstruct.resmul attributes within the "mathss" function. Is this legal(I get the right answer!)? Does this mean that the object attributes are available even within other functions?
Normally, I would return values from the function and then append it to the object attribute, but I was (pleasantly) surprised to see that I can directly modify the object attribute within another function.
..In a nutshell, my question is what is the scope of the object attributes once it is instantiated? Sorry if this is a 101 question.
The line restruct = Struct() occurs at the module top level, outside any function or class, so it creates an object in the module global namespace. This namespace is, as the term implies, global to the module, and can be accessed from all functions. If you had done restruct = Struct() inside a function, it wouldn't be global and would disappear when the function finished.
In other words, if you had created it in a function scope, the object's lifetime would be limited to that scope. But you created it in global scope, so it lives forever. (An object's attributes have no scope of their own as such; they are inside that object's own instance namespace and are accessible only via the object. You can access obj.attr whenever you can access obj.)
(Note, though, that assigning to global variables from inside a function requires a global statement. You are able to access restruct because you only read the value of the variable and mutate that object with methods. If you tried to assign to restruct within a function, you would be creating a new local variable shadowing the global one.)
Related
I have a Python code whose structure is as following:
for i in range (0,N):
ClassInstance = A(params)
... #some operation that modify the attribute of the instance "ClassInstance" of the class "A"
A is a class linked to another one by a class composition relation.
Now I want to reset at each loop cycle the class' instance and:
I don't want to create a new instance for each cycle with a different name
I don't want to write a method in A for the manual reset of attributes since they are many and not all defined in the __init__ method but spreaded inside the various methods of the class.
I just want that at each cycle the same old instance assumes the same state that had just after its creation; to do so I'd proceed putting a reset method in A like the following:
def reset(self, params):
self = A(params)
and modify the structure of the code as follow:
ClassInstance = A(params)
for i in range (0,N):
ClassInstance.reset(params)
... #some operation that modify the attribute of the instance "ClassInstance" of the class "A"
Is it a safe way to lose track of the previous history of ClassInstance, restarting at each cycle from 0, or there is some cons that I'm not considering?
P.S.
Searching online I saw some previous similar post (as Preferred way of resetting a class in Python) but I'd like to understand if this specific way works and if I should be careful about something when proceeding by it.
Clearly if this method is a wrong way to solve my problem, other approches/solutions that fit my circumstance are well accepted as well (but in that case I'd like to understand where is the problem)
You have to understand what does the = operator when you assign to a variable like in a=obj
That does not modify the object which the variable was pointing at. That just set which object the variable will be referencing from then on, leaving the old object alone.
So ClassInstance = A() makes a new object and assign it to the variable ClassInstance
The old instance is not referenced anymore, and you cannot access it anymore. So in each loop you have a new fresh instance.
Also, you cannot reset an instance by doing self = A() You are assigning a new object to the local variable self. The instance which was referenced by self is not touched. Moreover, when the method returns, the self variable is released and the instance is not referenced anymore, so it is destroyed.
In general assigning to variables does not do anything. Is just like putting a label to an object. self is a variable like any other. There is nothing special about it.
The only way of resetting an instance is by manually setting its properties.
('object' and 'instance' in this context means the same)
By the way, you cannot in python actually destroy objects. You can delete variables with del a for example, but the objects are destroyed automatically when they are not referenced anymore.
I am currently reviewing the python tutorials of python.org. I come from C++ and in the Classes tutorial (https://docs.python.org/3/tutorial/classes.html) I see that the scoping is similar to that in C++. It says the following about scoping and nesting:
"At any time during execution, there are at least three nested scopes whose namespaces are directly accessible:
- the innermost scope, which is searched first, contains the local names
- the scopes of any enclosing functions, which are searched starting with the nearest enclosing scope, contains non-local, but also non-global names
- the next-to-last scope contains the current module’s global names
- the outermost scope (searched last) is the namespace containing built-in names "
However I tried with following code from the same page:
class Dog:
tricks = []
def __init__(self, name):
self.name = name
def add_trick(self, trick):
self.tricks.append(trick) #this is the troublesome self
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over') #without the self this complains
>>> e.add_trick('play dead')
>>> d.tricks
['roll over', 'play dead']
If I remove the self in self.tricks.append(trick) the code will not compile and throw an NameError: name 'tricks' is not defined when calling the function d.add_trick('roll over').
Why does it happen? As I understand from the paragraph above, the function add_trick should look for a variable called tricks first within its own local scope, then if doesn't find any, in the nearest enclosing scope, which is the scope of the Class Dog, and there it should find it, without the need of using self. What am I missing?
As the tutorial said, scopes are searched in the order local, nonlocal, global, builtin.
The nonlocal scope is for enclosing functions. A class declaration is not a function. Its namespace gets thrown away after it is used to create the class object's __dict__, so variables at the class level cannot produce nonlocals in enclosed functions. Think of class-level assignments and variable reads like implicit assignments to and reads from a hidden dict, rather than as function locals. (Metaclasses can even replace this hidden dict with some other mapping.)
But the class scope does add one nonlocal, __class__. This is rarely used directly, but it's important for the zero-argument form of super().
This is the class object itself, so it's uninitialized until the class declaration finishes executing. So __class__.tricks would work inside a method if it's called after the class body executes (the usual case), but not if it's called during the execution of the class body.
There are other scopes to be aware of in Python. Comprehensions create a local scope like functions do. (They're basically compiled like generator functions--the kind with yield inside.) Also, caught exceptions are automatically deleted at the end of their handling clause to prevent a reference cycle.
You can see locals namespace using the locals() builtin and globals using globals(). The builtin scope is just the builtins module. The nonlocals are tricky. They'll actually show up in locals() if the compiler sees them being used. Function objects keep a reference to the nonlocals they use in their __closure__ attribute, which is a tuple of cells.
Your mistake is in thinking that the class is a scope. It isn't. As the doc you quoted explains, scopes are functions or modules.
Does this example help:
In [27]: foobar = 'pre'
In [28]: class AClass():
...: print('class def:', foobar)
...: foobar = 'class'
...: def __init__(self):
...: print('init:', foobar)
...: print(self.foobar)
...: self.foobar='instance'
...: print(self.foobar)
...:
class def: pre
In [29]: AClass.foobar
Out[29]: 'class'
Class definition is like running a function. foobar is initially the global value, but then gets reassigned, and is now available as part of the class namespace.
In [30]: x = AClass()
init: pre
class
instance
In [31]: x.foobar
Out[31]: 'instance'
In [32]: x.__class__.foobar
Out[32]: 'class'
When we define an instance, foobar comes from the outer, global namespace. self.foobar initially accesses the class namespace, but then gets redefined to be an instance variable.
Changing the global foobar is reflected in the next instance creation:
In [33]: foobar = 'post'
In [34]: y = AClass()
init: post
class
instance
In [35]: y.__class__.foobar
Out[35]: 'class'
Your tutorial page, in section 9.3.1. Class Definition Syntax says that while in the class definition, there's a new local namespace. That's where foobar='class' is defined. But once out of the class definition, that namespace is renamed as AClass.
The instance creation runs outside of the class definition. So it 'sees' the global foobar, not the class local one. It has to specify the namespace.
The distinction between scope when a class (or function) is defined, and when it is 'run' can be confusing.
A class definition in particular creates a class scope, which is a special kind of scope. While the class scope is indeed enclosed by the global scope (class variables can access global variables), the class scopes DO NOT ENCLOSE the local scopes within it! So, the local method scopes within the class body cannot access the class scope during name lookup. (At least without qualifying it). In other words, a class's scope is only accessible from within the top level codebody of its own class definition. it is inaccessible from anywhere else, be it inside or outside, without using dot notation directly
for Python 3.7
I have a class with a class attribute (class-wide variable):
class foo:
var="value goes here"
as well as an instance variable created in the class's init method:
def __init__(self, var=var):
self.var=var
Passing class variable to parameter
The class variable has the same name as init's parameter, and this doesn't confuse the interpreter, because the interpreter treats any field to the left of an "=" sign as a new variable within the scope of the method. It accomplishes this by populating a new namespace (a dictionary of variables) for the method's scope, implemented either as an array: e.g. parameters[1] = "var" or an associative array: parameters['var'] = pointer_to_value. Then the interpreter looks inside the method body and substitutes the generic reference for any references to "var" that occur on the right side of an "=" sign. Actually, this is a lie, but it's simpler to understand that than what it really does:
The interpreter identifies the matching regular expression .*= *var(,{0,1}| *) *(;{0,1}|\n*) and then passes the corresponding pointer_to_value to the program's call stack). Because of that, the interpreter doesn't care what the parameters are named and is oblivious to the ambiguity of var=var. The fact that the ambiguity can be resolved is a side-effect of the structure of the language, rather than an intentional design decision. After all, ask yourself, when defining a method, why would you access a variable from inside of the method that you are defining? And why would you ever call an assignment operation to a variable in the parent scope from within a method definition? These are both illogical actions, and their namespace possibilities are mutually exclusive, so the interpreter never needs to address the ambiguity.
Conversely, the interpreter treats the right side of the "=" sign as an existing value and searches the class's namespace for variable definitions.
Storing parameter in Instance Variable
Within the method, the instance variable also has the same name as the class variable and the parameter, and this works inside the init method, because the instance variable is accessed via the self reference, e.g.
self.varname = varname
The problem
Method Definition
I need to access the instance variable from within the method definition of another method and I want to use the same name for this function's parameter:
def lookup(self, var=var):
print(var)
Will the expression var = var get the class attribute or the instance attribute? What does methodname(self) do with self, exactly? Is self a reference to an actual object, or does it only change the behavior of the interpreter from from static method to instance method? Does the interpreter automatically contextualize the right hand side of the "=" sign as an instance attribute of whatever object is typed into methodname(object)?
Method Body
Within the method body, if I make an assignment to var...
def lookup(self, var=var):
var = var
Will it store it in the class variable, the instance variable, or a new variable with the same name?
Will it get the class variable, instance variable, or the method's variable?
How do I explicitly reference these variables?
I have read the documentation and several OOP tutorials, and a recent book, and this is still not clear to me.
The only way you can access an instance variable is as an attribute of self.
When you just refer to var, that's never an instance variable; it's always a local, enclosing, global, or builtin variable.
In your method definition:
def lookup(self, var=var):
print(var)
… you have a parameter named var. Parameters are local variables. The print(var) inside the body prints that local variable.
What about this?
def lookup(self, var=var):
var = var
Again, var is a local variable—a parameter. So, you're just assigning the current value of that local variable to the same variable. Which has no useful effect, but of course it's perfectly legal.
Where does the parameter's value come from? At function call time, if you pass an argument, that argument gets bound to the parameter; if you don't, it gets filled in with the default value.
OK, so where does the default value come from?
At function definition time (when the def statement is executed), var is looked up in the current scope—that is, the body of the class definition—and its value is stored as a default in the function object (it should be visible as foo.lookup.__defaults__[0]).
So, the default value is "value goes here".
Notice that it's not a closure capture or other reference to the class attribute. When the class statement is executed, it uses that same class body namespace to build the class's attributes, so you end up with foo.var as another name for the same value that's in foo.lookup.__defaults__[0]. But they're completely independent names for that value; you can reassign foo.var = 3, and the default value for lookup's parameter will still be "value goes here".
So, to answer your specific questions:
Will it store it in the class variable, the instance variable, or a new variable with the same name?
None of the above. It stores it in a local variable that already exists, because it's a parameter.
Will it get the class variable, instance variable, or the method's variable?
If by "the method's variable" you mean the parameter, it's the last one.
How do I explicitly reference these variables?
The same way you explicitly reference anything else:
var is a local-enclosing-global-or-builtin variable.
self.var is an instance attribute, or a class attribute if there is no instance attribute.
type(self).var is a class attribute, even if there is an instance attribute.
The implicit method argument self is the instance. Thus, while self.var is the instance variable, you need to prefix with the class object to access the class variable. Sometimes, you may not know the class object and then you can simply use the __class__ attribute, i.e. the class variable is self.__class__.var.
To answer your three questions
1. Your assignment in the lookup method will create a new variable with the same name var.
2. It will get the argument that you passed to the method (I guess that's what you mean by "method's variable"
3. The code below shows how you can explicitly access these variables (is illustrates it in the __init__, but it doesn't really matter which method you are in.
class A(object):
var = 'class_variable'
def __init__(self, var=var):
print('Argument var={}'.format(var))
var = var
self.var = var
print('Instance var={}'.format(self.var))
print('Class var={}'.format(self.__class__.var))
print('Alternative access to Class var={}'.format(A.var))
This gives
>>> a = A()
Argument var=class_variable
Instance var=class_variable
Class var=class_variable
Alternative access to Class var=class_variable
>>> b = A('v')
Argument var=v
Instance var=v
Class var=class_variable
Alternative access to Class var=class_variable
>>> c = A()
Argument var=class_variable
Instance var=class_variable
Class var=class_variable
Alternative access to Class var=class_variable
I'm going to do my best to answer your questions but if I may isolate your problem first:
I want to use the same name for this function's parameter
Don't do this. There's no logical reason to do it and if it's confusing you now imagine how you'll feel when you look at your code in a few hours/days/weeks/months/years. Imagine how someone else looking at your code will feel.
For everything I write, imagine we have an instance named bob
This will cause bob.var to be "value goes here" every time it is instantiated. Every new object will have var set to "value goes here"
class foo:
var="value goes here"
This will cause bob.var to be whatever value gets passed to foo during instantiation. If nothing is passed, it will default to "value goes here"
def __init__(self, var=var):
self.var=var
This will print whatever is passed OR "value goes here" if nothing is passed
def lookup(self, var=var):
print(var)
This does nothing as the var in question is locally scoped and only exists until the end of the method
def lookup(self, var=var):
var = var
I hope this helps and just to reiterate: Use different variable names for your different variables.
I have a question about inner classes usage in python. I know that this is a bad practice but anyway. I am wondering about scope where inner class is defined. I got an error 'global name 'ClassName' is not defined'. My code snippet looks like this:
I discovered that to avoid getting this error I can use:
ClassWithEnum.EnumClass
instead of:
EnumClass
inside of doSomethingWithEnum() function. So I am wondering if there is any other way to make EnumClass defined inside of doSomethingWithEnum() function? And why there is no such error when I declare EnumClass as a default parameter in doSomethingWithEnum() function?
class ClassWithEnum(object):
class EnumClass(object):
...
def doSomethingWithEnum(self, m = EnumClass....):
...
Python class construction executes as code. The def statement is really a line of code being executed that creates a function. The class keyword introduces a namespace. Putting these two mechanisms together, it means that class EnumClass really creates an object by that name in the current namespace, not much different from what foo = 'bar' does, so within the same namespace you can refer to it by that name, which is what happens in the def statement.
Also compare:
class Foo:
bar = 'baz'
print bar
baz = bar
Every line of code inside a class block is a regular executable line of code.
Once your class definition is done, you're out of the ClassWithEnum namespace and cannot access EnumClass anymore simply by that name; it's now only available as ClassWithEnum.EnumClass; whether from "outside" the class or from within a function (any function, including class methods).
To get access to the class without typing its name from within the method you could do:
type(self).EnumClass
Or simply self.EnumClass, since properties are looked up up the chain.
When you are inside doSomethingWithEnum function, you are in the different namespace. To access anything that is defined in your class, like EnumClass, you should call self.EnumClass. If it were a class method, it would be cls.EnumClass.
In this class:
class MyClass () :
foo = 1
#staticmethod
def bar () :
print MyClass.foo
Why do I need to qualify foo with MyClass? (otherwise I get NameError: global name 'foo' is not defined.
Isn't foo local to the class MyClass?
This is because Python's scope lookup order is LEGB (locals, enclosed function, global, builtin). More details in this answer. Python has an explicit class variable, which is the first argument of the method, typically named self. Normally one would access foo by using self.foo But in this case, the function is a static method, so it does not receive an explicit class variable, so there is no alternative way to access foo. Either remove the reference to foo or remove the #staticmethod decorator from the bar()and add self as the first argument of bar().
You need to do that because the bar function is a static method. This means you can call it without regarding an instance of the containing class. IE you don't have to create an instance of the class to access that function.
You can read more about it - in the documentation
This is called class attribute
which could be accessed directly by MyClass.foo, and owned by the class.
It's not owned by the instances of the class
for self this is instance variable, each instance of a class has a new copy of the variables
Isn't foo local to the class MyClass?
Actually, no. It's local to the class statement's body, which the bar function cannot access. Once the class object created and bound to MyClass, foo becomes an attribute of the class object (just like bar FWIW), but that's namespace, not scope.
Also and FWIW, Python's staticmethod dont access the class itself. If you want a method that needs to access the class, use a classmethod instead.
In Python, the concept of "local variables" really fully exists only in functions. A function (method) inside a class does not have implicit access to the class's (or instance's) scope; you must explicitly specify the object containing the desired attribute, i.e., the class or the instance (by convention passed to the method as self). As to why it was designed that way... you'd have to ask Guido, but the Zen of Python says "explicit is better than implicit" so that might have something to do with it.