The first thing to note is that Java does not have class methods. It has static methods and regular methods. A regular method receives the instance it was called from as an argument. A class method receives the class is was called from (not the class it is defined on) as an argument. Static methods get nothing special and act like normal functions -- static methods are just a way of grouping logically related methods.
The second thing to note is that a Java class definition is parsed into a separate class definition and an implicit static constructor. When initialising class attributes this enables you to call methods before they are defined in the class body. This is because in the actual program these statements will be called only after the class has been created/loaded into memory. In Python there is no such distinction. Instead, to create a class you execute a series of statements inside a specialised namespace, and this is then used to create the class. Like in a body of a function or module block of code you cannot use a variable before it is exists. This includes using the class within the class body (as it doesn't exist yet!)
eg. This is valid Java:
class X {
static int i = 1;
static X obj = newInstance();
// ^-- executed after the class has been created, but is still being initialised.
static X newInstance() {
return new X();
}
}
But this is not valid Python
class X:
val = 1
obj = new_instance()
# ^-- We're still in the body of X, and neither new_instance nor X has been created yet
@classmethod
def new_instance(cls):
return cls()
# even if new_instance was defined before obj, Python still wouldn't be able to fill
# in the cls argument as X still doesn't exist when new_instance is first invoked
In Python you must do the static construction of your class explicitly. Bear in mind this is exactly what would happen in Java, it's just hidden behind syntactic sugar.
class X:
val = 1 # this can still be done in the class body as it doesn't need the class
obj = None # not necessary, but can help type checkers know that X has an
# attribute obj -- you can use type annotations to further help
@classmethod
def new_instance(cls):
return cls()
# explicit class initialisation of attributes
X.obj = X.new_instance()
run_class_method(cls)
– Knockwurstrun_class_method
isn't defined @Knockwurst – Retiary