I have a code like this:
def my_func():
pass
class MyClass():
class_variable = my_func()
pass
i = MyClass()
Since my_func is logically related to MyClass, and doesn't serve any purpose outside of it, I'd prefer to have something like that instead:
class MyClass():
class_variable = my_func()
def my_func():
pass
i = MyClass()
The above doesn't work, of course, because my_func isn't defined yet at the time it's called. Is there some other way to assign a class variable from inside the class?
I'd personally keep my_func() outside the class. Sure, it may only be used for the class definition, but if it is not useful once the class is defined, it should not be part of the class API.
If the my_func() function should be used together with the class even after the class has been created, then you can still make this work with MyClass.my_func() being a static method. In that case define the function first before setting the class variable:
class MyClass():
#staticmethod
def my_func():
pass
class_variable = my_func.__func__()
The #staticmethod is not strictly necessary as at the time class_variable is set, my_func is still a local name in the class definition body.
However, since you are using it as as static function anyway, you may as well mark it as such. The advantage however is that MyClass.my_func() now also works.
Because a #staticmethod isn't going to bind outside of a class or instance attribute context, you do need to unwrap it first by accessing the wrapped function with the __func__ attribute.
Demo:
>>> class MyClass():
... #staticmethod
... def my_func():
... return 'foobar'
... class_variable = my_func.__func__()
...
>>> MyClass.class_variable
'foobar'
>>> MyClass.my_func()
'foobar'
Related
I am working with an external module with a class A and function foo. The class calls the function inside it
def foo(...):
...
class A:
def m(self, ...):
...
foo()
...
...
I need to change the behavior of foo without editing the module. Is there a neat way to do it, without subclassing class A?
Define the replacement function, then assign it to the class function.
def replacement_m(...):
...
from external_module import A
A.m = replacement_m
Unfortunately you can't just replace foo(), because it isn't a class method. You have to replace the whole A.m method.
This is called monkeypatching. See this question for more information What is monkey patching?
My case:
class BaseClass:
#staticmethod
def dummy_decorator(fnc):
def wrapper():
print('Im so dummy')
return wrapper
class InheritedClass(BaseClass):
def __init__(self):
pass
def anymethod(self):
print('hello world')
When I look at dir(), I see my staticmethod
>>> c = InheritedClass()
>>> dir(c)
['__doc__', '__init__', '__module__', 'anymethod', 'dummy_decorator']
Also, I can use my dummy operator as simple staticmethod inside new class.
But when I try to use it as decorator -- I get error
class InheritedClass(BaseClass):
def __init__(self):
pass
#dummy_decorator
def anymethod(self):
print('hello world')
>>> NameError: name 'dummy_decorator' is not defined
Why it works so?
I know, that if I change #dummy_decorator to #BaseClass.dummy_decorator -- everything will work, but why I can't use decorator without ref to parent class?
The reason why is baecause it is a static method, it belongs to the class as you have figured out when you put #BaseClass.dummy_decorator and it worked.
It is an attribute of the class so you can't just refer to it by dummy_decorator unless you move it out of the class or save it into the global namespace
To understand this properly, you need to understand how class definitions work. In a nutshell, everything inside a class block is executed just like regular Python code. Every name that has been created inside that class block (e.g. def or variable assignments) are then wrapped up at the end of the class block and become attributes of the new class object. It goes something like:
# START CAPTURE
def __init__(self):
pass
foo = 'bar'
# END CAPTURE
InheritedClass = # OBJECT WITH ATTRIBUTES "CAPTURED" ABOVE AND ADDITIONAL MAGIC
So, any code within the class block is just regular Python code. It hasn't "inherited" anything yet. That's the "additional magic" applied to the resulting class object at the end of the class block. And since there's no global "dummy_decorator" name defined, you can't call it by that name. It exists as "BaseClass.dummy_decoator", same as it would outside any class block.
I'm writing a method decorator and require access to the class defining the method that is currently decorated.
The issue seems with this is, that with Python 3 methods in a class are just functions unless the class is instantiated.
Is there any way around this? I don't really want to fiddle around with __qualname__...
In [29]: class A:
....: def B(self):
....: pass
....:
In [30]: A.B.__qualname__
Out[30]: 'A.B'
# This is what I want:
>>> get_class(A.B)
A
You can't, because at the time your decorator on a method is run, the class is yet to be created.
An example illustrates this a little better:
class Foo:
#spam
def bar(self): pass
When spam(bar) is invoked to produce a decorated function, we are inside the pseudo-function that Python runs to define the class body. Only when that pseudo-function is done executing, is the local namespace of that function turned into the class body and the actual class object itself is created.
That means that there is no Foo class object yet at the time spam() is run.
Instead, create a class decorator:
#spam
class Foo:
def bar(self): pass
Now spam() is passed the whole, complete Foo class giving you access to both the class and the methods.
If you need to mark specific methods on the class for decoration, you could use a marker decorator that sets attributes on the function:
def marker(func):
func._marked = True
return func
Use this decorator in the class body on methods that you want decorated, then use the class decorator to pick out those methods:
#spam
class Foo:
#marker
def bar(self): pass
def baz(self): pass
This is annoying:
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
MyClass.foo()
Is there a way to make this work without naming MyClass in the call? i.e. so I can just say foo() on the last line?
There is no way to use foo and get what you want. There is no implicit class scope, so foo is either a local or a global, neither of which you want.
You might find classmethods more useful:
class MyClass:
#classmethod
def foo(cls):
print "hi"
#classmethod
def bar(cls):
cls.foo()
This way, at least you don't have to repeat the name of the class.
Not possible. It is a question of language design. Compare that to C++, where both this (the same as Python self; in Python you have to write self.var, in C++ you may write just var, not this->var) and own class are used by default in member functions, and you will probably see that sometimes that's good and sometimes that's annoying. The only thing possible is to get used to that feature.
You 'variable-ize' the class name. This will not remove, but shorten the name.
class MyClass:
#staticmethod
def foo():
print "hi"
#staticmethod
def bar():
c.foo()
c = MyClass
You can do something hacky by making a module level function foo and then adding it to the class namespace with staticmethod:
def foo():
print "hi"
class MyClass(object):
foo = staticmethod(foo)
#classmethod
def bar(cls):
return cls.foo()
def baz(self):
return foo()
c = MyClass()
c.bar()
c.baz()
MyClass.bar()
MyClass.foo()
In ruby you can do this:
class A
def self.a
'A.a'
end
end
puts A.a #-> A.a
How can this be done in python. I need a method of a class to be called without it being called on an instance of the class. When I try to do this I get this error:
unbound method METHOD must be called with CLASS instance as first argument (got nothing instead)
This is what I tried:
class A
def a():
return 'A.a'
print A.a()
What you're looking for is the staticmethod decorator, which can be used to make methods that don't require a first implicit argument. It can be used like this:
class A(object):
#staticmethod
def a():
return 'A.a'
On the other hand, if you wish to access the class (not the instance) from the method, you can use the classmethod decorator, which is used mostly the same way:
class A(object):
#classmethod
def a(cls):
return '%s.a' % cls.__name__
Which can still be called without instanciating the object (A.a()).
There are two ways to do this:
#staticmethod
def foo(): # No implicit parameter
print 'foo'
#classmethod
def foo(cls): # Class as implicit paramter
print cls
The difference is that a static method has no implicit parameters at all. A class method receives the class that it is called on in exactly the same way that a normal method receives the instance.
Which one you use depends on if you want the method to have access to the class or not.
Either one can be called without an instance.
You can also access the class object in a static method using __class__:
class A() :
#staticmethod
def a() :
return '{}.a'.format( __class__.__name__ )
At least this works in Python 3.1