0

It seems that an acceptable answer to the question

What is a method?

is

A method is a function that's a member of a class.

I disagree with this.

class Foo(object):
    pass

def func():
    pass

Foo.func = func

f = Foo()

print "fine so far"
try:
    f.func()
except TypeError:
    print "whoops! func must not be a method after all"
  1. Is func a member of Foo?
  2. Is func a method of Foo?

I am well aware that this would work if func had a self argument. That's obvious. I'm interested in if it's a member of foo and in if it's a method as presented.

aaronasterling
  • 68,820
  • 20
  • 127
  • 125
  • Follow up to http://stackoverflow.com/questions/3786881/what-is-a-method-in-python/ – Falmarri Sep 24 '10 at 23:12
  • 2
    And as I've said in the other comments, you can't use an example that doesn't run as an example. – Falmarri Sep 24 '10 at 23:12
  • It runs fine until you try to treat `func` as a method. That is the point of the example. – aaronasterling Sep 24 '10 at 23:14
  • 1
    What?? Your code makes no sense. `func` never was a method, so why should it be a method? It is not a member of any class, and nowhere have you said `f.func = func` or anything to that effect, so what were you expecting to happen? func is not a member of Foo. func is not a method of Foo. – Blue Peppers Sep 24 '10 at 23:20
  • @Blue Peppers. Sorry, typo. A drunk was talking at me while I'm at borders. corrected. The original version that sparked this debate did not have that typo. – aaronasterling Sep 24 '10 at 23:22
  • Your exception is correct. func isn't a method. But it's also not a class member – Falmarri Sep 24 '10 at 23:27

3 Answers3

7

You're just testing it wrong:

>>> class Foo(object): pass
... 
>>> def func(self): pass
... 
>>> Foo.func = func
>>> f = Foo()
>>> f.func()
>>> 

You error of forgetting to have in the def the self argument has absolutely nothing to do with f.func "not being a method", of course. The peculiar conceit of having the def outside the class instead of inside it (perfectly legal Python of course, but, as I say, peculiar) has nothing to do with the case either: if you forget to have a first argument (conventionally named self) in your def statements for methods, you'll get errors in calling them, of course (a TypeError is what you get, among other cases, whenever the actual arguments specified in the call can't match the formal arguments accepted by the def, of course).

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
  • But the _whole_ point of my example is that `func` _doesn't_ have a first (and hence, any) parameter and yet it is _still_ a member of `Foo`. – aaronasterling Sep 24 '10 at 23:41
  • @Alex, Can I take your answer as saying that `func`, as defined, _is_ a _method_ of `Foo`? – aaronasterling Sep 24 '10 at 23:46
  • 5
    `func` is a name. When used as a **bare** name, it's not bound to a method object. When used as a **qualified** name, i.e., an attribute of a name bound to the class or an instance thereof, the value it provides **is** a method object (as it happens, a different method object each and every time: `print f.func is f.func` shows `False`). Therefore, the assertion "func is a method" is neither true nor false: it's meaningless. (If the function object doesn't have a first parameter, the method object cannot be called correctly, but of course that does **not** mean it's not a method object!). – Alex Martelli Sep 25 '10 at 00:05
  • But then is func really a function at all if it requires a context parameter? – Falmarri Sep 25 '10 at 00:06
  • 1
    BTW, `print type(f.func)` does of course confirm this, i.e., it shows `InstanceMethod`, quite independently from what parameters `f.func` has or lacks. Why is it so hard for you to accept that this is the case?! – Alex Martelli Sep 25 '10 at 00:07
  • `but of course that does not mean it's not a method object!` Does that mean it **is** a method object then? Are we just arguing for the sake of arguing if we're trying to call a function a method object if that object isn't' callable? – Falmarri Sep 25 '10 at 00:08
  • @Falmarri, `type(x)` tells you what type `x` is. Whether `x` can then be correctly used in a certain way, or not, does **not** determine `type(x)` (although to some large extent, `type(x)` may constrain how `x` can be correctly used, the reverse doesn't hold). E.g., `def f(x): pass` means `f()` and `f(12,34)` will both produce `TypeError`: why would anybody **dream** to read this as "f not being a function"?! – Alex Martelli Sep 25 '10 at 00:11
  • Any callable produces `TypeError` unless called with a sequence (possibly empty) and/or named args within a certain set of acceptable ones; for a buggily written method, the set of acceptable sequences of args simply is the empty set. Empty sets are sets, just like empty sequences are sequences. `type(f.func)` says it's a method: **that's** what "means it **is** a method object", quite independently of what the acceptable set of args sequences may be. Seems obvious to me that the ones "arguing for the sake of arguing" are those who claim `type(f.func)` is lying! – Alex Martelli Sep 25 '10 at 00:15
  • `why would anybody dream to read this as "f not being a function"?` I don't think that's the argument. I think the argument is that it can be read as "f not being a method". Although I've totally lost myself in the semantics and have no idea what the original argument is, lol – Falmarri Sep 25 '10 at 00:15
  • 1
    @Alex. Thanks for clearing up my confusion. I was certain that I was right but I can see now that I was thinking about it incorrectly. – aaronasterling Sep 25 '10 at 00:48
1

The type error wouldn't be thrown if func had a self argument, like any other instance method.

That's because when you evaluate f.func, you're actually binding f to the first argument of the function -- it then becomes a partial application which you can provide further arguments to.

If you want it to be a static method, then you need the staticmethod decorator which just throws away the first parameter and passes the rest into the original function.

So 2 ways of making it work:

def func(self): pass

-- or --

Foo.func = staticmethod(func)

depending on what you're aiming for.

Tom Whittock
  • 4,081
  • 19
  • 24
0

As written, func is a member of Foo and a method of Foo instances such as your f. However, it can't be successfully called because it doesn't accept at least one argument.

func is in f's namespace and has a _call_() method. In other words, it is enough of a method that Python tries to call it like one when you invoke it like one. If it quacks like a duck, in other words...

That this call doesn't succeed is neither here nor there, in my opinion.

But perhaps a proper response to "But Doctor! When I don't accept any arguments in a function defined in a class, I get confused about whether it's really a method or not!" is simply "Don't do that." :-)

kindall
  • 178,883
  • 35
  • 278
  • 309