There are some signs :-) that Python's object model is going to be revised even _before_ Python 3000. Is someone willing to join me fighting for class methods (I mean 'real' class-methods in the Smalltalk style here, _not_ static methods like in Java or C++). Thomas
"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> There are some signs :-) that Python's object model is going to TH> be revised even _before_ Python 3000. TH> Is someone willing to join me fighting for class methods (I mean TH> 'real' class-methods in the Smalltalk style here, _not_ static TH> methods like in Java or C++). The idea sounds good in the abstract. Class are objects and objects ought to have methods that implement their behavior. How does that very vague idea turn into something real? No clue. You start fighting and let's see where it goes :-). Jeremy
Jeremy Hylton wrote:
"TH" == Thomas Heller <thomas.heller@ion-tof.com> writes:
TH> There are some signs :-) that Python's object model is going to TH> be revised even _before_ Python 3000.
TH> Is someone willing to join me fighting for class methods (I mean TH> 'real' class-methods in the Smalltalk style here, _not_ static TH> methods like in Java or C++).
The idea sounds good in the abstract. Class are objects and objects ought to have methods that implement their behavior. How does that very vague idea turn into something real? No clue. You start fighting and let's see where it goes :-).
Here's something to start the fight ;-) ... 1) What would you do with class methods that you cannot do with e.g. globals and functions ? 2) How would you determine which methods are class-only methods and which are one usable by instances ? 3) If you don't like globals (see 1), wouldn't it be possible to store the state you want to manipulate using class methods in some other context object ? My impression is that class methods are not really needed and would only make optimizing Python harder... but that's maybe just me ;-) -- Marc-Andre Lemburg ______________________________________________________________________ Company & Consulting: http://www.egenix.com/ Python Pages: http://www.lemburg.com/python/
Here's something to start the fight ;-) ...
1) What would you do with class methods that you cannot do with e.g. globals and functions ?
I will write up a concrete example I have and post it later. Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book. This pattern is not needed if classes are 'first class' objects.
2) How would you determine which methods are class-only methods and which are one usable by instances ?
This is one of the issues which has to be resolved. I have no proposal at the moment. (Maybe function attributes can help here?)
3) If you don't like globals (see 1), wouldn't it be possible to store the state you want to manipulate using class methods in some other context object ?
I want the class methods (for example) to create and manipulate this 'context object'. This object, however, belongs into the class... What I want to avoid is class X(...): .... initialize(X)
My impression is that class methods are not really needed and would only make optimizing Python harder... but that's maybe just me ;-)
Unfortunately not, I fear. Thomas
Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book.
I imagine many of us (including yours truly :-) don't recall that in enough detail and/or don't have the book handy to look it up, so would you please do us a favor and explain this in a bit more detail?
This pattern is not needed if classes are 'first class' objects.
Depending on what you mean by the 'first class' phrase (which means something different to everyone), Python classes are already as first class as they get. E.g. they are tangible objects and you can pass them around and store them in variables.
What I want to avoid is
class X(...): .... initialize(X)
What would initialize(X) do that you can't write in the class body? --Guido van Rossum (home page: http://www.python.org/~guido/)
Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book.
I imagine many of us (including yours truly :-) don't recall that in enough detail and/or don't have the book handy to look it up, so would you please do us a favor and explain this in a bit more detail?
This is a valid request, but please wait for my larger example. I'm referring to this because I have not been good at explaining the things I want... All in all: I'm not really ready to start the fight _now_, I was just looking for some help... Thomas PS: I find it strange that everyone so far seems to be against it.
[Thomas Heller]
... PS: I find it strange that everyone so far seems to be against it.
I didn't get that sense yet. I did get the sense they're not actively *for* it yet, and the questions asked so far explain why: What does it buy us? What are the current alternatives? What are the costs (not least of all in terms of breaking existing code)? It's a bunch of tradeoffs, and it appears that few who aren't steeped in Smalltalk's view of the world understand what the practical *attraction* is. The same questions get asked even for wholly non-controversial changes, like, say, adding an optional ">> file" clause to "print" <wink>. by-default-it's-best-to-resist-everything-ly y'rs - tim
On Fri, 20 Apr 2001, Thomas Heller wrote:
Here's something to start the fight ;-) ...
1) What would you do with class methods that you cannot do with e.g. globals and functions ?
I will write up a concrete example I have and post it later.
There are a number of reasons why I'm all for Class attributes in general. For example, right now a class object cannot assert an interface. Sure, a class can say: class Foo: __implements__ = Bar # instances implement Bar but that is an assertion for the instances, not the *class itself*. Currently, you have to do the ugly hack: class Foo: __class_implements__ = FooFactory # the class implements # FooFactory. We've done things like the above in several places in our underground component elaboration. Not having class methods introduces many little wrinkles in the Python object model that have to be worked around. I can imagine, for example, wanting to define an __reduce__, or __init__ for a class object, which is not possible now.
Look into the motivation for the Prototype Pattern in the GOF book, or even better in the discussion of this pattern in the 'Design Pattern Smalltalk Companion' book.
This pattern is not needed if classes are 'first class' objects.
2) How would you determine which methods are class-only methods and which are one usable by instances ?
This is one of the issues which has to be resolved. I have no proposal at the moment. (Maybe function attributes can help here?)
I always thought along the lines of saying Class.instanceAttribute('foo') in the place of what is now said Class.foo. This would, of course, break code, but the warning and back to the future features mitigate most of that risk.
3) If you don't like globals (see 1), wouldn't it be possible to store the state you want to manipulate using class methods in some other context object ?
I want the class methods (for example) to create and manipulate this 'context object'. This object, however, belongs into the class...
What I want to avoid is
class X(...): .... initialize(X)
Yes! We use this monstrosity a lot in Zope. -Michel
On Fri, Apr 20, 2001 at 05:40:21PM +0200, Thomas Heller wrote: | I want the class methods (for example) to create and manipulate | this 'context object'. This object, however, belongs into the class... | | What I want to avoid is | | class X(...): | .... | initialize(X) Here is a different approach to consider : class X : def __class_init__( class_X ) : initialize( class_X ) The idea here is to provide a "magic" method in the class that the interpreter calls as soon as the class object exists. The first (only) argument is the class object, which can be named as desired (analogous to 'self'). The main problem here is clients aren't prevented from calling this method, and they really shouldn't. -D
There are some signs :-) that Python's object model is going to be revised even _before_ Python 3000.
Well, the official policy on this is now that Py3K is just a slogan, and that all the real work will be introduced gradually. :-)
Is someone willing to join me fighting for class methods (I mean 'real' class-methods in the Smalltalk style here, _not_ static methods like in Java or C++).
I will fight class methods to the death. :-) Seriously, I think you'll find an ally in Jim Fulton, who basically told me (since he's sort of my boss :-) to get on with this work. I think it can work as follows: Let x be an object, C its class, and M C's class. So, x.__class__ is C C.__class__ is M Then x's methods are described in C.__dict__, and C's methods are described in M.__dict__. The problem is that if you write C.spam, there could be two spams: one in C.__dict__, one in M.__dict__. Which one to use? How does Smalltalk resolve this? The problem is that for backwards compatibility, at lease, C.spam must be the unbound version of x.spam, because currently x.spam(...) can always also be written as C.spam(x, ...). For regular methods it may be possible to avoid this simply by choosing non-conflicting names, but I seem to recall that Jim wanted to use class methods with certain special names (like __init__ or __getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution? --Guido van Rossum (home page: http://www.python.org/~guido/)
Guido van Rossum writes:
__getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution?
Can that be dropped and still allow subclasses to extend a method offered by the base class? I think making the two different would break an enormous amount of code. -Fred -- Fred L. Drake, Jr. <fdrake at acm.org> PythonLabs at Digital Creations
Is someone willing to join me fighting for class methods (I mean 'real' class-methods in the Smalltalk style here, _not_ static methods like in Java or C++).
I will fight class methods to the death. :-) Ouch :-)
Seriously, I think you'll find an ally in Jim Fulton,
So there _is_ some hope.
who basically told me (since he's sort of my boss :-) to get on with this work.
This must be the reason that ExtensionClass provides them: You can implement them in C, and override them in python subclasses. Thomas
"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Let x be an object, C its class, and M C's class. So, | x.__class__ is C | C.__class__ is M GvR> Then x's methods are described in C.__dict__, and C's methods GvR> are described in M.__dict__. GvR> The problem is that if you write C.spam, there could be two GvR> spams: one in C.__dict__, one in M.__dict__. Which one to GvR> use? If you use naming to generally distinguish, and have a lookup chain that first found it in C.__dict__ and then looked in M.__dict__, you could control what happens when the name is in both dicts by using a more explicit lookup, e.g. C.__dict__['meth'] vs. C.__class__.__dict__['meth'] But maybe that's too ugly. GvR> How does Smalltalk resolve this? I don't remember, but I do remember that ObjC had the same concepts, and it used a distinguishing marker on the method definition to say whether the method was a class method (`+') or instance method (`-'), e.g. + void some_class_method ... - void an_instance_method Another question: presumably when I write class Foo: pass Foo is implicitly given the built-in metaclass M, but say I wanted to define a class Foo with a different metaclass, how would I spell this? I think at one point I suggested a semi-ugly syntactic hack, where `class' was actually a namespace and you could add new metaclasses to it. So you could write something like class.WeirdClass Foo: pass and now Foo's metaclass would be WeirdClass. waiting-for-the-bottom-turtle-to-burp-ly y'rs, -Barry
"GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Let x be an object, C its class, and M C's class. So,
| x.__class__ is C | C.__class__ is M
GvR> Then x's methods are described in C.__dict__, and C's methods GvR> are described in M.__dict__.
GvR> The problem is that if you write C.spam, there could be two GvR> spams: one in C.__dict__, one in M.__dict__. Which one to GvR> use?
[Barry wrote]
If you use naming to generally distinguish, and have a lookup chain that first found it in C.__dict__ and then looked in M.__dict__, you could control what happens when the name is in both dicts by using a more explicit lookup, e.g. C.__dict__['meth'] vs. C.__class__.__dict__['meth']
Couldn't be C.__class__.meth be used?
But maybe that's too ugly.
GvR> How does Smalltalk resolve this? I'm walking on thin ice here (maybe I should better try it out), but IIRC Smalltalk requires to explicit:
Another question: presumably when I write
class Foo: pass
Foo is implicitly given the built-in metaclass M, but say I wanted to define a class Foo with a different metaclass, how would I spell this? I think at one point I suggested a semi-ugly syntactic hack, where `class' was actually a namespace and you could add new metaclasses to it. So you could write something like
class.WeirdClass Foo: pass
and now Foo's metaclass would be WeirdClass. Thin ice again I'm on here (even more), but I have the impression
self class method; or self method; that creating a class Point in Smalltalk _automatically_ creates two classes: Point and PointClass. The latter is normally hidden (but contains the class methods of Point as instance methods). Thomas
"Thomas Heller" <thomas.heller@ion-tof.com> wrote,
> "GvR" == Guido van Rossum <guido@digicool.com> writes:
GvR> Let x be an object, C its class, and M C's class. So,
| x.__class__ is C | C.__class__ is M
GvR> Then x's methods are described in C.__dict__, and C's methods GvR> are described in M.__dict__.
GvR> The problem is that if you write C.spam, there could be two GvR> spams: one in C.__dict__, one in M.__dict__. Which one to GvR> use?
In my 'objectmodule' I adopted a concept which I refer to as the "unbound instance". That is, I invented an object which is used as a proxy for accessing instance attributes. It looks like an instance but only for the purposes of attribute access. Now, since this object will only return "unbound method objects" when accessing a method (as opposed to the "bound method object" you would get when accessing a method from a real instance) I thought the name was at least slightly appropriate. In short, each class defined by the objectmodule has a special attribute '_' which is the "unbound instance" for that class. This unbound instance is used to resolve the name ambiguity. Now, consider this: import object class foo(object.base): def frob(self): print "I've been frobbed", self class __class__: def frob(cl): print "No, I've been frobbed", cl >>> f = foo() >>> x = f.frob >>> # x is the instance frob method bound to f >>> y = foo.frob >>> # y is the class frob method bound to foo >>> z = foo._.frob >>> # z is the instance frob method but is not bound to any instance >>> huh = foo.__class__._.frob >>> # huh is the class frob method but is not bound to any class >>>
Thin ice again I'm on here (even more), but I have the impression that creating a class Point in Smalltalk _automatically_ creates two classes: Point and PointClass. The latter is normally hidden (but contains the class methods of Point as instance methods).
That's the way I remember it too. And, (if I recall correctly) in SmallTalk (unlike CLOS), you have no control over the meta-class. In the example above, like in SmallTalk, the name of foo.__class__ is determined automatically. In this case it is 'foo_class'. However, unlike SmallTalk, the above example could be extended to include a 'class __class__:' definition under the existing 'class __class__:'. The name generated by this construct would, of course, be 'foo_class_class'. Lather, Rinse, repeat... -- Donald Beaudry Ab Initio Software Corp. 201 Spring Street donb@init.com Lexington, MA 02421 ...Will hack for sushi...
On Fri, 20 Apr 2001, Guido van Rossum wrote:
Let x be an object, C its class, and M C's class. So,
x.__class__ is C C.__class__ is M
Then x's methods are described in C.__dict__, and C's methods are described in M.__dict__.
The problem is that if you write C.spam, there could be two spams: one in C.__dict__, one in M.__dict__. Which one to use?
I think, at the expense of breaking code, M.
How does Smalltalk resolve this? The problem is that for backwards compatibility, at lease, C.spam must be the unbound version of x.spam, because currently x.spam(...) can always also be written as C.spam(x, ...).
This is the part that choosing M would break. To get at C's shared instance attributes you could say something like C.instanceAttribute('spam')(x, ...). Yes, it's ugly. Perhaps someone can think of a more elegant spelling?
For regular methods it may be possible to avoid this simply by choosing non-conflicting names, but I seem to recall that Jim wanted to use class methods with certain special names (like __init__ or __getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution?
I'm not sure which idea you are talking about dropping, the first argument binding behavior, or the spelling of getting shared instance attributes from a class (C.spam). Just asking to make sure, cuz I don't think the first needs to change, just the spelling. BTW, you sent me some comments on the Components and Interfaces chapter of the Zope Developer's Guide where you noted that attributes of interface objects are not the attributes described by the interface and that this is "unfamiliar to the typical python programmer", ie: interface Hello: def hello(name): """ say hello to a name """ does not create a 'Hello.hello'. Instead, you need to say "Hello.getDescriptionFor('hello')". If we chose the more familiar 'Hello.hello' then the interface interface would be seriously limited, and any added functionality would need to be imported from an external module or be a builtin like isinstance(). Interfaces, like classes, wouldn't be able to have their own methods. -Michel
On Fri, 20 Apr 2001 11:26:01 -0500, Guido van Rossum <guido@digicool.com> wrote:
For regular methods it may be possible to avoid this simply by choosing non-conflicting names, but I seem to recall that Jim wanted to use class methods with certain special names (like __init__ or __getattr__?), and I have no idea how to do this without dropping the idea that x.spam(...) is C.spam(x, ...). So maybe that's the solution?
class A: def __init__(self): self.spam = 1 class B: def __init__(self): A.__init__(self) self.eggs = 2 -- "I'll be ex-DPL soon anyway so I'm |LUKE: Is Perl better than Python? looking for someplace else to grab power."|YODA: No...no... no. Quicker, -- Wichert Akkerman (on debian-private)| easier, more seductive. For public key, finger moshez@debian.org |http://www.{python,debian,gnu}.org
Guido:
The problem is that if you write C.spam, there could be two spams: one in C.__dict__, one in M.__dict__. Which one to use? How does Smalltalk resolve this?
The problem doesn't arise in Smalltalk, because method calls and instance variable accesses are completely different things and are handled by quite separate syntaxes and mechanisms. Python creates problems for itself here by confusing instance variables of the class with metadata about the instance's methods, and keeping them both in the same namespace. Thomas Heller <thomas.heller@ion-tof.com>:
I'm walking on thin ice here (maybe I should better try it out), but IIRC Smalltalk requires to explicit:
self class method; or self method;
No, to call a class method in Smalltalk, you just send a message to the class itself rather than an instance. There's no difference in the message sending syntax.
Thin ice again I'm on here (even more), but I have the impression that creating a class Point in Smalltalk _automatically_ creates two classes: Point and PointClass. The latter is normally hidden (but contains the class methods of Point as instance methods).
Yes. You don't normally get a choice about what the metaclass is, although no doubt you could reach under the covers and manually construct your own metaclass and instantiate it if you wanted. Greg Ewing, Computer Science Dept, +--------------------------------------+ University of Canterbury, | A citizen of NewZealandCorp, a | Christchurch, New Zealand | wholly-owned subsidiary of USA Inc. | greg@cosc.canterbury.ac.nz +--------------------------------------+
participants (12)
-
barry@digicool.com
-
D-Man
-
Donald Beaudry
-
Fred L. Drake, Jr.
-
Greg Ewing
-
Guido van Rossum
-
Jeremy Hylton
-
M.-A. Lemburg
-
Michel Pelletier
-
Moshe Zadka
-
Thomas Heller
-
Tim Peters