On 12/15/2011 12:01 AM, Steven D'Aprano wrote:
On Wed, 14 Dec 2011 18:13:36 -0500, Terry Reedy wrote:
On 12/14/2011 3:01 AM, Steven D'Aprano wrote:
On Wed, 14 Dec 2011 01:29:13 -0500, Terry Reedy wrote:
To complement what Eric says below: The with statement is looking for
an instance *method*, which by definition, is a function attribute of
a *class* (the class of the context manager) that takes an instance of
the class as its first parameter.
Note in the above that I am talking about *instance methods*.
I'm not sure that is correct... I don't think that there is anything
"by definition" about where methods live.
Since you are disagreeing with my statement that *instance methods* are
class attributes, you had better be claiming that *instance methods* can
live elsewhere, else your statement has no sense.
From the Python glossary:
"method: A function which is defined inside a class body."
That is actually a bit too narrow, as a function can be added to the
class after it is defined. But the point then is that it is treated as
if defined inside the class body.
Actually, I agree with Greg that rewording like he or I have suggested
would be a good idea.
So I'm happy for the glossary entry to stay as is, because complicating
it would confuse the average coder more than it would educate them.
But the definition as given is strictly wrong, because it fails to
capture the essence of what distinguishes a method from other objects. It
mistakes *how* you normally create a method for *what* a method is, a
little like defining "a hamburger is a foodstuff you get from McDonalds
by giving them money".
Here are three ways that the definition fails:
(1) You can create a function inside a class, and it remains a function,
so long as the class constructor (metaclass) never gets to build a method
object from the function. It is easy to do: just hide it inside a wrapper
object.
class FunctionInsideClass(object):
... def func(x, y): # define a function inside a class
... return x + 2*y
... print(type(func)) # confirm is actually is a function
... attr = (func,) # hide it from the metaclass
... del func
The function is not an attribute of the class, so my revised definition
does not fail.
<class 'function'>
print(type(FunctionInsideClass.attr[0]))
<class 'function'>
(2) Instead of hiding the function from the metaclass, you can change the
metaclass to something which doesn't make methods out of functions. I
won't show an example, because it's tricky to get right (or at least *I*
find metaclasses tricky).
The default metaclass does not 'make methods out of functions'. Rather,
functions that are attributes of an instance of 'type' are treated as
methods *when accessed* via an instance of that instance. In Py 2, they
were wrapped as unbound methods when accessed via the class, but no
longer in Py 3, which simplifies things.
Now, perhaps you can define a metaclass that disables method behavior,
but practically everything one say about normal Python functioning goes
out the window when one invokes 'metaclasses' (which do not even have to
be classes!). So I do not consider this relevant to the discussion.
(3) So the definition is too broad: you can have functions defined inside
classes that are not methods. But it is also too narrow: you can have
methods outside of classes. I'm not talking about bound and unbound
methods, but about *creating* the method from scratch outside of a class.
When you call the method constructor directly, you can create a method
from a function defined outside of a class.
def func(self, a):
... return self + a
...
type(func) # Definitely a function.
<class 'function'>
obj = types.MethodType(func, 42)
As I explained before, the intended input of MethodType is an *instance
method* and an instance of the class it is an attribute of. (Or, I
suspect, a class method and class, which is why the appropriate check in
each case should be outside the call. But I am sticking with instance
methods here.) If so, the output is a *bound method*. In your example
above, func is not an instance method and obj is not a bound method. It
is simply an partially evaluated curried function or if you prefer, a
bound function. Take you pick, or make up your own term, but it is NOT
an instance method, which is the subject under discussion. So obj has
nothing to do with the definition of instance method and whether I had
any authority for the definition I gave to the OP to help him solve his
problem.
obj(23) # Works as expected.
65
Yes, and I can think of three other ways to make an 'add42' function.
type(obj)
<class 'method'>
So what? That means 'bound method', but since your input function to
MethodType is not a method, its output is not a bound method.
So there's a method which has never been inside a class, and couldn't
even if you tried: int is a built-in immutable type.
Calling it a 'method' when it is not even a bound method does not make
it an instance method, which is the subject of discussion.
So what are methods? In Python, methods are wrappers around functions
which automatically pass the instance to the inner function object.
These are bound methods. The instance methods are the functions wrapped.
Particularly not in Python where
instance methods can be attributes of the instance itself.
This is access, not definition or actual location.
Not so. In the example I gave, the method *really is* inside the
instance, stored in the instance __dict__ and not the class __dict__.
Calling the object stored in the instance __dict__ a 'method' does not
make it an instance method.
The glossary entry go
on to say: "If called as an attribute of an instance of that class, the
method will get the instance object as its first argument (which is
usually called self)." This does *not* happen if a callable is found in
the instance-specific dictionary.
That's right.
Here you agree that instance methods are special because of where they
are and how accessed, because that is what the glossary, with my
comment, just said.
Methods are special not because of where they are,
Here you disagree.
An instance method is a function
(callable) attribute of a class that gets special treatment when
accessed (indirectly) through an instance of that class (or subclass
thereof).
Methods aren't functions at all, not in the isinstance sense.
Please, I just specifically clarified that I meant function in the
generic mathemetical callable sense. There is no single function class
for there to be an 'isinstance sense'. 'Callable(f)' means 'hasattr(f,
'__call__')
[snip]
'types.MethodType' is the exposed name of the class the interpreter uses
to create bound methods from a method and an instance of the class
containing the method. I believe the interpreter does an isinstance
check, but it must do that before calling the class, and not in the
bound method constructor itself. In any case, a bound method is not a
method.
Not an instance method, which is the usual default meaning of 'method'
when not qualified. Sorry if you missed that and got confused.
In this case, the result is not really even a bound method, as the
function argument is not a method, so we cannot even ask if the second
arg is an instance of the function class container. MethodType is a
special case of functools.partial, which was added later. You could have
used the latter to the same effect. Or you could have used any old
function that printed the same thing.
Good grief. Is it really your argument that the types.MethodType isn't
actually the type of methods,
Good grief. As I explained, it is the type of *bound methods*. When you
feed it an instance method and an object of the method's class, it
outputs a bound (instance) method. When you feed it a class method and
the corresponding class, I presume it outputs a bound (class) method.
These are the two ways the interpreter uses it.
If a user such as you feeds it any old function and an object that has
no relation to the function (other than its signature), then the result
is a generic bound function and not specifically a bound method.
but a fake that lies about returning methods?
It returns a bound method when you input a (instance/class) method, as
the interpreter does in its routine operation.
I am baffled that you are so insistent on confusing instance methods
with bound instance methods and bound functions. I told the OP that he
needed instance methods and what they are and that indeed is what they
are and what he needs.
--
Terry Jan Reedy
--
http://mail.python.org/mailman/listinfo/python-list