mk a écrit : > Stephen Hansen wrote: > >> You don't have to (and can't) refer to the class within the body. >> Class statements are sort of... odd. They are code which is directly >> executed, and the results are then passed into a >> metaclass/type/whatever and a class object is created. While within >> the class body, the class doesn't exist yet. >> >> But you don't need it to. >> >> Just do: >> >> 'internal_date': print_internal_date >> >> The 'def' is in the same local scope as 'tagdata' is. > > Thanks, that worked. But in order to make it work I had to get rid of > 'self' in print_internal_date signature
Indeed. Using it that way, the print_internal_date will not be wrapped in a method object. > bc all other functions in > tagdata have only a single argument: > > class PYFileInfo(FileInfo): > 'python file properties' > > def print_internal_date(filename): > ... > > tagdata = {'compiled_fname': lambda x: x + 'c', > 'size': os.path.getsize, > 'internal_date': print_internal_date > } > > That looks weird: a method with no 'self'. It's not a method. > Hmm that is probably > seriously wrong. > > This obviously means no other method can call it like > self.print_internal_date(), because self would get passed as first > argument, yes? Unless you make it a staticmethod. > I checked that print_internal_date can be called on an instance, so the > same method s/method/function/ > can be seen as: > > - class method -- when used in local scope definition like tagdata, or > - instance method -- when called from an instance or from self? Mmmm... Let's try to explain the whole damn thing. It's really (and IMHO beautifully) simple once you get it, but I agree it's a bit peculiar when compared to most mainstream OO languages. The first thing is that the def statement *always* yield a function object. Always. If you don't believe it, try the following snippet: class Foo(object): def bar(self): return "baaz" print Foo.__dict__.keys() print type(Foo.__dict__['bar']) So, why is it that type(Foo.bar) != type(Foo.__dict__['bar']) ? The answer is : attribute lookup rules and the descriptor protocol. To make a long story short, the descriptor protocol specify that, when, during an attribute lookup, a name resolves to a class attribute AND this attribute has a __get__ method, then this __get__ method is called (with either the instance or None and the class itself as arguments) and whatever it returns becomes the result of the attribute lookup. This mechanism is what provides support for computed attributes. Now the trick is that the function type do implement the descriptor protocol. So when a function is an attribute of a class object and you try to access it as an attribute of either the class itself or an instance of the class, it's __get__ method is called with the instance (or None) and the class. Having access to itself (of course), the instance (if there's one) and the class, it's easy for it to wrap all this into a method object. Which is itself a callable object, that when called mostly inject the instance as first object in the argument's list and returns the result of calling the wrapped function object. A (naive) implementation of the whole thing might look like this: class method(object): def __init__(self, func, instance, cls): self.im_func = func self.im_self = instance self.im_class = cls def __call__(self, *args, **kw): # XXX : all sanity checks removed for readability if self.im_self: args = (self.im_func,) + args return self.im_func(*args, **kw) class function(object): # ... def __get__(self, instance, cls): return method(self, instance, cls) So, what makes a function a "method" is not being defined in a class statement's body (well, not directly at least), it's that it is an attribute of the class. FWIW, the following code is perfectly legal: class Foo(object): pass def func(obj): print "obj is %s " % obj Foo.method = func f = Foo() f.method() Foo.method(f) func(f) > I wonder if I'm not trying to make Python things it shouldn't be doing, > but it's the problem at hand that is leading me into this conundrum: all > other functions for tagdata use single arguments. I should probably code > around that anyway.. Well, the simple solution is to just leave print_internal_date as a plain function instead of insisting on making it a method. Python is 100% OO in that everything is an object, but it's not a "pure" OO language, ie it doesn't require everything to happen in a method. So if all you need is a function, by all mean just use a function !-) Now if you really need print_internal_date to be exposed as a method of PYFileInfo - like, you need polymorphic dispatch - then make it a staticmethod. My 2 cents... -- http://mail.python.org/mailman/listinfo/python-list