Additionally, it makes no sense to call an *instance* method such as
f1() in a class context. Or in Java-speak: you can't call a non-static
method in a static context.
<nit>Actually, in python it does make sense, with a caveat that you have
to provide the instance as the first argument (i.e. as 'self'). The
semantic of "instance method" in python is a class method whose first
argument is curried/bound to a specific instance.</nit>
I think it's better not to confuse OP even further by drawing comparison
with Java; as Python and Java has a confusingly similar name but wholly
different "static method". Also python has nothing similar to "static
context".
The way classes work in Python, C2 isn't actually created until after
its body suite has been executed, so that's why Python can't find f1.
That isn't the reason why OP's code doesn't work. Python cannot find f1
because there is no f1 in the current scope. Class definition in Python
is done by *execution of class body*; the class body is executed in *a
new scope*, which will later become the class' scope. (btw, a "scope" in
python is nothing but sugar for a dictionary (waves a limb airily)).
An instance's scope is a shadow of the class' scope [with respect to
descriptor protocol] + __dict__ + the rest of __mro__; and this __mro__
is not known until the class body execution is finished and type() is
called to create the class. That's why f1() is not in the class' scope
at class declaration time.
In fact, the whole class declaration syntax is more or less sugar for:
class_scope = {}
exec "pass" in globals(), class_scope
Foo = type("Foo", (Parent1, Parent2), class_scope)
# class Foo(Parent1, Parent2):
# pass
the exec statement cannot access its Parent scope, except by explicit
reference through globals() (e.g. Parent1.foo).