Warren Stringer wrote: > Josiah Carlson wrote: >> >>> foo = type(foo)(foo.func_code, d, foo.func_name, foo.func_defaults, >> foo.func_closure) > > Wow! I've never seen that, before. Is there documentation for `type(n)(...)` > somewhere? I did find a very useful "Decorator for Binding Constants, by > Raymond Hettinger", that uses this technique.
type(obj) gets you the type of the object. To discover what it takes to construct a function object, I just used... >>> help(type(foo)) Help on class function in module __builtin__: class function(object) | function(code, globals[, name[, argdefs[, closure]]]) | | Create a function object from a code object and a dictionary. | The optional name string overrides the name from the code object. | The optional argdefs tuple specifies the default argument values. | The optional closure tuple supplies the bindings for free variables. ... > The calls are made from embedded classes that are constructed on the fly: > > class a(object): ... > class b(object): ... > class c(object): ... > > for `a.b[c]=1`, a.__getattr__('b') is called but 'c' need to be resolved as > an object before a.b.__getitem__(c) is called. Could a.b.__init__ set > globals so that 'c' gets resolved? Is this global namespace the same as the > `globals()` namespace? I don't believe there is any confusion as to *why* you are getting the error. It seems plain to everyone involved. You are getting the error because c is not defined in the namespace in which you are executing 'a.b[c] = 1'. Unless you modify the namespace in which it is running... >>> class a(object): ... class b(object): ... class c(object): ... pass ... >>> def merged_namespace(*ns): ... try: ... __builtins__ ... namespaces = ns + (globals(),__builtins__.__dict__) ... except NameError: ... namespaces = ns + (globals(),__builtin__) ... ns = {} ... for i in reversed(namespaces): ... ns.update(i) ... return ns ... >>> class m_level_namespace(dict): ... def __init__(self, *ns): ... try: ... __builtins__ ... self.namespaces = ns + (globals(),__builtins__.__dict__) ... except NameError: ... self.namespaces = ns + (globals(),__builtin__) ... def __getitem__(self, key): ... for i in self.namespaces: ... print "..." ... if key in i: ... return i[key] ... raise NameError("Name %r not found"%(key,)) ... def __setitem__(self, key, value): ... self.ns[0][key] = value ... def __delitem__(self, key): ... del self.ns[0][key] ... >>> def foo(): ... print type(globals()) ... a.b[c] = 1 ... >>> ns = m_level_namespace(a.b.__dict__) >>> >>> foo1 = type(foo)(foo.func_code, ns, foo.func_name, foo.func_defaults, foo.func_closure) >>> >>> foo1() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in foo NameError: global name 'type' is not defined >>> >>> ns = merged_namespace(a.b.__dict__) >>> >>> foo2 = type(foo)(foo.func_code, ns, foo.func_name, foo.func_defaults, foo.func_closure) >>> >>> foo2() <type 'dict'> Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in foo TypeError: 'type' object does not support item assignment >>> Due to the vagaries of Python's lookup mechanism, the m_level_namespace class doesn't work as a method of trying to build a name resolution order. However, if you are OK with the limitations of needing to merge namespaces, then the merged_namespace function should work for you (it doesn't pick up changed globals, builtins, your class contents, etc.) With all of that said, you still shouldn't be trying to do a.b[c] . You should instead be doing a.b[a.b.c] . Is it cumbersome? Yes. but it's the only mechanism that really makes sense (hacking namespaces is a great way of breaking your application in new and unexpected ways). - Josiah -- http://mail.python.org/mailman/listinfo/python-list