Why can't I invoke a static method inside the class body? - python

class StaticClass(object):
words = []
StaticClass.init()
#staticmethod
def init(file_name):
...
words.append('word')
...
#staticmethod
def fun():
print('fun')
test = StaticClass()
The error message is:
StaticClass.init()
NameError: name 'StaticClass' is not defined
Why can't I call the static function inside the class?
I want to use a class to do this and also want users to be able to do:
StaticClass.fun()
How to achieve the effect?

Why can't I call the static function inside the class?
As said in the comments, class bodies are executed in Python. It is like a zero-argument function that automatically runs once; then invokes type, passing it the class name, bases and a dict of class attributes from the local variables of that function; and only then assigns the result from type (i.e., a class object) to the name.
You can even put logic and other statements in there:
import random
# a class that sometimes fails to exist when you import the module.
class spam:
if __name__ != '__main__':
1 / random.randrange(3)
else:
print("thank you for running this as the main script.")
def __init__(self):
# etc.
As such, names have to be in scope. At the time that this code is running - because it runs immediately and automatically, rather than being delayed like a function - there isn't a StaticClass until after this code has completed. Consequently, the code inside can't reference the class itself.
To solve this, simply move the call to the end:
class StaticClass(object):
words = []
#staticmethod
def init(file_name):
...
words.append('word')
...
#staticmethod
def fun():
print('fun')
StaticClass.init()

By the time the body of the StaticClass class is being executed there is no reference to StaticClass, it doesn't exist yet. The body of the class is executed inside a namespace which is a dictionary. After that a new instance of type type which is here named StaticClass is created using that populated dictionary and added to the global namespaces. That's what class keyword roughly does in simple form.
Actually I don't know why you want this to work. Others already suggested best ways to deal with it but here is workaround if you want to call staticmethod as an initializer function when the class is being created and call it inside the class:
class StaticClass(object):
words = []
#staticmethod
def init(file_name, words=words):
words.append(file_name)
init.__get__(init)('word')
#staticmethod
def fun():
print('fun')
test = StaticClass()
StaticClass.fun()
print(StaticClass.words)
output:
fun
['word']
Yes it's really a mess, I just want to make it work to say why it didn't work before. You need to call init.__get__ because staticmethods are not callable. (I'm in Python 3.9.7) This way you init executed when the class is created. Also words is not accessible because the scope of the class is not enclosed the scope of the body of init, so I use it's reference as default parameter.

Related

Why the code inside a class is executed when defined but a code inside a function is not executed until it gets called?

I'm confused about this behavior,
def calc():
print ("function .. calculating")
class Calc:
print ("Class .. calculating")
Which generates this output:
Class .. calculating
Why the code inside a class gets executed even if we didn't call it or create an object, while the code inside a function doesn't get executed until we call it ?
That statement is not part of any method like __init__ or any method inside the class. As this statement is not a part of any method, the interpreter executes it before invoking the __init__ method (implicit in this case). Invoking the __init__ method means when the __init__ is called when you create an object of this class. That's why this prints it out.
Also another nice point, this would be executed multiple times when you instantiate the object. Because it is only when the interpreter is getting the class definition it executes that once. (From a discussion with Iain Shelvington)
It would be more clear from this output.
class Calc:
print ("Class .. calculating")
print(ab) #throws error
def __init__(self):
print('init')
In this case, if ab is not used earlier then it will throw you error. Very important thing is: the namespace it belongs to, check this:
class Calc:
print ("Class .. calculating")
ab=2
def __init__(self):
print('init')
print(ab) #throws error
Now it will again throw error. Since it is declared inside the class. But you can instantiate the object of the class and access it as something that is part of the class scope.
class Calc:
print ("Class .. calculating")
ab=2
def __init__(self):
print('init')
calc = Calc()
calc.ab # 2
You can check this for further reference. I want to just highlight the subtlety involved in this scope
When a class definition is left normally (via the end), a class object
is created. This is basically a wrapper around the contents of the
namespace created by the class definition; we’ll learn more about
class objects in the next section. The original local scope (the one
in effect just before the class definition was entered) is reinstated,
and the class object is bound here to the class name given in the
class definition header (ClassName in the example).
I totally agree with Tim Roberts. I'm not expert here but for specific below use case, the behavior is useful.
class Foo:
bar = 'Baz'
print(Foo.bar)
This way, you can store some data and need not to instantiate it to use the underlying data.
However, if you want to use it on class instance, it is also available.
f = Foo()
print(f.bar)
That is how the language is designed. The class body is executed when the class is defined. You can read more at docs: 9.3.1. Class Definition Syntax

Can Python Staticmethod Call Another Local Method?

In Python, within a class, can a staticmethod call on another local function/method defined within the same class?
I tried the following code and obtained an error message saying foo1() is not defined.
class trialOne(object):
#staticmethod
def foo1():
a = 3.1
return a
#staticmethod
def foo():
a = foo1()
return a
obj = trialOne()
b = obj.foo()
class Tester:
def local(self):
print "I'm a local!"
#staticmethod
def another_stat():
print "I'm a static!"
#staticmethod
def stat(inst):
inst.local()
Tester.another_stat()
t = Tester()
Tester.stat(t)
# Out:
# I'm a local!
# I'm a static!
Yes, you can! By definition, instance methods need an instance to associate themselves with, but as long as you have that instance, you can call local methods just as you normally would.
To go into this in a little more depth, there's nothing special about the word self. That's a variable just like any other. Any instance method of a class MUST take in an instance of that class as its first parameter, and it's convention to call that parameter self, but you could just as easily use any other name.
If it helps you understand the distinction, these two statements are semantically equivalent:
t.local()
Tester.local(t)
The first is just syntactic sugar for the second. The second is using the class name to reference a method of the Tester class, then passes in the instance as the first parameter. The first simply pretends that local is a field of t and calls it, but that call is transformed into Tester.local(t) by the Python interpreter.
Thus, calling a static method is the same syntax as Tester.local(t), except the first parameter does not have to be an instance of that class.
So classmethods and staticmethods are called in the same way, but the difference is that a class method "knows" what class it's coming from. The first parameter of a class method is always a variable that contains the class that it's being invoked from. That way if the method is inherited, it knows which method it's coming from, where a staticmethod would not know. In your comment, you said this:
#classmethod
def stat(cls):
cls.another_stat()
In this example, cls is a variable that contains the class that the method is being called from, not an instance of the class that it is being called from. That is why you can call static methods with cls - because it is equivalent to Tester

Methods defined outside class which itself is subsequently imported

Is it OK to define functions outside a particular class, use them in the class, and then import that class elsewhere and use it?
Are there any risks associated with doing that, rather than making all functions methods of the class?
I'm writing this code in python 2.7
For example, make a class like this:
def func(a):
return a
class MyClass():
def class_func(self, thing):
return func(thing)
Then import MyClass into another python script and use its class_func method.
Doing this is okay, and in fact a language feature of python. Functions have access to names of the scope they are defined in, regardless of where they are called from.
For example, you can also do something like this:
factor = 2
def multiply(num):
return num*factor
See this post for some background information.
The "risk" associated with this is that the outside name is explicitly not under your control. It can be freely modified by other parts of your program, without the implication being clear.
Consider this example:
def func(a):
return a
class MyClass(object): # note: you should inherit from object in py2.X!
def class_func(self, thing):
return func(thing)
myinstance = MyClass()
foo = myinstance.class_func(1)
def func(a):
return str(a)
bar = myinstance.class_func(1)
Here, foo and bar will be different, namely the integer 1 and the string "1".
Usually, making this possible is the entire point of using such a structure, however.
It's ok, but if func uses only in MyClass it can be helpful to make it staticmethod and place inside MyClass near class_func:
class MyClass(object):
#staticmethod
def _func(a):
return a
def class_func(self, thing):
return type(self)._func(thing)

Unresolved reference in class method

I don't think it is because of the scope of the function, but I get a
Unresolved reference at get_all_predicates(examples).count(predicate_list[0])
inside get_entropy_of_attributes(examples, predicate_list) function in my class Tree:
class Tree:
def get_examples(examples, attributes):
for value in examples:
yield dict(zip(attributes, value.strip().replace(" ", "").split(',')))
def get_all_predicates(examples):
return [d['Predicate'] for d in examples]
def get_entropy_of_attributes(examples, predicate_list):
get_all_predicates(examples).count(predicate_list[0])
return 0
examples = list(get_examples(all_examples, name_of_attributes))
predicate_list = list(set(get_all_predicates(examples)))
get_entropy_of_attributes(examples, predicate_list)
all_examples is a list of dictionary and name_of_attributes is a list, that holds values imported from a text file.
all_examples = [{'P_Length': '1.4', 'P_Width': '0.2', 'Predicate': 'I-setosa', 'Sepal_Width': '3.5', 'S_Length': '5.1'}, ...]
name_of_attributes = ["Check","P-Width"]
Any help?
Classes do not have scopes, only namespaces. This means that functions defined within them cannot see other class variables automatically.
class Foo(object):
var = 1 # lets create a class variable
def foo():
print(var) # this doesn't work!
To access a class variable, you need use attribute syntax: either Foo.var (to access via the class) or, if you're writing an instance method, with self.var (to access via the current instance, which will be passed in as the first argument).
class Bar(object):
var = 1
def bar1():
print(Bar.var) # works
def bar2(self):
print(self.var) # also works, if called on an instance, e.g. `Bar().bar2()`
With this kind of setup you can almost fix your current code (but not quite).
def get_entropy_of_attributes(examples, predicate_list):
Tree.get_all_predicates(examples).count(predicate_list[0]) # name the class
return 0
If you call this after the class is fully initialized, it will work without any exceptions (though it's implementation seems a bit nonsensical). However, it doesn't work when you call it to define a class variable, as your current code does. That's because the class object is only created and bound to the class name after all of the class body has been run.
I think the fix for that is probably to redesign your class in a more conventional way. Rather than having class variables set up based on various globals (like all_examples), you should probably create instances of your class by passing in arguments to the constructor and making the other variables you calculate from them instance attributes. I'd try to write it out, but frankly I don't understand what you're doing well enough.
If you want to call class methods, you have to call them with self, e.g.
class myClass:
def __init__(self):
pass
def get_all_predicates(self):
print('asd')
def do_something(self):
self.get_all_predicates() # working
get_all_predicates() # → Unresolved reference
test = myClass()
test.do_something()
See this link for examples for Python classes.

Is there a way to modify a class in a class method in Python?

I wanted to do something like setattr to a class in class method in Python, but the class doesn't exist so I basically get:
NameError: global name 'ClassName' is not defined
Is there a way for a class method to modify the class? Something like this but that actually works:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, name)
HocusPocus("blah")
HocusPocus("bleh")
Class methods get the class passed as the first argument:
class Bla(object):
#classmethod
def cm(cls,value):
cls.storedValue = value
Bla.cm("Hello")
print Bla.storedValue # prints "Hello"
Edit: I think I understand your problem now. If I get it correctly, all you want to do is this:
class Bla(object):
storedValue = "Hello again"
print Bla.storedValue # prints "Hello again"
Class creation in Python (pretty much) simply means:
Create a fresh namespace.
Run the code that you find inside the class body using this namespace
Put everything that's left in the namespace into the class as class attributes.
Since storedValue is in the namespace after step 2, it's turned into a class attribute in step 3.
Another way you could do this would be to use a class decorator, though these are only available from Python 2.6 onwards IIRC.
Something like this:
def addattributes(cls):
cls.foobar = 10
return cls
#addattributes
class MyClass(object):
pass
print MyClass.foobar
This kind of this most useful when you want to "decorate" a number of classes with some specific functionality / properties. In your case, if you only want to do this once, you might just want to use class methods as previously shown.
While many good suggestions have been advanced, the closest one can get to the originally requested code, that is:
class ClassName(object):
def HocusPocus(name):
setattr(ClassName, name, property(fget=..., fset=...))
HocusPocus("blah")
HocusPocus("bleh")
is this:
class ClassName(object):
def HocusPocus(name):
return property(fget=..., fset=...)
blah = HocusPocus("blah")
bleh = HocusPocus("bleh")
I'm assuming the mysterious ... redacted parts need access to name too (otherwise it's not necessary to pass it as an argument).
The point is that, within the class body, HocusPocus is still just a function (since the class object doesn't exist yet until the class body finishes executing, the body is essentially like a function body that's running in its local dict [without the namespace optimizations typically performed by the Python compiler on locals of a real function, but that only makes the semantics simpler!]) and in particular it can be called within that body, can return a value, that value can be assigned (to a local variable of the class body, which will become a class attribute at the end of the body's execution), etc.
If you don't want ClassName.HocusPocus hanging around later, when you're done executing it within the class body just add a del statement (e.g. as the last statement in the class body):
del HocusPocus

Categories