Bengt Richter wrote: > If we had a way to effect an override of a specific instance's attribute > accesses > to make certain attribute names act as if they were defined in > type(instance), and > if we could do this with function instances, and if function local accesses > would > check if names were one of the ones specified for the function instance being > called, > then we could define locally named constants etc like properties. > > The general mechanism would be that instance.__classvars__ if present would > make
Nah... you're not nearly going far enough with this. I'd suggest a full unification of "names" and "attributes." This would also enhance lexical scoping and allow an "outer" keyword to set values in an outer namespace without doing royally weird stuff. In general, all lexical blocks which currently have a local namespace (right now, modules and functions) would have a __namespace__ variable, containing the current namespace object. Operations to get/set/delete names would be exactly translated to getattr/setattr/delattrs. Getattrs on a namespace that does not contain the relevant name recurse up the chain of nested namespaces, to the global (module) namespace, which will raise an AttributeError if not found. This allows exact replication of current behaviour, with a couple interesting twists: 1) i = i+1 with "i" in only an outer scope acutally works now; it uses the outer scope "i" and creates a local "i" binding. 2) global variables are easily defined by a descriptor: def global_var(name): return property( lambda self: getattr(self.global,name), lambda (self, v): setattr(self.global,name,v), lambda self: delattr(self.global,name), "Global variable %s" % name) 3) "outer variables" under write access (outer x, x = 1) are also well-defined by descriptor (exercise left for reader). No more weird machinations involving a list in order to build an accumulator function, for example. Indeed, this is probably the primary benefit. 4) Generally, descriptor-based names become possible, allowing some rather interesting features[*]: i) "True" constants, which cannot be rebound (mutable objects aside) ii) Aliases, such that 'a' and 'b' actually reference the same bit, so a = 1 -> b == 1 iii) "Deep references", such that 'a' could be a reference to my_list[4]. iv) Dynamic variables, such as a "now_time" that implicitly expands to some function. 5) With redefinition of the __namespace__ object, interesting run-time manipulations become possible, such as redefining a variable used by a function to be local/global/outer. Very dangerous, of course, but potentially very flexible. One case that comes to mind is a "profiling" namespace, which tracks how often variables are accessed -- over-frequented variables might lead to better-optimized code, and unaccessed variables might indicate dead code. [*] -- I'm not saying that any of these examples are particularly good ideas; indeed, abuse of them would be incredibly ugly. It's just that these are the first things that come to mind, because they're also so related to the obvious use-cases of properties. The first reaction to this is going to be a definite "ewwwww," and I'd agree; this would make Python names be non-absolute [then again, the __classvars__ suggestion goes nearly as far anyway]. But this unification does bring all the power of "instance.attribute" down to the level of "local_name". The single biggest practical benefit is an easy definiton of an "outer" keyword: lexical closures in Python would then become truly on-par with use of global variables. The accumulator example would become: def make_accum(init): i = init def adder(j): outer i #[1] i += j return i return adder [1] -- note, this 'outer' check will have to require that 'i' be defined in an outer namespace -at the time the definition is compiled-. Otherwise, the variable might have to be created at runtime (as can be done now with 'global'), but there's no obvious choice on which namespace to create it in: global, or the immediately-outer one? This implies the following peculiar behaviour (but I think it's for the best): >>> # no i exists >>> def f(): # will error on definition outer i print i >>> def g(): # won't error print i >>> i = 1 >>> f() >>> g() Definitely a Py3K proposal, though. -- http://mail.python.org/mailman/listinfo/python-list