?? 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 -- http://mail.python.org/mailman/listinfo/python-list