Reputation: 3633
With Python 2.7x I'm attempting to create a Map object which can reference itself with a 'This' or 'self'. In Javascript this would be roughly,
myObj = function(){
obj = {};
this = obj;
obj = { 'a':'b', 'b':this.a };
return obj;
}()
But in Python you can't do multi-line lambda expressions. Scoping also doesn't behaviour the same as I expect. I can create a function on a separate line then call it, but this seems to lack pizzaz (especially since it isn't limited to being called only once). Is there an effective way to do this in Python?
EDIT: Some people have been asking OH MY GOD WHY???? Well first of all, as an exercise. Second, you are failing to understand what I'm trying to do - I'm attempting to emulate a CLASS with a MAP. In a class in python you would say, var otherfunc = self.predefinedFunction I want to be able to use self (this in some other languages), to reference the object. So in python I want to turn this:
my_obj = { 'sqr':lambda x: x*x, 'quad': my_obj['sqr']}
into this:
my_obj = { 'sqr':lambda x: x*x, 'quad': this['sqr']}
Upvotes: 0
Views: 112
Reputation: 5844
With the following boilerplate code:
class StoringOperations:
for specfunc in ["getattr", "getitem", "call", "len"]: # Extend as needed
name = "__" + specfunc + "__"
f = lambda self, *args, __name=name, **kwargs: StoredOperation(self, __name, args, kwargs)
f.__name__ = name
locals()[name] = f
class StoredOperation(StoringOperations):
def __init__(self, s, methname, args, kwargs):
self.__args = args
self.__kwargs = kwargs
self.__methname = methname
self.__s = s
super().__init__()
def gethiddenname(thing, name):
return getattr(thing, "_StoredOperation" + name)
def consolidate(thing, this):
if isinstance(thing, StoredOperation):
s = consolidate(gethiddenname(thing, "__s"), this)
methname = gethiddenname(thing, "__methname")
try:
meth = getattr(s, methname)
except AttributeError:
if methname == "__getattr__":
meth = lambda *args, **kwargs: getattr(s, *args, **kwargs)
else:
raise
return meth(*gethiddenname(thing, "__args"), **gethiddenname(thing, "__kwargs"))
elif isinstance(thing, StoringOperations):
return this
else:
return thing
class SelfConsciousMap(dict):
def __init__(self, **kwargs):
super().__init__()
self.kwargs = kwargs
for key in kwargs:
self.consolidation(key)
def consolidation(self, key):
self[key] = consolidate(self.kwargs[key], self)
def __getitem__(self, key):
if key in self.kwargs and key not in self:
self.consolidation(key)
return super().__getitem__(key)
this = StoringOperations()
You can do this:
d = SelfConsciousMap(a=[1,2,3], b=this["a"], c=this["b"].copy(), d=this["a"].__len__())
print(d)
And you will get:
{'a': [1, 2, 3], 'c': [1, 2, 3], 'b': [1, 2, 3], 'd': 3}
Might not be useful in real code, but it shows that with enough classes, anything is possible...
Upvotes: 0
Reputation: 40703
Given your example in your answer here, why don't you just write a class? The following is functionally equivalent to your code example.
class myobj(object):
def __init__(self):
self.count = 0
@staticmethod
def addOne(n):
return n + 1
def addOneTimesTwo(self, n):
return self.addOne(n) * 2
def __getitem__(self, attrname):
"Allows attributes to accessed as if they were key/value pairs in a map."
return getattr(self, attrname)
myObj = myobj()
assert myObj["addOneTimesTwo"](1) == 4
If you really have your heart set on trying to emulate prototyping then you could try the following. It won't work with inheritance though. You'll need to add a few more bits and pieces to make that work.
class Prototype(object):
def __init__(self, **attrs):
self.__dict__.update(attrs)
def myobj():
count = 0
def addOne(n):
return n + 1
def addOneTimesTwo(n):
"""This is like a 'bound' method. The self in this context will refer to the same
Prototype even if this function is transferred to a different Prototype."""
return self.addOne(n) * 2
self = Prototype(**locals())
return self
myObj = myobj()
assert myObj.addOneTimesTwo(1) == 4
Upvotes: 1
Reputation: 13289
If you're trying to implement a closure with a map, this would work fine
mymap = {a:1,b:"foo"} # all of your previously initialized and constant data
mymap["self"] = mymap
Then you can call
mymap["self"]["b"]
Here's how you can write code using this
mymap["func"] = lambda x: return x*mymap["self"]["x"]
This is admitted ugly, but you can't you have no way to refer to the map as anything but a global variable within a lambda expression. In particular, there's no good way to self reference. A better approach is to use an object, not a map.
Upvotes: 2