Difference between 'function' and 'method'
Bruno Desthuilliers
bruno.42.desthuilliers at wtf.websiteburo.oops.com
Tue Mar 4 06:27:58 EST 2008
?? a écrit :
> Howdy everyone,
>
> This is a big problem puzzles me for a long time. The core question is:
> How to dynamically create methods on a class or an instance?
class Foo(object):
pass
def bar(self, arg):
print "in bar : self == % - arg == %s" % (self, str(arg))
def baaz(self, arg):
print "in baaz : self == % - arg == %s" % (self, str(arg))
f = Foo()
# adding bar as a method to class Foo
Foo.bar = bar
# f now can use bar:
f.bar(42)
# as well as new instances of Foo, of course
g = Foo()
g.bar()
# adding baaz as a method to f, the old way:
import new
f.baaz = new.instancemethod(baaz, f, type(f))
f.baaz()
# adding baaz as a method to g, the other way:
g.baaz = baaz.__get__(g, type(g))
g.baaz()
> Let me state it step by step.
> 1.
> def gunc(self):
> pass
> class A(object):
> def func(self):
> pass
> a = A()
> a.func # gives "bound method", type is "instancemethod"
> A.func # gives "unbound method", type is "instancemethod"
> gunc # gives "function", type if "function"
>
> # ?? Does this line attach a method to instance? ... I don't think so.
> a.gunc = gunc
It doesn't.
> I found stardard library 'new' may help. Is that right?
cf above. If you work with old-style classes, you'll need
new.instancemethod.
> 2.
> a = A() # instance of old class A
> # Do attach a new method to class A...
> b = A() # instance of new class A
> Does "a" can get the new method automatically?
Yes. In Python, a class is itself an object, and is an attribute of it's
instances (instance.__class__). Names are resolved at runtime, and
attributes not found in the instance's __dict__ are looked up in the
class (and then in the superclasses etc).
> Does new method have the *same* concept level with old methods?
The newly added method works exactly the same way as already existing
ones. Not a single difference. The class statement is just syntactic
sugar anyway. The following snippets are equivalent:
# sugar-coated:
class Boo(object):
faaz = 0
def far(self):
type(self).faaz += 1
print self
def frob(self):
print "yadda"
# raw:
def far(self):
type(self).faaz += 1
print self
Boo = type('Boo', (object,), dict(faaz=0, far=far))
def frob(self):
print "yadda"
Boo.frob = frob
> Especially, if there
> are classes inherit from class A, how does name resolution work on this case?
As usual.
> 3.
> How do I write a decroator for a method?
Mostly the same way you'd write a decorator for a function
> Eg:
> class A(object):
> @my_dec
> def func(self):
> pass
> Here, my_dec should return a method rathar than a function/lambda. Am I right?
Nope. Functions defined within a class statement are plain ordinary
functions. It's the lookup mechanism that "turns them into methods" when
they are looked up as attribute of a class. In fact, Python "methods"
are thin callable wrappers around a function, a class and (most of the
time) an instance, wrappers which are created - usually at lookup time -
by the __get__ method of the function type (you may want to read about
the descriptor protocol on python.org - in the section about new style
classes IIRC).
Anyway, you can explore this by yourself:
>>> Boo.far
<unbound method Boo.far>
>>> b.far
<bound method Boo.far of <__main__.Boo object at 0xb787f96c>>
>>> Boo.__dict__['far']
<function far at 0xb7c28aac>
>>> Boo.__dict__['far'] is far
True
>>> f1 = b.far
>>> f2 = b.far
>>> f1 is f2
False
>>> f1()
<__main__.Boo object at 0xb787f96c>
>>> f2()
<__main__.Boo object at 0xb787f96c>
>>> dir(f1)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__',
'__get__', '__getattribute__', '__hash__', '__init__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'im_class', 'im_func', 'im_self']
>>> f1.im_class
<class '__main__.Boo'>
>>> f1.im_func
<function far at 0xb7c28aac>
>>> f1.im_func is far
True
>>> f1.im_self
<__main__.Boo object at 0xb787f96c>
>>> f1.im_self is b
True
>>> bf = Boo.far
>>> bf.im_func
<function far at 0xb7c28aac>
>>> bf.im_func is far
True
>>> bf.im_class
<class '__main__.Boo'>
>>> bf.im_self
>>> bf.im_self is None
True
>>> far.__get__(b, Boo)
<bound method Boo.far of <__main__.Boo object at 0xb787f96c>>
>>> far.__get__(b, Boo).im_func is far
True
>>>
So, to answer your question: what you are decorating are functions, not
methods.
> What does @property @staticmethod... really do? I cannot step-into them for
> source code.
staticmethod wraps the function into an object that, when looked up as
an attribute, will return the raw function instead of returning a method.
property is a type that provides a simple generic implementation for
computed attributes. You'll find more detailed explanations in the doc
(but perhaps not in the most obvious place - it's somewhere in the peps
or in the 'nws style classes' stuff IIRC). Anyway, using it as a
decorator is a somewhat special case (well... to me at least), that will
defined a property with only a getter (the decorated function).
> 4.
> If most of above questions can be solved, then it would be easy to implement
> the feature: "dynamic property attach".
> Eg:
> One class can read/store settings from/to some file based on
> the file content.
> # File: cfg.ini
> x = 1
> y = python
> config = SettingClass('cfg.ini') # dynamically build up properties x and y.
> x = config.x # x will be set to 1 (str -> int convertion would be
> done by 'property x')
> y = config.y # y will be set to 'python'
> config.x = 9 # 'x = 9' is written to cfg.ini.
>
> How to implement
In this case, I'd rather use the __getattr__/__setattr__ hooks. It won't
work with properties nor custom descriptors, since descriptors only work
as class attributes - not as instance attributes (which BTW is why
setting a function as an instance attribute doesn't make it a method...)
here are a couple links to relevant documentation and stuffs:
http://www.python.org/download/releases/2.2.3/descrintro/
http://users.rcn.com/python/download/Descriptor.htm
http://www.python.org/doc/newstyle/
> ^_^ Maybe there are some library does the same thing.
Indeed:
http://www.voidspace.org.uk/python/configobj.html
http://wiki.python.org/moin/ConfigParserShootout
HTH
More information about the Python-list
mailing list