Scopes in a class in Python - python

Please have a look at this:
class Car:
def __init__(self, bid_code):
self.__bid = bid_code
def doit(self, cry):
self.bid_it = cry
def show_bid(self):
print self.__bid
def show_it(self):
print self.bid_it
a = Car("ok")
a.show_bid()
a.doit("good")
a.show_it()
What is the scope of bid_it here? I thought it was a local variable, because it is inside a def block. How is it possible that I can call it outside the function? I haven't declared that bid_it is global.
Thanks

By using self, you've bound it to the instance. It's now an instance variable. Instance variables are local to their instances. If the variable were unbound (no self prefix), it'd have function scope and go out of scope once the method call is over, but you've bound it to something else (the instance).

def doit(self, cry):
self.bid_it = cry
'self' acts like a this pointer in c++, in this case a reference to a Car object. If bid_it is not defined in self, it's created on the fly and assigned a value. This means that you can create it anywhere, just as long as you have a reference to your object.

Related

Python object initialization and order of method evaluation

Asking just out of curiosity:
Intuitively, I would tend to think that the code below would fail because the __init__ function calls somefunc to populate somevar before the function was defined in the object's body, as would be the case for functions within a module.
Could you explain why this code actually works?
Thanks,
class someobj:
def __init__(self):
self.somevar = self.somefunc()
def somefunc(self):
return 'some_value'
obj = someobj()
print(obj.somevar)
Calling def assigns the function code, variables etc to its name, but doesn't run the internal code. Documentation.
The interpretater looks at this script and says
I'll define a class (basically a namespace)
Inside the class, I'll DEFINE class.init
Another define call; I'll DEFINE class.somefumc
Now the init is called by the constructor and the somefunc method is already defined.

Why class definition needs more information of its attributes than what is needed in a function definition?

def myfunc():
return x
x = 10
print(myfunc())
The above codes work, where the free variable x does not need to be defined when I define myfunc.
However, the following codes do not work:
class myclass:
func = extfunc
def extfunc(self):
return 'hello'
Here I need to move the definition of extfunc before the class definition, in order to make the codes work.
Why does class definition need more information of its attributes than what is needed for a free variable in a function definition?
This code:
def myfunc():
return x
defines a function, but doesn't execute the code inside it where x is until/unless myfunc is called. The body of the function isn't evaluated when the function definition is evaluated, it's evaluated later when the function is called.
In contrast, in this code:
class myclass:
func = extfunc
the class definition is evaluated in order to create the class, as described in the docs here. So func = extfunc is evaluated as part of class definition in order to assign a value to the func variable in the class scope. func is like a static member in languages that use that terminology.
A more direct comparison would be this:
class myclass:
def example(self):
return x
There, return x isn't evaluated until or unless example is called.
See also this example in the documentation:
Attribute references use the standard syntax used for all attribute references in Python: obj.name. Valid attribute names are all the names that were in the class’s namespace when the class object was created. So, if the class definition looked like this:
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
then MyClass.i and MyClass.f are valid attribute references, returning an integer and a function object, respectively.
In your example, myclass.func would be a valid reference immediately after the class definition, so func = extfunc must be evaluated during the class definition, unlike the body of a function.

Is it possible to call a static method from withing another static method

Is it possible to call a static method from within another static method?
I tried this:
class MyClass(object):
#staticmethod
def static_method_1(x):
x = static_method_2(x)
print x
#staticmethod
def static_method_2(x):
return 2*x
This returns
NameError: name 'static_method_2' is not defined
Staticmethods are called via the class: MyClass.static_method_2(x).
You probably don't want a staticmethod at all, but a classmethod. These are called the same way but get a reference to the class, which you can then use to call the other method.
class MyClass(object):
#classmethod
def static_method_1(cls, x):
x = cls.static_method_2(x)
print x
#classmethod
def static_method_2(cls, x):
return 2*x
Note, in Python you wouldn't ever do this. There's usually no reason to have a class unless it is storing state. These would probably both be best as standalone functions.
A static method must be invoked via the class that defines it; otherwise, that's just about the only difference between it and a regular function.
#staticmethod
def static_method_1(x):
x = MyClass.static_method_2(x)
print x
The reason is that the name static_method_2 isn't defined in the global scope, or in any other non-local scope (remember, a class does not define a new scope). The static method is simply an attribute of MyClass, and has to be accessed as such.

Do class/static variables have access to static methods?

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.

Python - Static Variable inside Function

I am trying to set a static variable inside a function. Essentially, I want this variable to be false initially. After the first time this function is called, I want the variable to be set to true.
I currently have the following:
class LKTracker(object):
def track_points(self,width,height):
if not hasattr(track_points, "gotInitialFeatures"):
track_points.gotInitialFeatures = None
if not track_points.gotInitialFeatures:
#do some stuff
track_points.gotInitialFeatures = True
With this code, I keep receiving the following error:
NameError: global name 'track_points' is not defined
Anyone know what is happening here?
In a global function, you can refer directly to the function object by looking up the name.
This does not work in a method; you'd have to look the method up on the class instead:
LKTracker.track_points
This still won't do what you want, however, because you'd get a unbound method object at that moment:
>>> LKTracker.track_points
<unbound method LKTracker.track_points>
Method objects are created on demand (because functions are descriptors), and creating an attribute on a method object is futile; they generally only live for a short while.
You'd need to access the function instead:
>>> LKTracker.track_points.__func__
<function track_points at 0x103e7c500>
but you can do the same thing on self:
self.track_points.__func__
Now you can add a attribute:
track_points = self.track_points.__func__
if not hasattr(track_points, "gotInitialFeatures"):
track_points.gotInitialFeatures = None
if not track_points.gotInitialFeatures:
#do some stuff
track_points.gotInitialFeatures = True
But it would be much easier to just store that attribute on the class instead:
if not hasattr(LKTracker, 'gotInitialFeatures'):
You shall init static variable before call a function.
def static_var(varname, value):
def decorate(func):
setattr(func, varname, value)
return func
return decorate
and now you can:
#static_var("gotInitialFeatures", False)
def track_points(self, width, height):
...

Categories