Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #17180 > unrolled thread
| Started by | Steve Howell <showell30@yahoo.com> |
|---|---|
| First post | 2011-12-13 21:42 -0800 |
| Last post | 2011-12-14 12:46 -0700 |
| Articles | 20 on this page of 27 — 10 participants |
Back to article view | Back to comp.lang.python
AttributeError in "with" statement (3.2.2) Steve Howell <showell30@yahoo.com> - 2011-12-13 21:42 -0800
Re: AttributeError in "with" statement (3.2.2) Eric Snow <ericsnowcurrently@gmail.com> - 2011-12-13 23:05 -0700
Re: AttributeError in "with" statement (3.2.2) Terry Reedy <tjreedy@udel.edu> - 2011-12-14 01:29 -0500
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-14 08:01 +0000
Re: AttributeError in "with" statement (3.2.2) 88888 Dihedral <dihedral88888@googlemail.com> - 2011-12-14 08:08 -0800
Re: AttributeError in "with" statement (3.2.2) 88888 Dihedral <dihedral88888@googlemail.com> - 2011-12-14 08:28 -0800
Re: AttributeError in "with" statement (3.2.2) Steve Howell <showell30@yahoo.com> - 2011-12-14 09:16 -0800
Re: AttributeError in "with" statement (3.2.2) Terry Reedy <tjreedy@udel.edu> - 2011-12-14 18:13 -0500
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-15 05:01 +0000
Re: AttributeError in "with" statement (3.2.2) MRAB <python@mrabarnett.plus.com> - 2011-12-15 05:15 +0000
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-15 07:21 +0000
Re: AttributeError in "with" statement (3.2.2) Gregory Ewing <greg.ewing@canterbury.ac.nz> - 2011-12-16 09:34 +1300
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-15 07:47 +0000
Re: AttributeError in "with" statement (3.2.2) Steve Howell <showell30@yahoo.com> - 2011-12-15 05:35 -0800
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-16 03:34 +0000
Re: AttributeError in "with" statement (3.2.2) Terry Reedy <tjreedy@udel.edu> - 2011-12-15 19:39 -0500
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-16 09:22 +0000
Re: AttributeError in "with" statement (3.2.2) Terry Reedy <tjreedy@udel.edu> - 2011-12-16 17:05 -0500
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-17 01:26 +0000
Re: AttributeError in "with" statement (3.2.2) Terry Reedy <tjreedy@udel.edu> - 2011-12-17 21:09 -0500
Re: AttributeError in "with" statement (3.2.2) Ethan Furman <ethan@stoneleaf.us> - 2011-12-16 15:26 -0800
Re: AttributeError in "with" statement (3.2.2) Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-12-17 03:05 +0000
Re: AttributeError in "with" statement (3.2.2) Ethan Furman <ethan@stoneleaf.us> - 2011-12-16 16:34 -0800
Re: AttributeError in "with" statement (3.2.2) Peter Otten <__peter__@web.de> - 2011-12-14 11:02 +0100
Re: AttributeError in "with" statement (3.2.2) Eric Snow <ericsnowcurrently@gmail.com> - 2011-12-14 09:56 -0700
Re: AttributeError in "with" statement (3.2.2) Lie Ryan <lie.1296@gmail.com> - 2011-12-15 06:14 +1100
Re: AttributeError in "with" statement (3.2.2) Eric Snow <ericsnowcurrently@gmail.com> - 2011-12-14 12:46 -0700
Page 1 of 2 [1] 2 Next page →
| From | Steve Howell <showell30@yahoo.com> |
|---|---|
| Date | 2011-12-13 21:42 -0800 |
| Subject | AttributeError in "with" statement (3.2.2) |
| Message-ID | <b8092181-c306-40bc-a07a-bb35bc925cf1@18g2000prn.googlegroups.com> |
I'm using Python 3.2.2, and the following program gives me an error
that I don't understand:
class Foo:
pass
foo = Foo()
foo.name = "Steve"
def add_goodbye_function(obj):
def goodbye():
print("goodbye " + obj.name)
obj.goodbye = goodbye
add_goodbye_function(foo)
foo.goodbye() # outputs goodbye Steve
foo.__exit__ = foo.goodbye
foo.__exit__() # outputs goodbye Steve
with foo: # fails with AttributeError: __exit__
print("doing stuff")
I am dynamically adding an attribute __exit__ to the variable foo,
which works fine when I call it directly, but it fails when I try to
use foo as the expression in the with statement. Here is the full
output:
> python3 with.coffee
goodbye Steve
goodbye Steve
Traceback (most recent call last):
File "with.coffee", line 17, in <module>
with foo: # fails with AttributeError:
AttributeError: __exit__
What am I doing wrong?
[toc] | [next] | [standalone]
| From | Eric Snow <ericsnowcurrently@gmail.com> |
|---|---|
| Date | 2011-12-13 23:05 -0700 |
| Message-ID | <mailman.3625.1323842756.27778.python-list@python.org> |
| In reply to | #17180 |
On Tue, Dec 13, 2011 at 10:42 PM, Steve Howell <showell30@yahoo.com> wrote:
> I'm using Python 3.2.2, and the following program gives me an error
> that I don't understand:
>
> class Foo:
> pass
>
> foo = Foo()
> foo.name = "Steve"
>
> def add_goodbye_function(obj):
> def goodbye():
> print("goodbye " + obj.name)
> obj.goodbye = goodbye
>
> add_goodbye_function(foo)
> foo.goodbye() # outputs goodbye Steve
> foo.__exit__ = foo.goodbye
> foo.__exit__() # outputs goodbye Steve
>
> with foo: # fails with AttributeError: __exit__
> print("doing stuff")
>
> I am dynamically adding an attribute __exit__ to the variable foo,
> which works fine when I call it directly, but it fails when I try to
> use foo as the expression in the with statement. Here is the full
> output:
>
>> python3 with.coffee
> goodbye Steve
> goodbye Steve
> Traceback (most recent call last):
> File "with.coffee", line 17, in <module>
> with foo: # fails with AttributeError:
> AttributeError: __exit__
>
> What am I doing wrong?
That is a tricky one.
As with many of the special methods (start and end with __) in Python,
the underlying mechanism in the interpreter is directly pulling the
function from the class object. It does not look to the instance
object for the function at any time. See
http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes.
-eric
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-14 01:29 -0500 |
| Message-ID | <mailman.3626.1323844169.27778.python-list@python.org> |
| In reply to | #17180 |
On 12/14/2011 1:05 AM, Eric Snow wrote:
> On Tue, Dec 13, 2011 at 10:42 PM, Steve Howell<showell30@yahoo.com> wrote:
>> I'm using Python 3.2.2, and the following program gives me an error
>> that I don't understand:
>>
>> class Foo:
>> pass
>>
>> foo = Foo()
>> foo.name = "Steve"
>>
>> def add_goodbye_function(obj):
>> def goodbye():
>> print("goodbye " + obj.name)
>> obj.goodbye = goodbye
>>
>> add_goodbye_function(foo)
>> foo.goodbye() # outputs goodbye Steve
>> foo.__exit__ = foo.goodbye
>> foo.__exit__() # outputs goodbye Steve
foo.goodbye, aliased as foo.__exit__, is a *function* attribute of the
foo *instance*.
>> with foo: # fails with AttributeError: __exit__
>> print("doing stuff")
>>
>> I am dynamically adding an attribute __exit__ to the variable foo,
>> which works fine when I call it directly, but it fails when I try to
>> use foo as the expression in the with statement. Here is the full
>> output:
>>
>>> python3 with.coffee
>> goodbye Steve
>> goodbye Steve
>> Traceback (most recent call last):
>> File "with.coffee", line 17, in<module>
>> with foo: # fails with AttributeError:
>> AttributeError: __exit__
>>
>> What am I doing wrong?
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. Notice that goodbye does not take any
parameter. The first parameter is conventionally called 'self', but that
is not a requirement. That it be there, that it expect to be bound to an
instance, and that the function be bound to the class are requirements.
> That is a tricky one.
>
> As with many of the special methods (start and end with __) in Python,
> the underlying mechanism in the interpreter is directly pulling the
> function from the class object. It does not look to the instance
> object for the function at any time. See
> http://docs.python.org/reference/datamodel.html#special-method-lookup-for-new-style-classes.
--
Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-14 08:01 +0000 |
| Message-ID | <4ee857d4$0$11091$c3e8da3@news.astraweb.com> |
| In reply to | #17182 |
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.
I'm not sure that is correct... I don't think that there is anything "by
definition" about where methods live. Particularly not in Python where
instance methods can be attributes of the instance itself.
>>> class Test(object):
... def method(self):
... print("This method is an attribute of the class.")
...
>>> t = Test()
>>> t.method()
This method is an attribute of the class.
>>>
>>> import types
>>> t.method = types.MethodType(
... lambda self: print(
... "This method is an attribute of the instance."), t)
>>> t.method()
This method is an attribute of the instance.
So the normal lookup rules that apply to data attributes, namely
instance, then class, then superclasses, also applies to methods in
Python. In languages that don't allow that sort of thing, like Java, you
need to use convoluted design patterns like Dynamic Proxy to make it
work. In Python, you just create a method and attach it on the instance.
http://stackoverflow.com/questions/8260740/override-a-method-for-an-
instance-of-a-class
But this doesn't apply for special dunder attributes like __exit__, for
speed reasons. (For new-style classes only, classic classes have no such
special casing. This makes automatic delegation a breeze in Python 2 with
classic classes, and a PITA in Python 3. Boo hiss.)
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | 88888 Dihedral <dihedral88888@googlemail.com> |
|---|---|
| Date | 2011-12-14 08:08 -0800 |
| Message-ID | <26514903.334.1323878912493.JavaMail.geo-discussion-forums@pruu23> |
| In reply to | #17184 |
On Wednesday, December 14, 2011 4:01:24 PM UTC+8, 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.
>
> I'm not sure that is correct... I don't think that there is anything "by
> definition" about where methods live. Particularly not in Python where
> instance methods can be attributes of the instance itself.
>
> >>> class Test(object):
> ... def method(self):
> ... print("This method is an attribute of the class.")
> ...
> >>> t = Test()
> >>> t.method()
> This method is an attribute of the class.
> >>>
> >>> import types
> >>> t.method = types.MethodType(
> ... lambda self: print(
> ... "This method is an attribute of the instance."), t)
> >>> t.method()
> This method is an attribute of the instance.
>
>
> So the normal lookup rules that apply to data attributes, namely
> instance, then class, then superclasses, also applies to methods in
> Python. In languages that don't allow that sort of thing, like Java, you
> need to use convoluted design patterns like Dynamic Proxy to make it
> work. In Python, you just create a method and attach it on the instance.
>
> http://stackoverflow.com/questions/8260740/override-a-method-for-an-
> instance-of-a-class
>
> But this doesn't apply for special dunder attributes like __exit__, for
> speed reasons. (For new-style classes only, classic classes have no such
> special casing. This makes automatic delegation a breeze in Python 2 with
> classic classes, and a PITA in Python 3. Boo hiss.)
>
>
>
> --
> Steven
In Python an instance of an object of a class can have its own method.
A living object can use those methods in the class definition and
can acquire a new method at runtime.
[toc] | [prev] | [next] | [standalone]
| From | 88888 Dihedral <dihedral88888@googlemail.com> |
|---|---|
| Date | 2011-12-14 08:28 -0800 |
| Message-ID | <13752584.332.1323880138063.JavaMail.geo-discussion-forums@pruu5> |
| In reply to | #17219 |
On Thursday, December 15, 2011 12:08:32 AM UTC+8, 88888 Dihedral wrote:
> On Wednesday, December 14, 2011 4:01:24 PM UTC+8, 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.
> >
> > I'm not sure that is correct... I don't think that there is anything "by
> > definition" about where methods live. Particularly not in Python where
> > instance methods can be attributes of the instance itself.
> >
> > >>> class Test(object):
> > ... def method(self):
> > ... print("This method is an attribute of the class.")
> > ...
> > >>> t = Test()
> > >>> t.method()
> > This method is an attribute of the class.
> > >>>
> > >>> import types
> > >>> t.method = types.MethodType(
> > ... lambda self: print(
> > ... "This method is an attribute of the instance."), t)
> > >>> t.method()
> > This method is an attribute of the instance.
> >
> >
> > So the normal lookup rules that apply to data attributes, namely
> > instance, then class, then superclasses, also applies to methods in
> > Python. In languages that don't allow that sort of thing, like Java, you
> > need to use convoluted design patterns like Dynamic Proxy to make it
> > work. In Python, you just create a method and attach it on the instance.
> >
> > http://stackoverflow.com/questions/8260740/override-a-method-for-an-
> > instance-of-a-class
> >
> > But this doesn't apply for special dunder attributes like __exit__, for
> > speed reasons. (For new-style classes only, classic classes have no such
> > special casing. This makes automatic delegation a breeze in Python 2 with
> > classic classes, and a PITA in Python 3. Boo hiss.)
> >
> >
> >
> > --
> > Steven
>
> In Python an instance of an object of a class can have its own method.
> A living object can use those methods in the class definition and
> can acquire a new method at runtime.
Therefore, it is possible for an object to build its decision tree of
actions toward a problem of various parameters in the run time.
[toc] | [prev] | [next] | [standalone]
| From | Steve Howell <showell30@yahoo.com> |
|---|---|
| Date | 2011-12-14 09:16 -0800 |
| Message-ID | <9440c6ea-f844-460a-ab88-a8890648c70e@t38g2000prg.googlegroups.com> |
| In reply to | #17184 |
On Dec 14, 12:01 am, Steven D'Aprano <steve
+comp.lang.pyt...@pearwood.info> wrote:
> [...]
>
> So the normal lookup rules that apply to data attributes, namely
> instance, then class, then superclasses, also applies to methods in
> Python. In languages that don't allow that sort of thing, like Java, you
> need to use convoluted design patterns like Dynamic Proxy to make it
> work. In Python, you just create a method and attach it on the instance.
>
> http://stackoverflow.com/questions/8260740/override-a-method-for-an-
> instance-of-a-class
>
> But this doesn't apply for special dunder attributes like __exit__, for
> speed reasons. (For new-style classes only, classic classes have no such
> special casing. This makes automatic delegation a breeze in Python 2 with
> classic classes, and a PITA in Python 3. Boo hiss.)
Thanks to all who responded. Basically, I think the special casing of
the "dunder" attributes threw me off.
Typically, I would just build context managers from a class, but I
wanted to experiment with instances that were built up without the
standard Python class mechanisms, instead following a Javascript-like
closure-based object creation model.
This is what I came up with:
class WithWrapper:
def __init__(self, obj):
self.obj = obj
def __enter__(self):
self.obj['enter']()
def __exit__(self, *args):
self.obj['exit'](*args)
def greeter_context(hello, goodbye):
return {
'enter': lambda: print("---\n" + hello),
'exit': lambda *args: print(goodbye)
}
gc_french = greeter_context("salut", "a plus tard")
with WithWrapper(gc_french):
print("doing stuff")
gc_slang = greeter_context("yo", "later")
with WithWrapper(gc_slang):
print("doing stuff")
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-14 18:13 -0500 |
| Message-ID | <mailman.3659.1323904439.27778.python-list@python.org> |
| In reply to | #17184 |
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.
>
> I'm not sure that is correct... I don't think that there is anything "by
> definition" about where methods live.
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.
> Particularly not in Python where
> instance methods can be attributes of the instance itself.
This is access, not definition or actual location. 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. 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).
>>>> class Test(object):
> ... def method(self):
> ... print("This method is an attribute of the class.")
> ...
>>>> t = Test()
>>>> t.method()
> This method is an attribute of the class.
The bound method t.method is an instance the class exposed as
types.MethodType. In other words, isinstance(t.method, types.MethodType)
== True
>>>> import types
>>>> t.method = types.MethodType(
> ... lambda self: print(
> ... "This method is an attribute of the instance."), t)
Calling any old fruit an apple does not make it one.
Calling any old function a method does not make it one.
'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. So the printed statement is not true.
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.
There is no relation between the object passed as the second arg of
MethodType and what you do with the resulting callable. Either 't' could
be something else. See below.
>>>> t.method()
> This method is an attribute of the instance.
Yes, the callable (which is not a method) is (currently) an attribute of
the instance. But that is irrelevant to its operation. t.method is just
a callable, in particular, a pseudo bound method, not a method. It is
*not* supplying the instance it is called on as the first parameter of
the callable. The arguemnt (which is not used) has already been
supplied. These produce the same output:
class B: pass
b = B()
b.method = t.method
b.method()
f = t.method
f()
t.method = lambda: print("This method is an attribute of the instance.")
t.method()
> So the normal lookup rules that apply to data attributes, namely
> instance, then class, then superclasses, also applies to methods in
> Python.
When you ask the interpreter to resolve a.x, x is just a supposed
attribute, and the interpreter has no idea what class the result should be.
> But this doesn't apply for special dunder attributes like __exit__, for
> speed reasons.
It does not apply to dunder *methods* because they are reserved names
defined to be (bound to) methods. So the interpreter knowing that it is
looking for a method and that methods have to be attributes of classes,
goes directly to the class.
--
Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-15 05:01 +0000 |
| Message-ID | <4ee97f20$0$11091$c3e8da3@news.astraweb.com> |
| In reply to | #17240 |
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.
>>
>> I'm not sure that is correct... I don't think that there is anything
>> "by definition" about where methods live.
>
> 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.
First off, let me preface this by saying that I'm not necessarily saying
that the above glossary definition needs to be changed. For most
purposes, it is fine, since *nearly always* methods are created as
functions defined inside the class body. But it needs to be understood in
context as a simplified, hand-wavy definition which covers 99% of the
common cases, and not a precise, definitive technical definition.
To give an analogy, it is like defining mammals as "hairy animals which
give birth to live young", which is correct for all mammals except for
monotremes, which are mammals which lay eggs.
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
...
<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).
(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)
>>> obj(23) # Works as expected.
65
>>> type(obj)
<class '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.
So what are methods? In Python, methods are wrappers around functions
which automatically pass the instance to the inner function object. Under
normal circumstances, you create methods by declaring functions inside a
class, but that's not the only way to create methods, and it is not the
only place they can be found.
Note that this definition can easily be adapted to describe class methods
and static methods too: class methods are wrappers around functions that
automatically pass the class to the inner function, and static methods
are wrappers which don't pass any automatic arguments.
>> 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__.
> 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. Methods are special not because of where they are, but
because of what they are.
> 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. They are
functions in the sense that any callable object is a function, i.e. they
are callable sub-routines. But they're not functions in the sense of
being instances of type "function". They are wrappers around functions.
Other languages may do things differently, but that's what Python does.
You can even retrieve the function object from the wrapper:
>>> obj.__func__
<function func at 0xb70fd4ec>
>>>>> class Test(object):
>> ... def method(self):
>> ... print("This method is an attribute of the class.") ...
>>>>> t = Test()
>>>>> t.method()
>> This method is an attribute of the class.
>
> The bound method t.method is an instance the class exposed as
> types.MethodType. In other words, isinstance(t.method, types.MethodType)
> == True
>
>>>>> import types
>>>>> t.method = types.MethodType(
>> ... lambda self: print(
>> ... "This method is an attribute of the instance."), t)
>
> Calling any old fruit an apple does not make it one. Calling any old
> function a method does not make it one.
I'm not *calling* a function a method, I'm *creating* a method from a
function object. There is no difference between a method created with
types.MethodType and a method automagically created inside a class except
for the location where the object is stored. The location is irrelevant.
> '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.
That's an astonishing statement. What is your evidence for this amazing
claim that bound methods are not actually methods? What are they then, if
not methods?
> 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, but a fake that lies about returning
methods? Well, that's easy enough to test:
>>> class K(object):
... def f(self):
... pass
...
>>> k = K()
>>> type(k.f) is types.MethodType
True
Unless you are going to accuse me of faking the interpreter output
(perhaps I monkey-patched the type built-in?) that is definitive proof
that types.MethodType is not fake, it actually is the method type used in
classes.
> There is no relation between the object passed as the second arg of
> MethodType and what you do with the resulting callable. Either 't' could
> be something else. See below.
>
>>>>> t.method()
>> This method is an attribute of the instance.
>
> Yes, the callable (which is not a method) is (currently) an attribute of
> the instance. But that is irrelevant to its operation. t.method is just
> a callable, in particular, a pseudo bound method, not a method. It is
> *not* supplying the instance it is called on as the first parameter of
> the callable.
Of course it is. It is because I made it to be that way.
I encourage you to experiment with Python's introspection tools, perhaps
put a few calls to print inside a "pseudo bound method" (your words,
there's nothing pseudo about it) and satisfy yourself that the instance
passed is the same instance as it is called from *under the circumstances
shown*.
> The arguemnt (which is not used) has already been
> supplied. These produce the same output:
>
> class B: pass
> b = B()
> b.method = t.method
> b.method()
Yes. So what? You can take a bound object and attach it to any other
object and see the same results -- this doesn't mean it isn't a bound
object. That's how bound objects work! Your objection fails because any
method will work the same way:
>>> class K: pass
...
>>> class Example:
... def foo(self):
... print(self)
...
>>> x = Example()
>>> k = K()
>>> k.attr = x.foo
>>> k.attr()
<__main__.Example object at 0xb70fcc0c>
No trickery with types.MethodType, no metaclass magic, no sleight of
hand, just stock standard Python behaviour.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | MRAB <python@mrabarnett.plus.com> |
|---|---|
| Date | 2011-12-15 05:15 +0000 |
| Message-ID | <mailman.3663.1323926134.27778.python-list@python.org> |
| In reply to | #17250 |
On 15/12/2011 05:01, 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. >>> >>> I'm not sure that is correct... I don't think that there is anything >>> "by definition" about where methods live. >> >> 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. > > First off, let me preface this by saying that I'm not necessarily saying > that the above glossary definition needs to be changed. For most > purposes, it is fine, since *nearly always* methods are created as > functions defined inside the class body. But it needs to be understood in > context as a simplified, hand-wavy definition which covers 99% of the > common cases, and not a precise, definitive technical definition. > > To give an analogy, it is like defining mammals as "hairy animals which > give birth to live young", which is correct for all mammals except for > monotremes, which are mammals which lay eggs. > [snip] Or the naked mole-rat. Or cetaceans (whales).
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-15 07:21 +0000 |
| Message-ID | <4ee99ffa$0$11091$c3e8da3@news.astraweb.com> |
| In reply to | #17251 |
On Thu, 15 Dec 2011 05:15:58 +0000, MRAB wrote: > On 15/12/2011 05:01, 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. >>>> >>>> I'm not sure that is correct... I don't think that there is anything >>>> "by definition" about where methods live. >>> >>> 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. >> >> First off, let me preface this by saying that I'm not necessarily >> saying that the above glossary definition needs to be changed. For most >> purposes, it is fine, since *nearly always* methods are created as >> functions defined inside the class body. But it needs to be understood >> in context as a simplified, hand-wavy definition which covers 99% of >> the common cases, and not a precise, definitive technical definition. >> >> To give an analogy, it is like defining mammals as "hairy animals which >> give birth to live young", which is correct for all mammals except for >> monotremes, which are mammals which lay eggs. >> > [snip] > Or the naked mole-rat. Or cetaceans (whales). Naked mole-rats and cetaceans do have hair, just not very much of it. E.g. http://marinelife.about.com/od/cetaceans/f/whaleshair.htm -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Gregory Ewing <greg.ewing@canterbury.ac.nz> |
|---|---|
| Date | 2011-12-16 09:34 +1300 |
| Message-ID | <9kv3vhFn8U1@mid.individual.net> |
| In reply to | #17251 |
MRAB wrote: >> To give an analogy, it is like defining mammals as "hairy animals which >> give birth to live young", which is correct for all mammals except for >> monotremes, which are mammals which lay eggs. > > Or the naked mole-rat. Or cetaceans (whales). The way I understand it, the main characteristic shared by all mammals is the presence of mammary glands in females. To wrest this back on topic, sometimes a definition can be improved without making it any more complicated. In the case of methods, perhaps instead of "defined inside a class body" it could say "bound to a name in a class namespace". That's what really matters, not how it came to be there. -- Greg
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-15 07:47 +0000 |
| Message-ID | <4ee9a5f9$0$11091$c3e8da3@news.astraweb.com> |
| In reply to | #17250 |
On Thu, 15 Dec 2011 05:01:21 +0000, Steven D'Aprano wrote: >> 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. [...] > But the definition as given is strictly wrong, because it fails to > capture the essence of what distinguishes a method from other objects. [...] TL;DR http://users.rcn.com/python/download/Descriptor.htm#functions-and-methods Short and sweet. -- Steven
[toc] | [prev] | [next] | [standalone]
| From | Steve Howell <showell30@yahoo.com> |
|---|---|
| Date | 2011-12-15 05:35 -0800 |
| Message-ID | <b1b3a91e-3825-4da5-9a43-c2a518448e4a@18g2000prn.googlegroups.com> |
| In reply to | #17250 |
On Dec 14, 9:01 pm, Steven D'Aprano <steve +comp.lang.pyt...@pearwood.info> wrote: > [...] > So what are methods? In Python, methods are wrappers around functions > which automatically pass the instance to the inner function object. Under > normal circumstances, you create methods by declaring functions inside a > class, but that's not the only way to create methods, and it is not the > only place they can be found. > I've always understood methods as basically function wrappers that pass in the instance, so it's good to hear somebody else formulate it that way. For the special methods like __enter__ and __exit__, the tricky part isn't understanding what would happen once the methods were called; the tricky part is getting them to be called in the first place, if they were not declared inside the class or attached to the class. import types class Blank: pass foo = Blank() foo.name = "foo1" foo.__exit__ = types.MethodType(lambda self, *args: print(self.name), foo) foo.__exit__() # works like a method in python3, prints foo1 with foo: pass
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-16 03:34 +0000 |
| Message-ID | <4eeabc32$0$29979$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #17269 |
On Thu, 15 Dec 2011 05:35:55 -0800, Steve Howell wrote:
> For the special methods like __enter__ and __exit__, the tricky part
> isn't understanding what would happen once the methods were called; the
> tricky part is getting them to be called in the first place, if they
> were not declared inside the class or attached to the class.
If you *must* have per-instance special methods, my advice is to use a
bit of scaffolding like this:
class Whatever:
def __enter__(self, *args):
try:
enter = self.__dict__['__enter__']
except KeyError:
do_something_else() # or just let the exception occur
else:
enter(*args)
Otherwise just live with the limitation that you can override all methods
per-instance *except* dunders, and design your application accordingly.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-15 19:39 -0500 |
| Message-ID | <mailman.3707.1323995986.27778.python-list@python.org> |
| In reply to | #17250 |
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
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-16 09:22 +0000 |
| Message-ID | <4eeb0ddb$0$29979$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #17321 |
On Thu, 15 Dec 2011 19:39:17 -0500, Terry Reedy wrote:
[...]
After reading your post, I think I have worked out where our disagreement
lines: you think that bound methods and instance methods are not the same
thing, and that a function defined inside a class is different from a
function outside of a class.
For example, you say:
> 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,
and later on:
>> 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.
I am afraid you are mistaken. What you say may very well apply to other
languages, but in Python, def creates functions no matter where you
execute it. Always and without exception.
I admit to an earlier mistake: I thought that conversion from function to
method occurred once, when the class statement was executed, but I was
mistaken. Re-reading Raymond Hettinger's excellent article on the
descriptor protocol reminded me that methods are created on an as-needed
basis, at runtime.
Back to methods and def. So let's see what happens in Python 3.1:
>>> def spam(self): # Clearly a function.
... pass
...
>>> class K(object):
... def ham(self): # Allegedly an instance method
... pass
...
According to your various statements, spam is a function and ham is an
instance method. Merely storing a outside function inside a class doesn't
create an instance method, it creates what you call a bound method
(although I'm unclear what you think the difference is). So let's see
what happens when we compare an alleged "bound method that is not an
instance method" with an actual instance method:
>>> K.spam = spam
>>> type(K.spam) is type(K.ham)
True
Their types are identical. We get the same thing when we compare an
actual function with a function object created inside a class, which you
claim is actually an instance method:
>>> type(spam) is type(K.__dict__['ham']) # Bypass descriptor protocol
True
Nor is there any difference in type between bound and unbound methods:
they are both instance methods differing only in whether or not they have
the first argument "self" available. Bound is an adjective, not part of
the type: small method, obfuscated method, buggy method, or bound method.
Python 3 no longer uses unbound methods, since they are functionally
identical to the unwrapped function, so this snippet is from Python 2.6:
py> k = K()
py> type(k.ham) is type(K().ham) # bound vs bound
True
py> type(k.ham) is type(K.ham) # bound vs unbound
True
In Python, instance methods are wrappers around function objects; they
are created on call, and generally do not exist *anywhere* until needed,
or if you store a reference to them.
>>> k = K()
>>> a = k.ham
>>> b = k.ham
>>> a is b
False
Under normal circumstances, the only persistent object is the function,
which you can extract from the (class or instance) __dict__ or the method
wrapper:
>>> a.__func__ is K.__dict__['ham']
True
Methods are created by the descriptor protocol: when you use the normal
a.b syntax to access K.__dict__['ham'], the metaclass calls the __get__
method of function ham. If you call it from an instance, you get a method
object bound to that instance. If you call it from the class, in Python 2
you get a method object not bound to an instance, in Python 3 you get the
function without a wrapper.
[Aside: class methods and static methods also work the same way, via
__get__ and the descriptor protocol, but behave differently. Class
methods reuse the instance method type, which is somewhat confusing, and
static methods just return the function.]
So, what the hell does all this mean in practice?
Most of the time, absolutely nothing. That's why I started this
discussion with the disclaimer that I didn't think it was worth changing
the (not quite right) definition of "method" you originally quoted. Most
of the time, we only access methods via the instance.method syntax, which
gives us an instance method. By the principle that if it quacks like a
duck and swims like a duck, it is good enough to call it a duck, I'm
happy to agree that ham here is a method:
class K:
def ham(self): pass
That covers 99% of all use-cases and is good enough for most situations.
But the OP ran into one of those edge cases in the 1%, where things are
not so simple. He was attempting to create an instance method called
"__exit__" and store it in the instance __dict__ instead of the class
__dict__. This is a perfectly reasonable thing to do, but there are two
gotchas to it:
* The descriptor protocol doesn't get used for instance
lookups. That's why you can't stick properties in an
instance, only in the class.
* CPython, and I believe Jython, don't look up special
dunder methods like __exit__ on the instance, only on
the class.
So even if the OP manually created an instance method rather than relying
on the descriptor protocol, his per-instance __exit__ would not be called
without extra work.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-16 17:05 -0500 |
| Message-ID | <mailman.3753.1324073187.27778.python-list@python.org> |
| In reply to | #17341 |
On 12/16/2011 4:22 AM, Steven D'Aprano wrote: > On Thu, 15 Dec 2011 19:39:17 -0500, Terry Reedy wrote: > [...] > > After reading your post, I think I have worked out where our disagreement > lines: you think that bound methods and instance methods are not the same > thing, Do you agree that an unbound method and a bound method are different? In Python, as indicated by the glossary entry, an unspecified 'method' is usually meant to be an unbound method. It is am important distinction and I do not see why you insist on confusing the two. > and that a function defined inside a class is different from a > function outside of a class. That, and your repetition of the same claim further on, is a insulting lie. Def statements always create functions. I have known that for 14 years since the first day I started with Python. I have never thought differently. If you actually think that I have, you are wrong. What I have said from my first response is that a function that is an attribute of a class, *whether defined in or outside the class*, gets special treatment when accessed via an instance of the class. And that is the truth. If you are ever interested in learning anything from me on this subject, re=read what I already wrote with a more open mind than you have so far. Otherwise, I am done. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-12-17 01:26 +0000 |
| Message-ID | <4eebefc0$0$29979$c3e8da3$5496439d@news.astraweb.com> |
| In reply to | #17388 |
On Fri, 16 Dec 2011 17:05:57 -0500, Terry Reedy wrote:
> On 12/16/2011 4:22 AM, Steven D'Aprano wrote:
>> On Thu, 15 Dec 2011 19:39:17 -0500, Terry Reedy wrote: [...]
>>
>> After reading your post, I think I have worked out where our
>> disagreement lines: you think that bound methods and instance methods
>> are not the same thing,
>
> Do you agree that an unbound method and a bound method are different?
"Are different" or "are different types"?
Bound and unbound methods in Python 2 are the same type. They are
different in the sense that one is effectively a curry of the other, but
they are implemented as a single type. So presumably the difference is a
bound method has a slot filled and an unbound method doesn't, or some
other implementation detail.
In Python 3, unbound methods don't exist.
> In
> Python, as indicated by the glossary entry, an unspecified 'method' is
> usually meant to be an unbound method.
I think you are badly confused here. The glossary talks about calling
methods as an attribute of an instance, e.g. instance.method(), and the
method receiving the instance as the first argument. That's a bound
method, not unbound. How do you conclude that this indicates that an
unspecified "method" is unbound?
Your conclusion is especially nonsensical because unbound methods don't
exist in Python 3 -- you're alleging that the usual meaning of "method"
is something which no longer exists in the language!
method
A function which is defined inside a class body. 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). See function and nested scope.
http://docs.python.org/glossary.html
> It is am important distinction
> and I do not see why you insist on confusing the two.
It is not an important distinction, and I am not confusing the two. Bound
or unbound, it is still an instance method.
>> and that a function defined inside a class is different from a function
>> outside of a class.
>
> That, and your repetition of the same claim further on, is a insulting
> lie.
If you can't assume I'm carrying on this discussion in good faith, then
we have a serious problem. This is not like you Terry -- I've been
reading your posts for many years, and you're not usually so obstreperous.
> Def statements always create functions. I have known that for 14 years
> since the first day I started with Python. I have never thought
> differently. If you actually think that I have, you are wrong.
I'm glad to hear it. But nevertheless you have made statements (which I
quoted, and you deleted from your reply) that suggest the opposite. If I
have misinterpreted them, or if you had worded them badly, there's no
need to attribute malice to me. Calling me a liar for something said in
good faith and which I prefixed with "I think" is simply not cool.
--
Steven
[toc] | [prev] | [next] | [standalone]
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-12-17 21:09 -0500 |
| Message-ID | <mailman.3773.1324174203.27778.python-list@python.org> |
| In reply to | #17398 |
On 12/16/2011 8:26 PM, Steven D'Aprano wrote: > On Fri, 16 Dec 2011 17:05:57 -0500, Terry Reedy wrote: >> It is am important distinction [unbound versus bound] > It is not an important distinction, and I am not confusing the two. So we agree on the distinction but disagree on its importance. Let us leave it at that. > Bound or unbound, it is still an instance method. OK. So 'instance method' is a bit ambiguous (more than I thought, or would prefer) in that it can refer to unbound methods, bounds methods, or both. So be it. >>> and that a function defined inside a class is different from a function >>> outside of a class. >> >> That, and your repetition of the same claim further on, is a insulting >> lie. > > If you can't assume I'm carrying on this discussion in good faith, If you can't assume that I am intelligent and experienced enough to know the meaning of def, one on the most basic aspects of Python, and you are unwilling to give me the benefit of any doubt you might have on that score, but instead go on to 'correct' me publicly, then no, I can't. >> Def statements always create functions. I have known that for 14 years >> since the first day I started with Python. I have never thought >> differently. If you actually think that I have, you are wrong. > > I'm glad to hear it. But nevertheless you have made statements (which I > quoted, and you deleted from your reply) that suggest the opposite. OK, let us look at the my statement and your 'repetition of the same claim further on' that I previously deleted. I wrote >> These are bound methods. The instance methods are the functions wrapped. As I indicated in response to Ethan, I would now revised the second sentence now to "The unbound methods are the function wrapped" or "The instance-requiring methods are the functions wrapped." But that is not important here. In my opinion, there is no way that anyone reading that in good faith could conclude that I do not know the meaning of def statements. They are not the subject of discussion in that sentence or the rest of this thread. But in response you wrote. > I am afraid you are mistaken. About what? You go on to explain. > What you say may very well apply to other languages, > but in Python, def creates functions no matter where you > execute it. Always and without exception. So that makes twice that you said or implied that I think the location of a def statement changes what it creates, even though I explicitly said the opposite when I suggested that the glossary entry might be revised. What am I to think at such a tactic. You are normally much more careful in what you write. > If I have misinterpreted them, or if you had worded them badly, > there's no need to attribute malice to me. I did not do that. I gave my opinion of your statement, just as you have given your opinions of mine. I really did not and do not know why you misrepresented my knowledge of Python. I actually consider overt intentional malice much less likely than other possibilities. > Calling me a liar I did not do that, any more than you have been calling me things. I believe you are asking for the same 'benefit of the doubt' that I believe you denied to me. -- Terry Jan Reedy
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.python
csiph-web