does anyone have idea how to refer to class static method in the class attributes? for example:
class A(object):
var = A.staticMethod1 # this line doesn't work, as A has not be defined yet.
#staticmethod
def staticMethod1(*param):
pass
Class blocks are just temporary scopes, so, it's actually pretty simple. Just move the alias below the method definition, and take off the class name (since you're in scope directly)
class A(object):
#staticmethod
def staticMethod1(*param):
pass
var = staticMethod1
Related
I'm trying to instantiate a class within a function, then call a method within the class inside the same function, like this:
# Define the class
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
# Define the function that utilizes the class
def func(class,func,str)
instance = class(str)
class = class.func()
# Run the function that utilizes the class
func(myclass,myclass_func,str)
But I am getting an error like "'myclass' object is not callable". Why is this? Additionally, I expect my 'class = class.func()' line is wrong; if it is, what is the correct way to call the method from the recently instantiated class?
Edit: fixed mistake in class declaration
You can't use method names as global variables. If you want to call a method dynamically, pass its name as a string and use the getattr() function.
# Define the class
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
# Define the function that utilizes the class
def func(class,func,str)
instance = class(str)
return getattr(instance, func)()
# Run the function that utilizes the class
func(myclass,'myclass_func',str)
Define your class using the class keyword rather than def.
Create an instance of the class.
Define a function that will try to execute the function given by its name.
class myclass:
def __init__(self,string_to_print):
self.string_to_print = string_to_print
def myclass_func(self):
print(self.string_to_print)
myclass_instance = myclass('Hello world')
def execute_function(instance, function):
getattr(instance, function)()
execute_function(myclass_instance, 'myclass_func')
Output:
Hello world
I have the following class and class variables:
class MyClass:
class_var_1 = "a"
class_var_2 = run_class_method()
#classmethod
def run_class_method(cls):
return "ran class method"
However, the interpreter says that run_class_method isn't defined. Using MyClass.run_class_method() doesn't work either. Coming from a java background, I don't understand why this doesn't work. So, how can I fix it?
Additionally, I discovered that this works if I define class variables at the end of the class. Is this considered bad practice in python?
Class body in python is an executable context, not like Java that only contains declaration. What this ultimately means is that sequence of execution is important within a class definition.
To quote the documentation:
class definition is an executable statement.
...
The class’s suite is then executed in a new execution frame (see Naming and binding), using a newly created local namespace and the original global namespace. (Usually, the suite contains mostly function definitions.) When the class’s suite finishes execution, its execution frame is discarded but its local namespace is saved. [4] A class object is then created using the inheritance list for the base classes and the saved local namespace for the attribute dictionary. The class name is bound to this class object in the original local namespace.
Some more lengthier explanations.
If you want to call a function to define a class variable, you can do it with one of these ways:
use staticmethod:
class MyClass:
def _run_instance_method():
return "ran instance method"
run_instance_method = staticmethod(_run_instance_method)
class_var_1 = "a"
class_var_2 = _run_instance_method() # or run_instance_method.__func__()
or define it as a standalone function:
def run_method():
return "ran method"
class MyClass:
class_var_1 = "a"
class_var_2 = run_method()
# optional
run_method = staticmethod(run_method)
or access the original function with __func__ and provide a dummy cls value:
class MyClass:
#classmethod
def run_class_method(cls):
return "ran class method"
class_var_1 = "a"
class_var_2 = run_class_method.__func__(object())
or set the class variables after class creation:
class MyClass:
#classmethod
def run_class_method(cls):
return "ran class method"
class_var_1 = "a"
MyClass.class_var_2 = MyClass.run_class_method()
MyClass is not yet defined when its class attributes are still being defined, so at the time class_var_2 is being defined, MyClass is not yet available for reference. You can work around this by defining class_var_2 after the MyClass definition block:
class MyClass:
class_var_1 = "a"
#classmethod
def run_class_method(cls):
return "ran class method"
MyClass.class_var_2 = MyClass.run_class_method()
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()
Another way to do this would be to define a parent class that has control over the creation of its subclasses (or a metaclass). Below, we use __init_subclass__ in a parent class to set the attribute during class creation.
class InitVar():
def __init_subclass__(cls, varname, funcname, **kwargs):
class_method = getattr(cls, funcname)
setattr(cls, varname, class_method())
class MyClass(InitVar, varname="class_var_2", funcname="run_class_method"):
class_var_1 = "a"
#classmethod
def run_class_method(cls):
return "ran class method"
print(MyClass.class_var_2)
# ran class method
I'm looking for an equivalent to the static { ... } block in Java that can be used in Python classes. Specifically, I want to be able to access static resources like the arguments of the class constructor and store them in a field of the class, like so:
class A:
constructor_args = A.__init__.__code__.co_varnames
def __init__(self, foo=0, bar=1):
...
This example doesn't work, because class A is not yet initialized when I call A.__init__.__code__.co_varnames.
My current workaround is to alter the static field after the class has been created like so:
class A:
constructor_args = ...
def __init__(self, foo=0, bar=1):
...
constructor_args = A.__init__.__code__.co_varnames
But this solution is rather ugly because I change a static field of a class outside of the class context and if the class contains a lot of code, it's easy to miss out on what is going on here.
So basically I need a way to call a function right after the class has been initialized, and I want to define this function inside of the class.
You will have to at least define the __init__ method first, but you can access its properties immediately after:
class Foo:
def __init__(self, bar, baz):
pass
constructor_args = __init__.__code__.co_varnames
Inside the class block code executes inside its own namespace, so __init__ is directly accessible as __init__.
Here is a simple approach that postpones execution of code that needs the finished class by moving it inside a function defined inside the class body. To have the function called and deleted after use we define a simple decorator:
import inspect
def finalizing(cls):
cls.__finalize__(cls)
del cls.__finalize__
return cls
#finalizing
class example:
def __finalize__(me):
me.constructor_args = list(inspect.signature(me.__init__).parameters)
def __init__(self, x):
pass
example.constructor_args
# ['self', 'x']
You could use a class decorator:
def store_constructor_args(cls):
cls.constructor_args = cls.__init__.__code__.co_varnames
return cls
#store_constructor_args
class A:
def __init__(self, foo=0, bar=1):
x = 10
print(A.constructor_args)
# ('self', 'foo', 'bar', 'x')
#store_constructor_args
class A:
is equivalent to
class A:
...
A = store_constructor_args(A)
I am creating a couple of 'Child' classes which are quite similar and thus wanted to group common methods in a parent class. My problem comes when trying to access static variables of the child classes from the super class.
The following code throws the error: NameError: name 'var' is not defined
class Parent:
#staticmethod
def do_something_with_var():
print(var)
class Child(Parent):
var = "Hello world"
Child.do_something_with_var()
Next thing I tried was obviously to declare var in Parent, but the same error persists.
class Parent:
var = ""
#staticmethod
def do_something_with_var():
print(var)
class Child(Parent):
var = "Hello world"
Child.do_something_with_var()
A solution that I found was to receive the sender class, but then the call becomes a bit ugly:
class Parent:
#staticmethod
def do_something_with_var(cls):
print(cls.var)
class Child(Parent):
var = "Hello world"
Child.do_something_with_var(Child)
You are confused over the usage of staticmethods(your third attempt), accessing class variables (second attempt).
What you want to do is classmethods, as shown under (Python 2.7):
class Parent(object):
#classmethod
def do_something_with_var(cls):
print cls.var
class ChildA(Parent):
var = "Child A"
ChildA.do_something_with_var() # prints Child A
This example is equivalent to your third attempt.
Static scoping of the method means it is bound to the class scope as a namespace, without any reference to the class.
What you need is to have a #classmethod, so that you are able to get a reference to the class.
class Something(object):
our_random = Something.random_thing
#staticmethod
def random_thing():
return 4
Of course, this doesn't work, becauese Something doesn't exist when I attempt to call its method. Nor does this:
class Something(object):
our_random = random_thing
#staticmethod
def random_thing():
return 4
I've "solved" this by Just placing random_thing()'s definition above the class, but I find this messy.
Call it in the .__init__() initializer then:
class Something(object):
def __init__(self):
self.our_random = Something.random_thing()
or call the static method after you defined it, but are still defining the class; because it is a static method, you'd have to access it through the __func__ attribute:
class Something(object):
#staticmethod
def random_thing():
return 4
our_random = random_thing.__func__()
If you didn't mean to call it, just create a copy of the method with a different name, just do so after you defined it:
class Something(object):
#staticmethod
def random_thing():
return 4
our_random = random_thing # our_random as an alias for random_thing
The class body is executed as a function, with the local namespace of the function then forming the class attributes. So, like a function, if you want to refer to other objects you need to make sure they are defined first.
class Something(object):
#staticmethod
def random_thing():
return 4
our_random = random_thing
Class definitions create a namespace, so you can refer to other names (class attributes) within the class body without needing to access them through the class.