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
Related
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]
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.
I am trying to understand what does this class
class undo:
def __init__(self, ss):
self.ss = ss
In my head it should simply put the value of ss uniquely in the variables i decide to use,but when I'm using it it rewrites all the variables, as if it was shared.
sum_expenses[100][0] = 100
sum_expenses[99][2] = 99
s = 1
a = [0 for i in range(100)]
a[s] = undo(sum_expenses)
output(a[1].ss)
sum_expenses[100][0] = 0
b = undo(sum_expenses)
print " "
print b.ss
print " "
sum_expenses[99][2] = 1
a[2] = undo(sum_expenses)
print a[2].ss
I do not understand why it overwrites all the variables with the current values of sum_expense, when I try to put it individually so that I can use the past values of sum_expenses.
Thank you and have a good day!
It happens because you're giving __init__ a reference to the list. If you change the list somewhere else, the reference in .ss still points to the same list, so the changes are visible there, too.
You could copy the list, since it's 2D try deepcopy.
Everytime you call this function it overrides reference to thr whole array ss, changing it to the new one you just passed to the constructor.
You can also create this array within the class and pass indexes and value to it like so:
undo.add(index1,index2,value)
Or you can make another variable ss_old and have make the function return that variable before you set it to a new value.
I've created new class based on default str class. I've also changed default methods like __add__, __mul__, __repr__ etc. But I want to change default behaviour when user equal new variable to old one. Look what I have now:
a = stream('new stream')
b = a
b += ' was modified'
a == b
>>> True
print a
>>> stream('new stream was modified')
print b
>>> stream('new stream was modified')
So as you see each time I modify second variable Python also changes original variable. As I understand Python simply sends adress of variable a to variable b. Is it possible to make a copy of variable on creation like in usual str? As I think I need smth like new in C++.
a = 'new string'
b = a
b += ' was modified'
a == b
>>> False
P.S. Creation of the object begins in self.new() method. Creation is made like this:
def __new__(self, string):
return(str.__new__(self, string))
It is more complicated, because it takes care of unicode and QString type, first getting str object from them, but I think it's not neccessary.
I don't believe you can change the behavior of the assignment operator, but there are explicit ways to create a copy of an object rather than just using a reference. For a complex object, take a look at the copy module. For a basic sequence type (like str), the following works assuming you're implementing slice properly:
Code
a = str('abc')
#A slice creates a copy of a sequence object.
#[:] creates a copy of the entire thing.
b = a[:]
#Since b is a full copy of a, this will not modify a
b += ' was modified'
#Check the various values
print('a == b' + str(a == b))
print(a)
print(b)
Output
False
abc
abc was modified
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.