# HG changeset patch # User Paul Boddie # Date 1480343452 -3600 # Node ID 4abc21c107cbcf6b2fbff68dafda99d1b52d2582 # Parent 7267486338ae59baee7b39fe31bfa5e536236877 Allow null contexts in retrieved attributes to override accessor contexts. This allows the use of functions as methods by instances. Make sure that methods which cannot be initialised in class structures are assigned with their context intact. diff -r 7267486338ae -r 4abc21c107cb templates/ops.c --- a/templates/ops.c Mon Nov 28 01:00:10 2016 +0100 +++ b/templates/ops.c Mon Nov 28 15:30:52 2016 +0100 @@ -172,9 +172,9 @@ __attr __test_context(__ref context, __attr attr) { - /* Preserve any existing instance context. */ + /* Preserve any existing null or instance context. */ - if (__is_instance(attr.context)) + if ((attr.context == 0) || __is_instance(attr.context)) return attr; /* Test any instance context against the context employed by the diff -r 7267486338ae -r 4abc21c107cb tests/methods_changing.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/methods_changing.py Mon Nov 28 15:30:52 2016 +0100 @@ -0,0 +1,28 @@ +class C: + def f(self): + return 1 + + def g(self): + return self.f() + +class D(C): + pass + +def f(): + return 2 + +c = C() +d = D() + +# Invoke a method that calls the default version of f. + +print c.g() # 1 +print d.g() # 1 + +# Replace f in C and invoke the method again. For C, f will have changed, +# but for D, f will retain its original value. + +C.f = f + +print c.g() # 2 +print d.g() # 1 diff -r 7267486338ae -r 4abc21c107cb translator.py --- a/translator.py Mon Nov 28 01:00:10 2016 +0100 +++ b/translator.py Mon Nov 28 15:30:52 2016 +0100 @@ -306,7 +306,7 @@ "Return whether 'path' is a method." class_name, method_name = path.rsplit(".", 1) - return self.importer.classes.has_key(class_name) and class_name + return self.importer.classes.has_key(class_name) and class_name or None def in_method(self): @@ -890,8 +890,12 @@ if self.in_conditional or self.in_function: self.process_assignment_for_function(original_name, compiler.ast.Name(name)) elif not ref.static(): + context = self.is_method(objpath) + self.process_assignment_for_function(original_name, - make_expression("((__attr) {0, &%s})" % encode_path(objpath))) + make_expression("((__attr) {%s, &%s})" % ( + context and "&%s" % encode_path(context) or "0", + encode_path(objpath)))) def process_function_defaults(self, n, name, instance_name):