How do I replace a python object everywhere with another object?
I have two classes, SimpleObject and FancyObject. I've created a SimpleObject, and have several references to it. Now I'd like to create a FancyObject, and make all those references point to the new object.
a = SimpleObject()
some_list.append(a)
b = FancyObject()
a = b is not what I want, it just changes what a points to. I read the following would work, but doesn't. I get an error "Attribute __dict__ is not writable":
a.__dict__ = b.__dict__
What I want is the equivalent of (pseudo-C):
*a = *b
I know this is hacky, but is there any way to accomplish this?
There's no way. It'd let you mutate immutable objects and cause all sorts of nastiness.
x = 1
y = (x,)
z = {x: 3}
magic_replace(x, [1])
# x is now a list!
# The contents of y have changed, and z now has an unhashable key.
x = 1 + 1
# Is x 2, or [1, 1], or something stranger?
You can put that object in global namespace of separate module and than monkey patch it when you need.
objstore.py:
replaceable = object()
sample.py:
import objstore
b = object()
def isB():
return objstore.replaceable is b
if __name__ == '__main__':
print isB()#False
objstore.replaceable = b
print isB()#True
P.S. Rely on monkey patching is a symptom of bad design
PyJack has a function replace_all_refs that replaces all references to an object in memory.
An example from the docs:
>>> item = (100, 'one hundred')
>>> data = {item: True, 'itemdata': item}
>>>
>>> class Foobar(object):
... the_item = item
...
>>> def outer(datum):
... def inner():
... return ("Here is the datum:", datum,)
...
... return inner
...
>>> inner = outer(item)
>>>
>>> print item
(100, 'one hundred')
>>> print data
{'itemdata': (100, 'one hundred'), (100, 'one hundred'): True}
>>> print Foobar.the_item
(100, 'one hundred')
>>> print inner()
('Here is the datum:', (100, 'one hundred'))
Calling replace_all_refs
>>> new = (101, 'one hundred and one')
>>> org_item = pyjack.replace_all_refs(item, new)
>>>
>>> print item
(101, 'one hundred and one')
>>> print data
{'itemdata': (101, 'one hundred and one'), (101, 'one hundred and one'): True}
>>> print Foobar.the_item
(101, 'one hundred and one')
>>> print inner()
('Here is the datum:', (101, 'one hundred and one'))
You have a number of options:
Design this in from the beginning, using the Facade pattern (i.e. every object in your main code is a proxy for something else), or a single mutable container (i.e. every variable holds a list; you can change the contents of the list through any such reference). Advantages are that it works with the execution machinery of the language, and is relatively easily discoverable from the affected code. Downside: more code.
Always refer to the same single variable. This is one implementation of the above. Clean, nothing fancy, clear in code. I would recommend this by far.
Use the debug, gc, and introspection features to hunt down every object meeting your criterion and alter the variables while running. The disadvantage is that the value of variables will change during code execution, without it being discoverable from the affected code. Even if the change is atomic (eliminating a class of errors), because this can change the type of a variable after the execution of code which determined the value was of a different type, introduces errors which cannot reasonably be anticipated in that code. For example
a = iter(b) # will blow up if not iterable
[x for x in b] # before change, was iterable, but between two lines, b was changed to an int.
More subtly, when discriminating between string and non-string sequences (because the defining feature of strings is that iterating them also yields strings, which are themselves iterable), when flattening a structure, code may be broken.
Another answer mentions pyjack which implements option 3. Although it may work, it has all of the problems mentioned. This is likely to be appropriate only in debugging and development.
Take advantage of mutable objects such as a list.
a = [SimpleObject()]
some_list.append(a)
b = FancyObject()
a[0] = b
Proof that this works:
class SimpleObject():
def Who(self):
print 'SimpleObject'
class FancyObject():
def Who(self):
print 'FancyObject'
>>> a = [SimpleObject()]
>>> a[0].Who()
SimpleObject
>>> some_list = []
>>> some_list.append(a)
>>> some_list[0][0].Who()
SimpleObject
>>> b = FancyObject()
>>> b.Who()
FancyObject
>>> a[0] = b
>>> some_list[0][0].Who()
FancyObject
Related
Are the following declarations different?
l1=list
l2=list()
As I used type() function, following were the results!
type(l1)
<class 'type'>
type(l2)
<class 'list'>
l1 is l2
False
These probably shows that l1 and l2 are not the same. Why does l1 belongs to class type and not class list
l1 = list means assignment of list class in l1 variable.
l2=list() mreans calling list() function to create a list and assign the list to l2 variable.
When you are calling list, you get an instance of it class:
>> l = list()
>> l
[]
but when you assign list to another variable, you are completely transforming all List information to another variable and you can use them as you can use List, for example :
>> a = List
>> l1 = a() # same as l1 = List()
>> l1
[]
>> a
List
>> isinstance(l1, a)
True
>> isinstance(l1, List)
True
I hope this might helps you understand.
In Python, nothing gets called unless you ask for it to be called, with parentheses. Even if there are no arguments. Without the parentheses, you're just referring to the function, or method, or class, or whatever as a value. (This is different from some other languages, like Ruby or Perl.)
This may be a little more obvious with functions or methods:
>>> input
<function input>
>>> abs
<function abs>
>>> 'abc'.upper
<function str.upper>
… but it's exactly the same with classes:
>>> list
list
Those are all perfectly good values, which we can even store in a variable:
>>> abcupper = 'abc'.upper
When you call a function or method, you know what that does. When you call a class, that's how you construct an instance of the class.
Either way, you need the parentheses:
>>> abs(-2)
2
>>> list((1, 2, 3))
[1, 2, 3]
… even if there are no arguments:
>>> 'abc'.upper()
'ABC'
>>> list()
[]
… even if you're calling a method you stored in a variable earlier:
>>> abcupper()
'ABC'
I understand that since unhashable types like lists are mutating, they cannot be used as a key for hashing. However, I don't see why their memory address (which I don't believe changes) can be used?
For example:
my_list = [1,2,3]
my_dict = {my_list: 1} #error
my_dict = {id(my_list): 1} # no error
You actually can use the memory address of an object as a hash function if you extend list, set, etc.
The primary reason using a memory address for a hash is bad is because if two objects are equal (a == b evaluates to True) we also want their hashes to be equal (hash(a) == hash(b) to be True). Otherwise, we could get unintended behavior.
To see an example of this, let's create our own class that extends list and use the memory address of the object as a hash function.
>>> class HashableList(list):
def __hash__(self):
return id(self) # Returns the memory address of the object
Now we can create two hashable lists! Our HashableList uses the same constructor as python's built-in list.
>>> a = HashableList((1, 2, 3))
>>> b = HashableList((1, 2, 3))
Sure enough, as we would expect, we get
>>> a == b
True
And we can hash our lists!
>>> hash(a)
1728723187976
>>> hash(b)
1728723187816
>>> hash(a) == hash(b)
False
If you look at the last 3 digits, you'll see a and b are close to each other in memory, but aren't in the same location. Since we're using the memory address as our hash, that also means their hashes aren't equal.
What happens if compare the built in hash of two equal tuples (or any other hashable object)?
>>> y = ('foo', 'bar')
>>> z = ('foo', 'bar')
>>> y == z
True
>>> hash(y)
-1256824942587948134
>>> hash(z)
-1256824942587948134
>>> hash(y) == hash(z)
True
If you try this on your own, your hash of ('foo', 'bar') won't match mine, since the hashes of strings changes every time a new session of python starts. The important thing is that, in the same session hash(y) will always equal hash(z).
Let's see what happens if we make a set, and play around with the HashableList objects and the tuples we made.
>>> s = set()
>>> s.add(a)
>>> s.add(y)
>>> s
{[1, 2, 3], ('foo', 'bar')}
>>> a in s # Since hash(a) == hash(a), we can find a in our set
True
>>> y in s # Since hash(y) == hash(y), we can find y in our set
True
>>> b in s
False
>>> z in s
True
Even though a == b, we couldn't find a in the set because hash(b) doesn't equal hash(a), so we couldn't find our equivalent list in the set!
My understanding of mutability and immutability in Python is, say we have a variable foo, if there exists a way to change how foo looks like (by using print) without changing its id, then foo is mutable. Otherwise, it's immutable.
For example, you can do this for a list,
foo = [1, 2, 3]
print(foo, id(foo))
foo[0] = 100
print(foo, id(foo))
but no way for int.
But what about function? First of all, is my definitions of mutability and immutability given above correct? If yes, can you find a way to mutate function without changing its id in order to prove it's mutable?
You can explicitly change the code of a function without affecting its id (here is code using python 2.7):
>>> def f():
... print "f"
...
>>> def g():
... print "g"
...
>>> id(f)
140305904690672
>>> f()
f
>>> f.func_code = g.func_code
>>> id(f)
140305904690672
>>> f()
g
I don't know if the heading makes sense... but this is what I am trying to do using list
>>> x = 5
>>> l = [x]
>>> l
[5]
>>> x = 6
>>> l
[5] # I want l to automatically get updated and wish to see [6]
>>>
The same happens with dict, tuple. Is there a python object that can store the dynamic value of variable?
Thanks,
There's no way to get this to work due to how the assignment operator works in Python. x = WHATEVER will always rebind the local name x to WHATEVER, without modifying what previously x was previously bound to.(*)
You can work around this by replacing the integers with a container data type, such as single-element lists:
>>> x = [5]
>>> l = [x]
>>> l
[[5]]
>>> x[0] = 6
>>> l
[[6]]
but that's really a hack, and I wouldn't recommend it for anything but experimentation.
(*) Rebinding may actually modify previously bound objects when their reference count drops to zero, e.g. it may close files. You shouldn't rely on that, though.
A variable is a place to store data. A datastructure is a place to store data. Pick the one which meets your needs.
You can do it with the numpy module.
>>> from numpy import array
>>> a = array(5)
>>> a
array(5)
>>> l = [a]
>>> l
[array(5)]
>>> a.itemset(6)
>>> a
array(6)
>>> l
[array(6)]
Generally a 0-D numpy array can be treated as any regular value as shown below:
>>> a + 3
9
However, if you need to, you can access the underlying object as such:
>>> a.item()
6
Here's a kind of hacky method of dynamic access that isn't very extensible/flexible in its given form, but could be used as a basis for something better.
>>> a = 7
>>> class l:
def a_get(self):
global a
return a
def a_set(self, value):
global a
a = value
a = property(a_get, a_set)
>>> c = l()
>>> c.a
7
>>> a = 4
>>> c.a
4
>>> c.a = 6
>>> a
6
I want to have a a reference that reads as "whatever variable of name 'x' is pointing to" with ints so that it behaves as:
>>> a = 1
>>> b = 2
>>> c = (a, b)
>>> c
(1, 2)
>>> a = 3
>>> c
(3, 2)
I know I could do something similar with lists by doing:
>>> a = [1]
>>> b = [2]
>>> c = (a, b)
>>> c
([1], [2])
>>> a[0] = 3
>>> c
([3], [2])
but this can be easily lost if one assigns a or b to something instead of their elements.
Is there a simple way to do this?
No, there isn't a direct way to do this in Python. The reason is that both scalar values (numbers) and tuples are immutable. Once you have established a binding from a name to an immutable value (such as the name c with the tuple (1, 2)), nothing you do except reassigning c can change the value it's bound to.
Note that in your second example, although the tuple is itself immutable, it contains references to mutable values. So it appears as though the tuple changes, but the identity of the tuple remains constant and only the mutable parts are changing.
Whatever possible solution you come up with the second last line will always destroy it:
a = 3
This will assign a completely new content to the variable. Unless a stands for a property of an object or something (or a key in a list, as you did in your own example), you won't be able to have a relation between the first and last a.
If you just need the current values to be placed in a tuple on the fly you could use a lambda. You'll have to call c, not just return it or use it, but that may be acceptable in your situation. Something like this:
>>> a = 1
>>> b = 2
>>> c = lambda: (a, b)
>>> c()
(1, 2)
>>> a = 3
>>> c()
(3, 2)
There isn't a way in Python, not only because numbers are immutable, but also because you don't have pointers. Wrapping the value in a list simulates that you have pointers, so that's the best you can do.
class ByRefValue(object):
def __init__(self, value):
self.value = value
Pass it around wherever you like, remembering that you need to access the value member rather than the entire object.
Alternatively, globals().get('a', 0) will return the value of a if it is in the global namespace (or zero if it isn't).
Finally:
import threading
tls = threading.local()
tls.a = 1
If you import tls into every module where you need it, you will access the same value for a on each thread. Depending on how your program is set up, this may be acceptable, ideal or useless.
You can try creating your own pointer class and your own pointer storage object to emulate the system's internal stack.