This code:
def myfunc(): return x
defines a function, but doesn't execute the code inside it where x is until/unless myfunc is called. The body of the function isn't evaluated when the function definition is evaluated, it's evaluated later when the function is called.
In contrast, in this code:
class myclass: func = extfunc
the class definition is evaluated in order to create the class, as described in the docs here. So func = extfunc is evaluated as part of class definition in order to assign a value to the func variable in the class scope. func is like a static member in languages that use that terminology.
A more direct comparison would be this:
class myclass: def example(self): return x
There, return x isn't evaluated until or unless example is called.
See also this example in the documentation:
Attribute references use the standard syntax used for all attribute references in Python: obj.name. Valid attribute names are all the names that were in the class’s namespace when the class object was created. So, if the class definition looked like this:
class MyClass: """A simple example class""" i = 12345 def f(self): return 'hello world'
then MyClass.i and MyClass.f are valid attribute references, returning an integer and a function object, respectively.
In your example, myclass.func would be a valid reference immediately after the class definition, so func = extfunc must be evaluated during the class definition, unlike the body of a function.
__init__, but that’s inefficient for each instance to have its own version of a method.