Devin Jeanpierre wrote: > On Mon, Feb 2, 2015 at 6:07 AM, Steven D'Aprano > <steve+comp.lang.pyt...@pearwood.info> wrote: >> Run this code: >> >> # === cut === >> >> class K(object): >> def f(self): pass >> >> def f(self): pass >> >> instance = K() >> things = [instance.f, f.__get__(instance, K)] >> from random import shuffle >> shuffle(things) >> print(things) >> >> # === cut === >> >> >> You allege that one of these things is a method, and the other is not. I >> challenge you to find any behavioural or functional difference between >> the two. (Object IDs don't count.) >> >> If you can find any meaningful difference between the two, I will accept >> that methods have to be created as functions inside a class body. > > In this particular case, there is none. What if the body of the > "method" was super().f() ?
What of it? The zero-argument form of super() is a compiler hack documented as only working inside classes. Most methods don't even use super *at all*, let alone the Python3-only zero argument form. Surely you cannot be serious that the defining characteristic of what is or is not a method is whether or not an explicit hack works? But you know, I can duplicate the compiler hack and still use the zero-argument form of super in a method defined on the outside of the class. py> class A(object): ... pass ... py> def magic(): # Don't do this at home! ... __class__ = A ... def f(self): ... __class__ ... return super() # Magic zero-argument form. ... return f ... py> A.f = magic() py> a = A() py> a.f() <super: <class 'A'>, <A object>> So to answer your question: What if the body of the "method" was super().f() ? It would still work correctly. Because Python is just that awesome. > Some methods can be defined outside of the body and still work exactly > the same, but others won't. "Some methods can be defined outside of the body". AT LONG LAST THE LIGHT DAWNS! THE PENNY DROPS! If some methods can be defined outside of the body of a class, then being defined inside the body of a class does not define a method. You say "some methods", but the reality is that *all methods* can do so. Even if they use super. Even if they use the zero-argument form of super (although that one is rather inconvenient). The class statement is syntactic sugar for calling type(name, bases, ns): class A(bases): x = 100 f = lambda self: self.x + 1 is equivalent to: A = type("A", bases, {'x': 100, 'f': lambda self: self.x + 1}) *ANY* class you create with the class statement can be created (less conveniently) with type (or the appropriate metaclass). Obviously the class statement form is convenient because it allows you to define the items of the namespace in place, which you can't always do using type itself. With type, you may have to prepare the items first, insert them into a dict, and pass it as the namespace argument. It also offers convenient syntax for changing the metaclass. Most importantly, it is simply more readable and nicer to be able to define the methods indented inside the class statement. This is the natural way to define classes, and given that the glossary need not be 100% complete and definitive, "function defined inside a class body" is close enough to the truth. But it is not *the whole truth*. Not only can methods be defined outside of a class, but with a little preparation functions defined inside of classes can remain functions. py> class function(object): ... def __init__(self, func): ... self.func = func ... def __get__(self, obj, cls=None): ... return self.func ... py> class B(object): ... @function ... def f(x, y): # No self. ... return x + y ... py> B.f(23, 42) 65 py> b = B() py> b.f(23, 42) 65 py> type(b.f) <class 'function'> (Alternatively, I could change the metaclass, although that's trickier. Using a custom descriptor is just too easy.) >> Otherwise you are reduced to claiming that there is some sort of >> mystical, undetectable "essence" or "spirit" that makes one of those two >> objects a real method and the other one a fake method, even though they >> have the same type, the same behaviour, and there is no test that can >> tell you which is which. > > It isn't mystical. There are differences in semantics of defining > methods inside or outside of a class that apply in certain situations > (e.g. super(), metaclasses). You have cherrypicked an example that > avoids them. Out of the millions, billions of methods people write, how many do you think use super? 1% 0.1%? 10%? And you accuse *me* of cherrypicking. Not that it matters. As I have shown, even the zero argument form of super can be used. -- Steven -- https://mail.python.org/mailman/listinfo/python-list