On Tue, 27 Sep 2005 16:42:21 +0000, Ron Adam wrote: >>> >>> def beacon(self, x): >>>... print "beacon + %s" % x >>>... >> >> >> Did you mean bacon? *wink* > > Of course... remembering arbitrary word letter sequences is probably my > worst skill. ;-) That, and I think for some reason the name Francis > Beacon was in my mind at the time.
I think you mean Francis Bacon *wink* Thanks to everybody for all the feedback, it was useful, but I was finding that I couldn't keep it all straight in my head (as seen by the mistaken conclusions I drew earlier). So I wrote a short script to systematically test the various combinations of functions and methods. I'm satisfied with the results. For the sake of completeness, here are my results: In the script below, ham and spam are defined first as regular functions outside of a class definition. ham is defined with a placeholder for "self", spam is not. They are then assigned (in separate tests) to both an instance and a class. eggs is defined as a class method, and then assigned to an object outside a class. Think of it as the control variable. "Failure" means the call raises an exception, "Success" means it does not. Here are the results: #################### Comparing module function with instance method: ===================================================== Test: func= | ham | spam | eggs | ----------------------+---------+---------+---------+ func(arg) | Failure | Success | Failure | inst.func(arg) | Failure | Success | Success | inst.func(self, arg) | Success | Failure | Failure | Comparing module function with class method: ===================================================== Test: func= | ham | spam | eggs | ----------------------+---------+---------+---------+ func(arg) | Failure | Success | Failure | inst.func(arg) | Success | Failure | Success | inst.func(self, arg) | Failure | Failure | Failure | Comparing object types: ==================================== Where: | ham | spam | eggs | --------------+------+------+------+ module level | f | f | m | instance | f | f | m | class | m | m | m | Key: f = function; m = method; ? = other #################### This clearly shows that assigning a function to a class attribute invokes whatever machinery Python uses to turn that function into a true method, but assigning it to an instance does not. Here is the script for those interested: #################### """Testing of the dynamic addition of functions to classes and instances.""" TABLE = """ %s ===================================================== Test: func= | ham | spam | eggs | ----------------------+---------+---------+---------+ func(arg) | %s | %s | %s | inst.func(arg) | %s | %s | %s | inst.func(self, arg) | %s | %s | %s | """ TABLE2 = """ %s ==================================== Where: | ham | spam | eggs | --------------+------+------+------+ module level | %s | %s | %s | instance | %s | %s | %s | class | %s | %s | %s | Key: f = function; m = method; ? = other """ # Functions and methods to be tested: def ham(self, x): """Function with placeholder self argument.""" return "ham " * x def spam(x): """Function without placeholder self argument.""" return "spam " * x class Klass: def eggs(self, x): """Method defined in the class.""" return "%s eggs" % x eggs = Klass.eggs # Testing functions: def get_type(obj): s = type(obj).__name__ if s == "function": return "f" elif s == "instancemethod": return "m" else: return "?" def single_test(func, args): """Calls func(*args) and returns None if it succeeds or an exception if it fails.""" try: func(*args) return "Success" except Exception, obj: return "Failure" def multiple_test(instance, label): """Runs multiple tests and returns a table of results.""" L = [label] for f in (ham, spam, eggs, instance.ham, instance.spam, instance.eggs): L.append(single_test(f, [1])) for f in (instance.ham, instance.spam, instance.eggs): L.append(single_test(f, [instance, 1])) return TABLE % tuple(L) def type_test(inst1, inst2): L = ["Comparing object types:"] for obj in (ham, spam, eggs, inst1.ham, inst1.spam, inst1.eggs, \ inst2.ham, inst2.spam, inst2.eggs): L.append(get_type(obj)) return TABLE2 % tuple(L) def main(): inst1 = Klass() inst1.ham = ham inst1.spam = spam print multiple_test(inst1, "Comparing module function with instance method:") inst2 = Klass() Klass.ham = ham Klass.spam = spam print multiple_test(inst2, "Comparing module function with class method:") print type_test(inst1, inst2) if __name__ == "__main__": main() #################### I hope this is as interesting and useful for others as it was for me. -- Steven. -- http://mail.python.org/mailman/listinfo/python-list