User
User

Reputation: 14873

Replace object with another in the entire process / become in Python

Context: I want to replace an object with another:

x = []
r = [2]
replace(x, r)
assert x == [2]
assert x is r

In Smalltalk this would be called become .

Question: How would I do that? Would I need to create a C-extension or is there already something like this?

I tried: This But I need to handle so many cases. Just changing the object behind the pointer would be enough for me.

Reason: I want to implement extensions like features, refinements and subjects. Sometimes I can not change the class of an builtin object os.__class__ = X to enable more flexibility. Since I can not do that, I though about replacing.

Concrete Example of Usage:

A subjective view:

import pylung
pylung.deutsch()

import os # I want to preserve object identity with the original os

os.ERREICHE_SETZEN
os.durchlaufe(...)

A translation:

import os
import pylung

os = pylung.translate(os, 'deutsch') # German

@os.walk
def durchlaufe(ordner, oben_nach_unten, folge_links):
    """Ordner baum erzeuger
"""

Upvotes: 2

Views: 1785

Answers (4)

kindall
kindall

Reputation: 184280

In Python, the only way to do this natively is through assignment:

x = []
r = [2]
x = r
assert x == [2]
assert x is r

However, this is so trivial I doubt it is what you're looking for. More likely you want all references to r to be updated. This isn't possible with Python. You can do it, after a fashion, with slice assignment, but this won't actually change the object identity, so your last assert will fail, and also this only works with certain types such as lists (though some other container types have similar capabilities; for example with a dict you could .clear() then .update()).

x = []
r = [2]
x[:] = r
assert x == [2]
assert x is r     # fails

The closest you can come, probably, is with a wrapper object that holds the list as an attribute. If the wrapper is always passed around, never the list, and the list is always accessed through the wrapper, then you can simply update the attribute and every other reference will see it.

Edit: Looking at your specific use case, which you added after I wrote the above, it doesn't actually require replacing anything. You can just set the translated function/class names onto the existing module object (removing the existing ones, if that's necessary). An easier way would probably to make an entirely new module and stick it into sys.modules[modulename]. As long as you do this before any other modules import it, they will never see the untranslated module.

Of course, this is a silly thing to do; there is no good way to machine-translate Python code into another human language. Translate it by hand and provide it to interested parties as an importable module of its own.

Upvotes: 2

Aya
Aya

Reputation: 42000

If you want to be able to do this...

import pylung
pylung.deutsch()

import os # I want to preserve object identity with the original os

os.ERREICHE_SETZEN
os.durchlaufe(...)

...and retain compatibility with existing libraries (which will use the English names), it's probably easiest to add additional attributes to the os module, rather than replacing them. For example...

# pylung.py
def deutsch():
    import os
    os.durchlaufe = os.walk
    # etc...

...if you also want to translate module names, say collections to kollektionen, you can do something like this...

# pylung.py
import sys

def deutsch():
    import os
    os.durchlaufe = os.walk
    # etc...
    import collections
    sys.modules['kollektionen'] = sys.modules['collections']

...again, ensuring you keep the original module name in place for compatibility.

You could also look at using a custom import hook to do the module translations on-demand, so you need only replace the symbols that are actually used in the script.

Upvotes: 3

kirelagin
kirelagin

Reputation: 13616

You should realise that a variable is actually nothing more than a name that is being searched in dictionaries representing scopes.

Scopes (dictionaries) actually contain references (think, pointers). You can replace a pointer, but in Python there is no way to change an object in-place. That's what you can do with references in C (which give you access to the underlying memory cell), but there is a limitation that objects sizes must match. So, no, you can't.

Upvotes: 1

user1907906
user1907906

Reputation:

A simple = does what you want:

x = []
r = [2]
x = r
assert x == [2]
assert x == r
assert x is r

Upvotes: 4

Related Questions