So, I have learnt that strings have a center method.
>>> \'a\'.center(3)
\' a \'
Then I have noticed that I can do the same thing
To expand on RichieHindle's answer:
In Python, all methods on a class idiomatically take a "self" parameter. For example:
def method(self, arg): pass
That "self" argument tells Python what instance of the class the method is being called on. When you call a method on a class instance, this is typically passed implicitly for you:
o.method(1)
However, you also have the option of using the class Object, and explicitly passing in the class instance:
C.method(o, 1)
To to use your string example, str.center is a method on the str object:
"hi".center(5)
is equivalent to:
str.center("hi", 5)
You are passing in the str instance "hi" to the object, explicitly doing what's normally implicit.
There should be one-- and preferably only one --obvious way to do it.
Philosophically speaking, there is only one obvious way to do it: 'a'.center(3). The fact that there is an unobvious way of calling any method (i.e. the well-explained-by-previous-commentors o.method(x) and Type.method(o, x)) which is useful in many contexts is perfectly in line with the zen of python.
Your homework assignment is to read Guido's Why the Explicit Self Has to Stay.
That's simply how classes in Python work:
class C:
def method(self, arg):
print "In C.method, with", arg
o = C()
o.method(1)
C.method(o, 1)
# Prints:
# In C.method, with 1
# In C.method, with 1
When you say o.method(1)
you can think of it as a shorthand for C.method(o, 1)
. A method_descriptor
is part of the machinery that makes that work.
'a'.center(3) == str.center('a',3)
There is only one way to do it.
Method descriptor is a normal class with __get__
, __set__
and __del__
methods.
When, e.g., __get__
is called, it is passed 2 or 3 arguments:
self
, which is the descriptor class itself,inst
, which is the caller objet to which the "described" method should be bound,cls
, which can be None
.To illustrate method_descriptor machinery, let me give this example:
class Descriptor(object):
def __init__(self, m):
self._meth=m
def __get__(self, inst, cls=None):
if cls is None: cls=type(inst)
delattr(cls,self._meth.func_name)
def _inst_meth(*a):
return self._meth(inst,*a)
return _inst_meth
def instanceonlymethod(f):
return Descriptor(f)
class Test(object):
def meth_1(self,*a):
return '-'.join(str(i) for i in a)
@instanceonlymethod
def meth_2(self,*a):
return '-'.join(str(i) for i in a)
t=Test()
print t.meth_1(2,3,4,5) #returns: 2-3-4-5
print Test.meth_1(t,1,2,3,4) #returns: 1-2-3-4
print t.meth_2(2,3,4,5) #returns: 2-3-4-5
try:
print Test.meth_2(t,1,2,3,4)
except Exception, why: #for 2.6, see changes
print why #returns: type object 'Test' has no attribute 'meth_2'
Now, when you call Test.meth_2(t, 1,2,3,4)
, it won't work.