immutable classes [was: pre-PEP: Default Argument Expressions]
I have added python-ideas to the Cc list, and suggest removing python-3000 from additional replies. BJörn Lindqvist gave an example explaining why he might want to re-evaluate mutable default arguments. It still looks like like buggy code, but it isn't the error I was expecting -- and I think it comes from the difficulty of declaring something immutable. On 2/15/07, BJörn Lindqvist <bjourne@gmail.com> wrote:
On 2/15/07, Jim Jewett <jimjjewett@gmail.com> wrote:
Then are there *any* good use cases for [non-persistent mutable defaults]
(1) Not really (treated as) mutable. ==> Doesn't care
>>> def f(extra_settings={}) ...
usually doesn't modify or even store extra_settings; ...
That is dangerous code. Sooner or later someone will modify the extra_settings dict.
How? >>> f.func_defaults[0]['key']=value may be misguided, but it probably isn't an accident. BJörn's example does store the mutable directly, but it makes a bit more sense because it looks like a complex object rather than just a mapping.
class Vector: def __init__(self, x, y, z): self.x = x self.y = y self.z = z
class Ray: def __init__(self, direction, origin = Vector(0, 0, 0)): self.direction = direction self.origin = origin
ray1 = Ray(Vector(0, 0, -1)) ray2 = Ray(Vector(0, 0, 1)) ray3 = Ray(Vector(-1, 0, 0), Vector(2, 3, 4))
The above code looks quite nice, but is wrong.
Why is vector mutable? Is the real problem that it is too hard to declare objects or attributes immutable? My solution is below, but I'll grant that it isn't as straightforward as I would have liked. Is this something that could be solved with a recipe, or a factory to make immutable classes?
class Vector3D(tuple): ... def __new__(self, x, y, z): ... return super(Vector3D, self).__new__(self, (x, y, z)) ... x=property(lambda self: self[0]) ... y=property(lambda self: self[1]) ... z=property(lambda self: self[2])
-jJ
"Jim Jewett" <jimjjewett@gmail.com> wrote:
class Vector3D(tuple): ... def __new__(self, x, y, z): ... return super(Vector3D, self).__new__(self, (x, y, z)) ... x=property(lambda self: self[0]) ... y=property(lambda self: self[1]) ... z=property(lambda self: self[2])
That looks very much like Raymond Hettinger's named tuple recipe, recently offered in python-dev: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/500261 - Josiah
Well, except that Raymond's is indeed better -- so consider this a request for inclusion in 2.6 On 2/17/07, Josiah Carlson <jcarlson@uci.edu> wrote:
"Jim Jewett" <jimjjewett@gmail.com> wrote:
class Vector3D(tuple): ... def __new__(self, x, y, z): ... return super(Vector3D, self).__new__(self, (x, y, z)) ... x=property(lambda self: self[0]) ... y=property(lambda self: self[1]) ... z=property(lambda self: self[2])
That looks very much like Raymond Hettinger's named tuple recipe, recently offered in python-dev:
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/500261
-jJ
On the 'using old semantics when you really want to' part, that's very well possible with a decorator under the proposed semantics: def caching(**cachevars): def inner(func): def wrapper(**argdict): for var in cachevars: if not var in argdict: argdict[var] = cachevars[var] return func(**argdict) return wrapper return inner @caching(cache={}) def foo(in, cache): result = bar(in) cache[in] = result return result This implementation of caching doesn't handle positional args, but it can be made to. One such decorator would still be a net win of several hundred lines of code in the standard lib. Of course, IMHO, the real fix to this is to 1) have default expressions be evaluated at calltime, and 2) have _all_ lexical variables be bound at definition time and 3) make them immutable. Then something like lst = [] for i in range(10): lst.append(lambda i: i*i) would work. That would be a real win for functional programming. (good thing) Unfortunately Guido's decided not to support (1), and (2) has been proposed some time ago and didn't make it. In both cases because it would be to big a departure from how Python currently works. (3) is quite impossible in a language like python. <mode=dreaming> I just hope if python were designed today it would have done these. </mode> - Jan
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote: [snip]
lst = [] for i in range(10): lst.append(lambda i: i*i)
You must mean something like... lambda j: i*j
<mode=dreaming> I just hope if python were designed today it would have done these. </mode>
Probably not. Value binding breaks closures. - Josiah
On Tue, 20 Feb 2007 00:17:53 +0100, Josiah Carlson <jcarlson@uci.edu> wrote:
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote: [snip]
lst = [] for i in range(10): lst.append(lambda i: i*i)
You must mean something like... lambda j: i*j
yes. my mistake.
<mode=dreaming> I just hope if python were designed today it would have done these. </mode>
Probably not. Value binding breaks closures.
That depends on how you exactly define closures. The basics of having an inner function with free variables and initializing those free variables to the values they have in the parent scope still works.
- Josiah
On Tue, 20 Feb 2007 14:28:23 +0100, Nick Coghlan <ncoghlan@gmail.com> wrote:
Jan Kanis wrote: <mode=dreaming> I just hope if
python were designed today it would have done these. </mode>
If Python had done these, it wouldn't be Python ;)
True. Let's make the better-than-python language. (aiming high) ;)
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote:
On Tue, 20 Feb 2007 00:17:53 +0100, Josiah Carlson <jcarlson@uci.edu> wrote:
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote:
<mode=dreaming> I just hope if python were designed today it would have done these. </mode>
Probably not. Value binding breaks closures.
That depends on how you exactly define closures. The basics of having an inner function with free variables and initializing those free variables to the values they have in the parent scope still works.
It would break closures as defined for Python version 1.? to Python 2.5, Python 3.x, and beyond. Changing the semantics of Python closures is not the right thing to do, whether in 2.6, 3.x or otherwise. - Josiah
On Sun, 25 Feb 2007 23:45:08 +0100, Josiah Carlson <jcarlson@uci.edu> wrote:
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote:
On Tue, 20 Feb 2007 00:17:53 +0100, Josiah Carlson <jcarlson@uci.edu> wrote:
"Jan Kanis" <jan.kanis@phil.uu.nl> wrote:
<mode=dreaming> I just hope if python were designed today it would have done these. </mode>
Probably not. Value binding breaks closures.
That depends on how you exactly define closures. The basics of having an inner function with free variables and initializing those free variables to the values they have in the parent scope still works.
It would break closures as defined for Python version 1.? to Python 2.5, Python 3.x, and beyond.
Changing the semantics of Python closures is not the right thing to do, whether in 2.6, 3.x or otherwise.
Yup. That's why I used '<mode=dreaming>' and talked about if python were designed today, i.e. it didn't exist yet. Of course, that's not actually the case so it's a purely theoretical point.
Jan Kanis wrote: <mode=dreaming> I just hope if
python were designed today it would have done these. </mode>
If Python had done these, it wouldn't be Python ;) There are many, many programming language design decisions which have good arguments on each side (and some which seem obviously correct may involve hidden costs which aren't appreciated until after it is too late to change them). That's one of the major reasons why there are so many different programming languages out there. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia --------------------------------------------------------------- http://www.boredomandlaziness.org
participants (4)
-
Jan Kanis
-
Jim Jewett
-
Josiah Carlson
-
Nick Coghlan