Re: 2.2a1: classmethod() and class attributes
Aahz:
It's not particularly convenient for me to try out 2.2a1, so I'm just going by what's written. One little hole that I don't see an answer to is what happens when you do this:
class C(object): x = 0 def foo(cls): cls.x += 1 foo = classmethod(foo)
C.foo()
Okay, after thinking about this a bit, I think that if the above code requires __dynamic__=1 to work, then the default for __dynamic__ should be changed. I don't find the arguments about changing __class__ to be particularly persuasive, but I think the above code *is* closely related to standard Python idioms that should work by default. +1 on changing __dynamic__ or at least enabling some kind of class variable mutability by default. -- --- Aahz (@pobox.com) Hugs and backrubs -- I break Rule 6 <*> http://www.rahul.net/aahz/ Androgynous poly kinky vanilla queer het Pythonista I don't really mind a person having the last whine, but I do mind someone else having the last self-righteous whine.
+1 on changing __dynamic__ or at least enabling some kind of class variable mutability by default.
After converting the Tools/compiler package to the new class system, I tend to agree (I already said so on c.l.py in my last post there). Here's a problem, related to performance. The dispatch for special operations (like __iter__) from C uses a C function stored in a corresponding slot (e.g. tp_iter) in the type object. So when class X has an __iter__ method, there needs to be a slot wrapper (a C function that calls the __iter__ object) in the in the tp_iter slot in the type object representing X. For dynamic classes, I must assume that at any time someone can add a special method (like __iter__) to a class. It's hard to set up things so that the dispatch function is set in the type object at the moment C.__iter__ is assigned: it would require a class to keep track of all its subclasses, without keeping those subclasses alive. While I know I can do that using weak references, I don't like having to maintain all that administration. So at the moment, when a class is dynamic, I just stick all dispatch functions in the type object -- the dispatch functions will raise AttributeError when their corresponding method is not found. (This is the same approach used for classic classes, BTW.) This is slower than it should be -- the fully dynamic Tools/compiler package compiles itself about 25% slower this way. If I tweak it to use all static classes (not very hard), it runs at about the same speed as it does with classic classes. I imagine I could make it faster by using __slots__, but I don't know enough about the internals yet to be able to do that. My goal (before I'm happy with making __dynamic__=1 the default) is that dynamic classes should be at least as fast as classic classes. I haven't profiled it yet -- it's possible that there's a cheap hack possible by making more conservative assumptions about __getattr__ alone -- classic classes special-case __getattr__ too.) --Guido van Rossum (home page: http://www.python.org/~guido/)
[okay, so I'm following up on old stuff -- sue me] [there's also excessive quoting to maintain context] Guido van Rossum wrote:
Aahz:
+1 on changing __dynamic__ or at least enabling some kind of class variable mutability by default.
After converting the Tools/compiler package to the new class system, I tend to agree (I already said so on c.l.py in my last post there).
Yeah, you did, but I didn't see you directly address my point about the necessary mutability of class variables.
For dynamic classes, I must assume that at any time someone can add a special method (like __iter__) to a class. It's hard to set up things so that the dispatch function is set in the type object at the moment C.__iter__ is assigned: it would require a class to keep track of all its subclasses, without keeping those subclasses alive. While I know I can do that using weak references, I don't like having to maintain all that administration. So at the moment, when a class is dynamic, I just stick all dispatch functions in the type object -- the dispatch functions will raise AttributeError when their corresponding method is not found. (This is the same approach used for classic classes, BTW.)
This is slower than it should be -- the fully dynamic Tools/compiler package compiles itself about 25% slower this way. If I tweak it to use all static classes (not very hard), it runs at about the same speed as it does with classic classes. I imagine I could make it faster by using __slots__, but I don't know enough about the internals yet to be able to do that.
My goal (before I'm happy with making __dynamic__=1 the default) is that dynamic classes should be at least as fast as classic classes. I haven't profiled it yet -- it's possible that there's a cheap hack possible by making more conservative assumptions about __getattr__ alone -- classic classes special-case __getattr__ too.)
Okay, keeping in mind that I don't actually understand what I'm talking about, what is the problem involved in permitting existing attributes to be mutable? That is, as I think James Althoff has pointed out, there are at least two levels of mutability, one of which is the ability to mutate existing attributes, and another of which is the ability to add attributes. Would making this all finer-grained help? Do we actually need to control whether existing attributes are mutable? -- --- Aahz (@pobox.com) Hugs and backrubs -- I break Rule 6 <*> http://www.rahul.net/aahz/ Androgynous poly kinky vanilla queer het Pythonista We must not let the evil of a few trample the freedoms of the many.
Aahz:
+1 on changing __dynamic__ or at least enabling some kind of class variable mutability by default.
Guido van Rossum wrote:
After converting the Tools/compiler package to the new class system, I tend to agree (I already said so on c.l.py in my last post there).
[Aahz]
Yeah, you did, but I didn't see you directly address my point about the necessary mutability of class variables.
I agree that they are necessary. What else do you want me to say?
For dynamic classes, I must assume that at any time someone can add a special method (like __iter__) to a class. It's hard to set up things so that the dispatch function is set in the type object at the moment C.__iter__ is assigned: it would require a class to keep track of all its subclasses, without keeping those subclasses alive. While I know I can do that using weak references, I don't like having to maintain all that administration. So at the moment, when a class is dynamic, I just stick all dispatch functions in the type object -- the dispatch functions will raise AttributeError when their corresponding method is not found. (This is the same approach used for classic classes, BTW.)
This is slower than it should be -- the fully dynamic Tools/compiler package compiles itself about 25% slower this way. If I tweak it to use all static classes (not very hard), it runs at about the same speed as it does with classic classes. I imagine I could make it faster by using __slots__, but I don't know enough about the internals yet to be able to do that.
My goal (before I'm happy with making __dynamic__=1 the default) is that dynamic classes should be at least as fast as classic classes. I haven't profiled it yet -- it's possible that there's a cheap hack possible by making more conservative assumptions about __getattr__ alone -- classic classes special-case __getattr__ too.)
Okay, keeping in mind that I don't actually understand what I'm talking about, what is the problem involved in permitting existing attributes to be mutable?
That is, as I think James Althoff has pointed out, there are at least two levels of mutability, one of which is the ability to mutate existing attributes, and another of which is the ability to add attributes. Would making this all finer-grained help? Do we actually need to control whether existing attributes are mutable?
The problem is that the only kind of control that is easy to implement is to make *everything* immutable. Given that I strive for __dynamic__=1 as the default, I don't want to add more code that's only temporary. Maybe I'll just make __dynamic__=1 the default in 2.2a4, and work on the performance issues later. (But there are subtle semantics differences as well that make life more complicated than it should be with __dynamic__=1.) --Guido van Rossum (home page: http://www.python.org/~guido/)
participants (2)
-
aahz@rahul.net
-
Guido van Rossum