defining variables inside a function belonging to a class - python

In a code, there is a class that has a function named 'goal_callback'. In the function, variables are defined using .init prefix and others are defined normally without the prefix.
I know that the self. prefix is used to make the variable a 'class variable' so that it can be accessible to every function in class. So in the code, I have, only one function present, does it make any difference if we define the variables with the self. prefix or not.
What exactly will be the difference between the '_pub_takeoff' variable and the 'takeoff_or_land' variable?
#! /usr/bin/env python
class CustomActionMsgClass(object):
def __init__(self):
self._as = actionlib.SimpleActionServer("action_custom_msg_as", CustomActionMsgAction,
self.goal_callback, False)
def goal_callback(self, goal):
success = True
r = rospy.Rate(1)
self._pub_takeoff = rospy.Publisher('/drone/takeoff', Empty, queue_size=1)
self._takeoff_msg = Empty()
self._land_msg = Empty()
# Get the goal word: UP or DOWN
takeoff_or_land = goal.goal #goal has attribute named 'goal'.
if __name__ == '__main__':
rospy.init_node('action_custom_msg')
CustomActionMsgClass()
rospy.spin()

Here is an example for object-level and class-level variables.
class A(object):
Z = 3 # class variable. Upper-case is good code style for class-level variables
# defined inside the class but outsize of it's methods
def __init__(self):
self.x = 1 # object variable
y = 2 # local variable; it will lost after returning from the function
def some_method(self):
self.w = 4 # object variable too
# Note that it is not recommended to define
# object variables outside of __init__()
In your code _pub_takeoff is variable of the object; takeoff_or_land is local variable.

Related

See function stop from locating defined class in Python

I'd like to define a class inside a function (for testing purpose) and put a value into
a function variable:
def foo():
myvar = None
class myclass:
def run(self):
myvar = 5
mm = myclass()
mm.run()
print(myvar)
The above prints None
Is there any way other than global to make the myvar variable accessible from the class? The correct answer would print 5
It's not possible to assign a value to a variable outside the current scope without global. If you need to persist the value within the class you can define class variables instead. Example:
def foo():
class Class:
var_to_change = None
def run (self):
self.var_to_change = 5
print (Class.var_to_change)
instance = Class()
instance.run()
print (Class.var_to_change)
I haven't tested the above code but it should work in theory.

How to access variable of a nested functions in python?

I need to access a variable which is set in a nested function. I'm reading this variable data from another thread. What is the best way to obtain the data without doing any scope violation?
Here is the code snippet,
class main(object):
def sub_fun(self):
def inner_fun(self):
self.var = 10
inner_fun(self)
p = main().sub_fun()
Now how to access the var attribute of p?
class main(object):
def sub_fun(self):
def inner_fun(self):
self.var = 10
p = main()
You cannot access the nested function's variable because its a closure & is accessible only to the immediate parent. var is only accessible by inner_fun. See below for a different implementation.
class main(object):
def outer_function(self):
def inner_function(self):
self.x = 10
return self.x
out = inner_function(self) # Accessing the inner function
return out
p = main()
q = p.outer_function()
print(q)
If there is a need for a class object or a parent function to access a variable inside a child nested function, then the variable should be hoisted to the outer scope by returning it. Otherwise the scope of the variable will reside only in the so called child nested function.
The problem is that main.sub_fun returns None. There are two simple workarounds:
Just store a reference to the item you create before calling the method:
p = main()
p.sub_fun()
print(p.var)
This is the best option in my opinion.
If you really want the one line version to work, return self from sub_fun:
def sub_fun(self):
def inner_fun():
self.var = 10
inner_fun()
return self
print(main().sub_fun().var)
In neither case do you need to pass self to inner_fun. It will always look into the outer scope when the local name is not found. #2 shows an example of this.

Calling class-specific method from another class

I am working in a class called AlgoSystem, which is given strategy_0 and strategy_1 as inputs under initialization as well as the number of strategies (2 in this case). The strategy classes are stored in a dictionary called "strategies" within the AlgoSystem. Both strategy_0 and strategy_1 are different classes themselves, but both with a function called "__on_tick". These functions I want to call from within the AlgoSystem class.
My current attempt to do this is seen below:
class AlgoSystem:
def __init__(self, strategy_0, strategy_1, numstrategies):
self.var= 1
self.strategies = {0 : strategy_0,
1 : strategy_1}
self.num_strategies = numstrategies
def start(self):
for i in range(self.num_strategies):
self.strategies[i].__on_tick(self.var)
class Strategy_zero:
def __init__(self, x):
self.x = x
def __on_tick(self, var):
self.x = self.x + var
print(self.x)
class Strategy_one:
def __init__(self, y):
self.y = y
def __on_tick(self, var):
self.y = self.y - var
print(self.y)
strategy_0 = Strategy_zero(2)
strategy_1 = Strategy_one(4)
num_strategies = 2
system = AlgoSystem(strategy_0, strategy_1, 2)
system.start()
When I run the code above, I am given the error:
Strategy_zero' object has no attribute '_AlgoSystem__on_tick'
Apparently I'm not calling the class-functions "__on_tick" properly. How should I do this? I need to do it in a way, so I keep track on the changes of the two sub-classes (strategy_0 and strategy_1) through my defined dictionary within AlgoSystem: "strategies".
The double underscore prefix is specifically designed to prevent you from doing exactly what you are doing.
There is no reason for you to use it here. Remove the prefix and can your methods just on_tick.
Double underscore names are hidden names (hidden by obfuscation). I suggest having your on_tick method be called on_tick and try again.
The following code might help clarify what's going on with name-mangling.
class A:
def __mangled(self):
print "Class A name-mangled method"
class B:
def __init__(self):
a = A()
try:
a.__mangled()
except AttributeError:
# an attempt to access a name-mangled method assumes that
# the '_{class_name}' prefix should use 'B' as the class name
print "A instance has no attribute '_B__mangled'"
a._A__mangled()
# prints "Class A name-mangled method"
getattr(a, '_{}__mangled'.format(a.__class__.__name__))()
# same thing, but can be done without knowing the class name
B()
So, you could update self.strategies[i].__on_tick(self.var) to be:
strat = self.strategies[i]
getattr(strat, '_{}__on_tick'.format(strat.__class__.__name__)(self.var)
But, it would probably be best to not precede __on_tick with a double-underscore since it is intended to be accessed outside the class/instance.

python using __init__ vs just defining variables in class - any difference?

I'm new to Python - and just trying to better understand the logic behind certain things.
Why would I write this way (default variables are in __init__):
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
Instead of this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
def insert( self, word ):
#...
def finish( self ):
#...
I mean - why do I need to use __init__ -> if I can just as easily add default variables to a class directly?
When you create variables in the Class, then they are Class variables (They are common to all the objects of the class), when you initialize the variables in __init__ with self.variable_name = value then they are created per instance and called instance variables.
For example,
class TestClass(object):
variable = 1
var_1, var_2 = TestClass(), TestClass()
print var_1.variable is var_2.variable
# True
print TestClass.variable is var_1.variable
# True
Since variable is a class variable, the is operator evaluates to True. But, in case of instance variables,
class TestClass(object):
def __init__(self, value):
self.variable = value
var_1, var_2 = TestClass(1), TestClass(2)
print var_1.variable is var_2.variable
# False
print TestClass.variable is var_1.variable
# AttributeError: type object 'TestClass' has no attribute 'variable'
And you cannot access an instance variable, with just the class name.
When you write this:
class Dawg:
previousWord = ""
root = DawgNode()
uncheckedNodes = []
minimizedNodes = {}
Those are not instance variables, they're class variables (meaning: the same variables with the same values are shared between all instances of the class.) On the other hand, this:
class Dawg:
def __init__(self):
self.previousWord = ""
self.root = DawgNode()
self.uncheckedNodes = []
self.minimizedNodes = {}
... Is declaring instance variables, meaning: the values are different for each instance of the class. As you see, each snippet means a completely different thing, and you have to pick the one that is appropriate for you. Hint: most of the time you're interested in instance variables, because class variables define a kind of shared global state for your objects, which is error prone.

How to reference a static attribute from within a class in Python?

I have the following python snippet:
class myClass:
myVar = 'a'
def __init__(self):
self.myOtherVar = 'b'
myVar = 'c' # Gets assigned but only as a local variable.
print myVar # prints 'a' !
print self.myOtherVar # says 'self' not found
My question is this;
What's the proper way to print the contents of myVar from within myClass and/or re-assign them from init?
The problem you are facing is because you don't understand how the scoping of class declarations work. A class declaration is executed in its own scope. After the execution is completed a new class object is created and the obtained scope is attached to the class as its __dict__.
Note: the class scope is not searched from within the methods scopes! This means that you have to reference class attributes as MyClass.attribute when inside a method definition.
For example:
class MyClass:
var = 1
# we are executing this code as a single block
# so you must reference the variable as is usual
print(var)
# default values are *not* inside the definition.
# they are evaluated in the outer scope, so use plain "var" here
def method(self, a_default=var):
print(a_default)
def other_method(self):
# inside methods you are in a different scope
print(MyClass.var)
# equivalent *if* no "var" instance attributes exists
print(self.var)
Note: since the class doesn't still exist when executing its declaration you cannot refer to MyClass at the "top level" of MyClass declaration:
class MyClass:
var = 1
print(MyClass.var) # error: MyClass still doesn't exist.
A side effect of this, is that the following code:
class MyClass:
x = 1
results = list(i+x for i in range(10))
Produces:
NameError Traceback (most recent call last)
<ipython-input-6-f1d4417b2e52> in <module>()
----> 1 class MyClass:
2 x = 1
3 results = list(i+x for i in range(10))
4
<ipython-input-6-f1d4417b2e52> in MyClass()
1 class MyClass:
2 x = 1
----> 3 results = list(i+x for i in range(10))
4
<ipython-input-6-f1d4417b2e52> in <genexpr>(.0)
1 class MyClass:
2 x = 1
----> 3 results = list(i+x for i in range(10))
4
NameError: name 'x' is not defined
Because generator expressions (and list-comprehensions in python3) are, in fact, considered functions with their own scope. Since the class scope isn't searched from inner function scopes the x cannot be found.
You can word around this using a function definition and default values:
class MyClass:
x = 1
def _make_results(x=x):
return list(i+x for i in range(10))
results = _make_results()
del _make_results # otherwise it would be added as a method.
# or:
results = (lambda x=x: list(i+x for i in range(10)))()
This isn't usually a problem since class definitions rarely contain anything other than method definitions and a few constants.
There are already a few questions on SO about class scopes:
The scope of names defined in class block doesn't extend to the methods' blocks. Why is that?
Short Description of the Scoping Rules?
Nested classes' scope?
Variable scopes in python classes
Why static binding works differently for class and function?
self.var will:
give var in self.__dict__ if present
give var in self.__class__.__dict__ if present
AttributeError
So use this or self.__class__.var if you want to access the static variable minding inheritance. If you extend myClass, the children instances will access the static variable in the child class.
If you want to access the static variable in myClass even when called from descendants, use myClass.var.
As for reassigning them, this must be done explicitly on the class object, or the assignment will just target the instance.
class myClass:
myVar = 'a'
def __init__(self):
self.myOtherVar = 'b'
print myVar # -> 'a'
class EmptyClass: pass
s = EmptyClass()
__init__(s)
myVar = s.myOtherVar
print myVar # -> 'b'
print myClass.myVar # -> 'b'

Categories

Resources