Python multi-instances use the same variable - python

I want to use a variable for two instances in python.
When a instance update the variable, it also be updated in other instances.
my variable is task_id:
class Task(object): # pragma: no cover
def run_deploy(self, args, **kwargs):
# atexit.register(atexit_handler)
self.task_id = kwargs.get('task_id', str(uuid.uuid4()))
def start_benchmark(self, args, **kwargs):
"""Start a benchmark scenario."""
atexit.register(atexit_handler)
self.task_id = kwargs.get('task_id', str(uuid.uuid4()))
But when I run code, I detected that task_id has different value, I want they have same value.
Please let me know how to do it.
Thanks!

To reference an object in python is trivial. Here is a simple example using a class instance:
class cl:
var1 = 0
def __init__(self, var2):
self.var2 = var2
Lets look at two instances of this class and how they update:
>>> x = cl(1) #
>>> y=x
>>> print(y.var2)
1
>>> y.var2 = 2
>>> print(x.var2)
2
And now comes the crucial part:
>>> x is y
True
Don't forget that ìs is not the same as ==.
The same happens also to var1 for both instances.

In python, everything is a reference. A variable is merely a name you give to a reference to an object. You can give many names to refer to the same object.
This pretty much how python works, and it's exactly what you need here.
E.g.:
a = [] # a reference to an empty list, named "a"
b = a # a reference to the same empty list, named "b"
a.append(5) # modify, through the "a" reference
print(b) # "b" still refers to the same list, which is not empty now
=> [5]

Related

Python: understanding class and instance variables

I think I have some misconception about class and instance variables. Here is an example code:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.energy -= 1
def new_skill(self, skill):
self.skills.append(skill)
if __name__ == '__main__':
a1 = Animal()
a2 = Animal()
a1.work()
print a1.energy # result:9
print a2.energy # result:10
a1.new_skill('bark')
a2.new_skill('sleep')
print a1.skills # result:['bark', 'sleep']
print a2.skills # result:['bark', 'sleep']
I thought that energy and skill were class variables, because I declared them out of any method. I modify its values inside the methods in the same way (with self in his declaration, maybe incorrect?). But the results show me that energy takes different values for each object (like a instance variable), while skills seems to be shared (like a class variable). I think I've missed something important...
The trick here is in understanding what self.energy -= 1 does. It's really two expressions; one getting the value of self.energy - 1, and one assigning that back to self.energy.
But the thing that's confusing you is that the references are not interpreted the same way on both sides of that assignment. When Python is told to get self.energy, it tries to find that attribute on the instance, fails, and falls back to the class attribute. However, when it assigns to self.energy, it will always assign to an instance attribute, even though that hadn't previously existed.
You are running into initialization issues based around mutability.
First, the fix. skills and energy are class attributes.
It is a good practice to consider them as read only, as initial values for instance attributes. The classic way to build your class is:
class Animal(object):
energy = 10
skills = []
def __init__(self,en=energy,sk=None):
self.energy = en
self.skills = [] if sk is None else sk
....
Then each instance will have its own attributes, all your problems will disappear.
Second, what's happening with this code?
Why is skills shared, when energy is per-instance?
The -= operator is subtle. it is for in-place assignation if possible. The difference here is that list types are mutable so in-place modification often occurs:
In [6]:
b=[]
print(b,id(b))
b+=['strong']
print(b,id(b))
[] 201781512
['strong'] 201781512
So a1.skills and a2.skills are the same list, which is also accessible as Animal.skills. But energy is a non-mutable int, so modification is impossible. In this case a new int object is created, so each instance manages its own copy of the energy variable:
In [7]:
a=10
print(a,id(a))
a-=1
print(a,id(a))
10 1360251232
9 1360251200
Upon initial creation both attributes are the same object:
>>> a1 = Animal()
>>> a2 = Animal()
>>> a1.energy is a2.energy
True
>>> a1.skills is a2.skills
True
>>> a1 is a2
False
When you assign to a class attribute, it is made local to the instance:
>>> id(a1.energy)
31346816
>>> id(a2.energy)
31346816
>>> a1.work()
I do something
>>> id(a1.energy)
31346840 # id changes as attribute is made local to instance
>>> id(a2.energy)
31346816
The new_skill() method does not assign a new value to the skills array, but rather it appends which modifies the list in place.
If you were to manually add a skill, then the skills list would be come local to the instance:
>>> id(a1.skills)
140668681481032
>>> a1.skills = ['sit', 'jump']
>>> id(a1.skills)
140668681617704
>>> id(a2.skills)
140668681481032
>>> a1.skills
['sit', 'jump']
>>> a2.skills
['bark', 'sleep']
Finally, if you were to delete the instance attribute a1.skills, the reference would revert back to the class attribute:
>>> a1.skills
['sit', 'jump']
>>> del a1.skills
>>> a1.skills
['bark', 'sleep']
>>> id(a1.skills)
140668681481032
Access the class variables through the class, not through self:
class Animal(object):
energy = 10
skills = []
def work(self):
print 'I do something'
self.__class__.energy -= 1
def new_skill(self, skill):
self.__class__.skills.append(skill)
Actually in you code
a1.work();
print a1.energy;
print a2.energy
when you are calling a1.work() an instance variable for a1 object is getting created with the same name that is 'energy'.
And When interpreter comes to 'print a1.energy' it execute the instance variable of object a1.
And when interpreter comes to 'print a2.energy' it execute the class variable, and since you have not changed the value of class variable it shows 10 as output.

Print Pass by Value in Python?

The class is given below, this will print 20_20. Now till the line 5 code is same, I don't want the value of T.a to change when i change value of T1.a. How to solve it?
class Test:
def __init__(self, val):
self.a = val
T = Test(10)
T1 = T
T1.a = 20
print T.a + '__' + T1.a
Expected Output Is 10_20 .
In line 6. T1 = T, you are telling python to make a new reference to object T called T1.
i dont want the value of T.a to change when i change value of T1.a
This can't be done the way you set it up since T and T1 point to the same object. You can see this by noting that T is T1 evaluates to True in the python interpreter.
It seems maybe that you want to instantiate 2 Test objects, each with its own a property, so that changing one object won't affect the other.
You could also use the copy method of the copy module:
import copy
T = Test(20)
T1 = copy.copy(T)
T1.a = 40
print T.a
# Output 20
print T1.a
# Output 40
For more info check out the copy docs, https://docs.python.org/2/library/copy.html
The thing you want to do is probably called "deep copying" https://docs.python.org/2/library/copy.html
this allows you to create a copy of an existing object, instead of a reference. That is the closest thing to pass by value, I can think of, when using objects.
By making T1=T you are making both of them same so if you change T1 it will affect T and vice versa . You could use copy,deep copy etc
class Test:
def __init__(self, val):
self.a = val
T = Test (10)
T1 = Test(20)
print str(T.a) + '__' + str(T1.a)
see this link for more on mutuable and non-mutable object assignment and value changing

Making a variable cross module in Python - Within a class and function

I'm trying to use a variable in other python modules, like this:
In a.py:
class Names:
def userNames(self):
self.name = 'Richard'
In z.py:
import a
d = a.Names.name
print d
However this doesn't recognise the variable name and the following error is received:
AttributeError: type object 'Names' has no attribute 'name'
Thanks
There are lots of different scopes a variable can be bound to, which is what you seem to be confused about. Here are a few:
# a.py
a = 1 # (1) is module scope
class A:
a = 2 # (2) is class scope
def __init__(self, a=3): # (3) is function scope
self.a = a # (4) self.a is object scope
def same_as_class(self):
return self.a == A.a # compare object- and class-scope variables
def same_as_module(self):
return self.a == a # compare object- and module-scope variables
Now see how these different variables (I only called them all a to make the point, please don't do this for real) are named, and how they all have different values:
>>> import a
>>> a.a
1 # module scope (1)
>>> a.A.a
2 # class scope (2)
>>> obj1 = a.A() # note the argument defaults to 3 (3)
>>> obj1.a # and this value is bound to the object-scope variable (4)
3
>>> obj.same_as_class()
False # compare the object and class values (3 != 2)
>>> obj2 = a.A(2) # now create a new object, giving an explicit value for (3)
>>> obj2.same_as_class()
True
Note we can also change any of these values:
>>> obj1.same_as_module()
False
>>> obj1.a = 1
>>> obj1.same_as_module()
True
For reference, your z.py above should probably look like:
import a
n = a.Names()
d.userNames()
d = n.name
print d
because a.Name is a class, but you're trying to refer to an object-scope variable. An object is an instance of a class: I've called my instance n. Now I have an object, I can get at the object-scope variable. This is equivalent to Goranek's answer.
In terms of my previous example, you were trying to access obj1.a without having an obj1 or anything like it. I'm not really sure how to make this clearer, without turning this into an introductory essay on OO and Python's type system.
"I've checked again and it's because I'm importing from is a Tornado Framework and the variable is within a class."
Accordingly, your problem is not the one shown in your question.
If you actually want to access the variable of a class (and likely, you don't), then do this:
from othermodule import ClassName
print ClassName.var_i_want
You probably want to access the variable as held inside an instance:
from othermodule import ClassName, some_func
classnameinstance = some_func(blah)
print classnameinstance.var_i_want
Update Now that you have completely changed your question, here is the answer to your new question:
IN this code:
class Names:
def userNames(self):
name = 'Richard'
name is not a variable accessible outside of the activation of the method userNames. This is known as a local variable. You would create an instance variable by changing the code to:
def userNames(self):
self.name = 'Richard'
Then, if you have an instance in a variable called classnameinstance you can do:
print classnameinstance.name
This will only work if the variable has been already created on the instance, as by calling userNames.
You don't need to import the class itself if there is some other way to receive instances of the class.
file:a.py
class Names:
def userNames(self):
self.name = 'Richard'
file:z.py
import a
c = a.Names()
c.userNames()
what_you_want_is = c.name
Btw, this code makes no sense..but this is apparently what you want
Better a.py
class Names:
def userNames(self, name):
self.name = name
Better z.py
import a
c = a.Names()
c.userNames("Stephen or something")
what_you_want_is = c.name
# what_you_want_is is "Stephen or something"

Best of two ways to declare a class variable in Python

The way I usually declare a class variable to be used in instances in Python is the following:
class MyClass(object):
def __init__(self):
self.a_member = 0
my_object = MyClass()
my_object.a_member # evaluates to 0
But the following also works. Is it bad practice? If so, why?
class MyClass(object):
a_member = 0
my_object = MyClass()
my_object.a_member # also evaluates to 0
The second method is used all over Zope, but I haven't seen it anywhere else. Why is that?
Edit: as a response to sr2222's answer. I understand that the two are essentially different. However, if the class is only ever used to instantiate objects, the two will work he same way. So is it bad to use a class variable as an instance variable? It feels like it would be but I can't explain why.
The question is whether this is an attribute of the class itself or of a particular object. If the whole class of things has a certain attribute (possibly with minor exceptions), then by all means, assign an attribute onto the class. If some strange objects, or subclasses differ in this attribute, they can override it as necessary. Also, this is more memory-efficient than assigning an essentially constant attribute onto every object; only the class's __dict__ has a single entry for that attribute, and the __dict__ of each object may remain empty (at least for that particular attribute).
In short, both of your examples are quite idiomatic code, but they mean somewhat different things, both at the machine level, and at the human semantic level.
Let me explain this:
>>> class MyClass(object):
... a_member = 'a'
...
>>> o = MyClass()
>>> p = MyClass()
>>> o.a_member
'a'
>>> p.a_member
'a'
>>> o.a_member = 'b'
>>> p.a_member
'a'
On line two, you're setting a "class attribute". This is litterally an attribute of the object named "MyClass". It is stored as MyClass.__dict__['a_member'] = 'a'. On later lines, you're setting the object attribute o.a_member to be. This is completely equivalent to o.__dict__['a_member'] = 'b'. You can see that this has nothing to do with the separate dictionary of p.__dict__. When accessing a_member of p, it is not found in the object dictionary, and deferred up to its class dictionary: MyClass.a_member. This is why modifying the attributes of o do not affect the attributes of p, because it doesn't affect the attributes of MyClass.
The first is an instance attribute, the second a class attribute. They are not the same at all. An instance attribute is attached to an actual created object of the type whereas the class variable is attached to the class (the type) itself.
>>> class A(object):
... cls_attr = 'a'
... def __init__(self, x):
... self.ins_attr = x
...
>>> a1 = A(1)
>>> a2 = A(2)
>>> a1.cls_attr
'a'
>>> a2.cls_attr
'a'
>>> a1.ins_attr
1
>>> a2.ins_attr
2
>>> a1.__class__.cls_attr = 'b'
>>> a2.cls_attr
'b'
>>> a1.ins_attr = 3
>>> a2.ins_attr
2
Even if you are never modifying the objects' contents, the two are not interchangeable. The way I understand it, accessing class attributes is slightly slower than accessing instance attributes, because the interpreter essentially has to take an extra step to look up the class attribute.
Instance attribute
"What's a.thing?"
Class attribute
"What's a.thing? Oh, a has no instance attribute thing, I'll check its class..."
I have my answer! I owe to #mjgpy3's reference in the comment to the original post. The difference comes if the value assigned to the class variable is MUTABLE! THEN, the two will be changed together. The members split when a new value replaces the old one
>>> class MyClass(object):
... my_str = 'a'
... my_list = []
...
>>> a1, a2 = MyClass(), MyClass()
>>> a1.my_str # This is the CLASS variable.
'a'
>>> a2.my_str # This is the exact same class variable.
'a'
>>> a1.my_str = 'b' # This is a completely new instance variable. Strings are not mutable.
>>> a2.my_str # This is still the old, unchanged class variable.
'a'
>>> a1.my_list.append('w') # We're changing the mutable class variable, but not reassigning it.
>>> a2.my_list # This is the same old class variable, but with a new value.
['w']
Edit: this is pretty much what bukzor wrote. They get the best answer mark.

python binding of variable to particular expression

I am developing a simple application which hava a file Constants.py containing all configuration, it is like this
x = y
during execution of program , the value of y changes , I want value of x o get updated too , automatically, this can be reffered as binding, how can I achieve this
In Python variable names point at values. x=y tells Python that the variable name x should point at the value that y is currently pointing at.
When you change y, then the variable name y points at a new value, while the variable name x still points at the old value.
You can not achieve what you want with plain variable names.
I like KennyTM's suggestion to define x as a function since it makes explicit that the value of x requires running some code (the lookup of the value of y).
However, if you want to maintain a uniform syntax (making all the constants accessible in the same way), then you could use a class with properties (attributes which call getter and setter functions):
Constants.py:
class BunchOConstants(object):
def __init__(self, **kwds):
self.__dict__.update(kwds)
#property
def x(self):
return self.y
#x.setter
def x(self,val):
self.y=val
const=BunchOConstants(y=10,z='foo')
Your script.py:
import Constants
const=Constants.const
print(const.y)
# 10
print(const.x)
# 10
Here you change the "constant" y:
const.y='bar'
And the "constant" x is changed too:
print(const.x)
# bar
You can change x also,
const.x='foo'
and y too gets changed:
print(const.y)
# foo
If you change the value (object) itself, then all references to it will be updated:
>>> a = []
>>> b = a # b refers to the same object a is refering right now
>>> a.append('foo')
>>> print b
['foo']
However, if you make the name point to some other object, then other names will still reference whatever they were referencing before:
>>> a = 15
>>> print b
['foo']
That's how python works. Names are just references to objects. You can make a name reference the same object another name is referencing, but you can't make a name reference another name. Name attribution using the = operator (a = 15) changes what a refers to, so it can't affect other names.
if your configuration values are inside a class, you could do something like this:
>>> class A(object):
... a = 4
... #property
... def b(self):
... return self.a
...
then, every time you access b, it will return the value of a.
There is a simple solution you can do. Just define a property and ask for the fget value you defined.
For example:
a = 7
#property
def b():
return a
if you ask for b, you will get something like this <property object at 0x1150418> but if you do b.fget(), you will obtain the value 7
Now try this:
a = 9
b.fget() # this will give you 9. The current value of a
You don't need to have a class with this way, otherwise, I think you will need it.

Categories

Resources