Python staticmethod decorator with inheritance - python

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.

Related

Assign Python class variable with a method of that class

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'

How to add a classmethod in Python dynamically

I'm using Python 3.
I know about the #classmethod decorator. Also, I know that classmethods can be called from instances.
class HappyClass(object):
#classmethod
def say_hello():
print('hello')
HappyClass.say_hello() # hello
HappyClass().say_hello() # hello
However, I don't seem to be able to create class methods dynamically AND let them be called from instances. Let's say I want something like
class SadClass(object):
def __init__(self, *args, **kwargs):
# create a class method say_dynamic
SadClass.say_dynamic() # prints "dynamic!"
SadClass().say_dynamic() # prints "dynamic!"
I've played with cls.__dict__ (which produces exceptions), and with setattr(cls, 'say_dynamic', blahblah) (which only makes the thingie callable from the class and not the instance).
If you ask me why, I wanted to make a lazy class property. But it cannot be called from instances.
#classmethod
def search_url(cls):
if hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url
Maybe because the property hasn't been called from the class yet...
In summary, I want to add a lazy, class method that can be called from the instance... Can this be achieved in an elegant (nottoomanylines) way?
Any thoughts?
How I achieved it
Sorry, my examples were very bad ones :\
Anyway, in the end I did it like this...
#classmethod
def search_url(cls):
if not hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url
And the setattr does work, but I had made a mistake when testing it...
You can add a function to a class at any point, a practice known as monkey-patching:
class SadClass:
pass
#classmethod
def say_dynamic(cls):
print('hello')
SadClass.say_dynamic = say_dynamic
>>> SadClass.say_dynamic()
hello
>>> SadClass().say_dynamic()
hello
Note that you are using the classmethod decorator, but your function accepts no arguments, which indicates that it's designed to be a static method. Did you mean to use staticmethod instead?
If you want to create class methods, do not create them in the __init__ function as it is then recreated for each instance creation. However, following works:
class SadClass(object):
pass
def say_dynamic(cls):
print("dynamic")
SadClass.say_dynamic = classmethod(say_dynamic)
# or
setattr(SadClass, 'say_dynamic', classmethod(say_dynamic))
SadClass.say_dynamic() # prints "dynamic!"
SadClass().say_dynamic() # prints "dynamic!"
Of course, in the __init__ method the self argument is an instance, and not the class: to put the method in the class there, you can hack something like
class SadClass(object):
def __init__(self, *args, **kwargs):
#classmethod
def say_dynamic(cls):
print("dynamic!")
setattr(self.__class__, 'say_dynamic', say_dynamic)
But it will again reset the method for each instance creation, possibly needlessly. And notice that your code most probably fails because you are calling the SadClass.say_dynamic() before any instances are created, and thus before the class method is injected.
Also, notice that a classmethod gets the implicit class argument cls; if you do want your function to be called without any arguments, use the staticmethod decorator.
As a side note, you can just use an instance attribute to hold a function:
>>> class Test:
... pass
...
>>> t=Test()
>>> t.monkey_patch=lambda s: print(s)
>>> t.monkey_patch('Hello from the monkey patch')
Hello from the monkey patch
How I achieved it:
#classmethod
def search_url(cls):
if not hasattr(cls, '_search_url'):
setattr(cls, '_search_url', reverse('%s-search' % cls._meta.model_name))
return cls._search_url

Dealing with class inheritance in python

Can someone explain why I'm getting the error:
global name 'helloWorld' is not defined
when executing the following:
class A:
def helloWorld():
print 'hello world'
class B(A):
def displayHelloWorld(self):
helloWorld()
class Main:
def main:
b = B()
b.displayHelloWorld()
I'm used to java where class B would obviously have a copy of class A's method "helloWorld" and thus this code would run fine when executing main. This however appears to think class B doesn't have any method called "helloWorld"
Missing the self before the helloWorld(). The self keyword means that this an instance function or variable. When class B inherits class A, all the functions in class A can now be accessed with the self.classAfunction() as if they were implemented in class B.
class A():
def helloWorld(self): # <= missing a self here too
print 'hello world'
class B(A):
def displayHelloWorld(self):
self.helloWorld()
class Main():
def main(self):
b = B()
b.displayHelloWorld()
You need to indicate that the method is from that class (self.):
class B(A):
def displayHelloWorld(self):
self.helloWorld()
Python differs in this from Java. You have to specify this explicitly in Python whereas Java accepts implicitly as well.
I don't know what is the version of python used in this example but it seems that syntax looks like python3. (except print statement which looks like python2.x)
Lets suppose that this is python3
I would say that helloWorld is class method of class A and It should be called as class attribute. As soon as this function is in class namespace It can be accessed outside this class only using owner class.
A.helloWorld()
or
B.helloWorld()
or
self.__class__.helloWorld()
You can't call it as bound method in this case because self argument will be passed and as soon as your function doesn't expect it it will fail.
there is possibility that helloWorld is method of A and self parameter is just missed
in this case this method can be called as follow:
self.helloWorld()
or
A.helloWorld(self)

How to refer overriden class functions in python

I know C++ and Java and I am unfamiliar with Pythonic programming. So maybe it is bad style what I am trying to do.
Consider fallowing example:
class foo:
def a():
__class__.b() # gives: this is foo
bar.b() # gives: this is bar
foo.b() # gives: this is foo
# b() I'd like to get "this is bar" automatically
def b():
print("this is foo")
class bar( foo ):
def b( ):
print("this is bar")
bar.a()
Notice, that I am not using self parameters as I am not trying to make instances of classes, as there is no need for my task. I am just trying to refer to a function in a way that the function could be overridden.
What you want is for a to be a classmethod.
class Foo(object):
#classmethod
def a(cls):
Foo.b() # gives: this is foo
Bar.b() # gives: this is bar
cls.b() # gives: this is bar
#staticmethod
def b():
print("this is foo")
class Bar(Foo):
#staticmethod
def b():
print("this is bar")
Bar.a()
I've edited your style to match the Python coding style. Use 4 spaces as your indent. Don't put extra spaces in between parenthesis. Capitalize & CamelCase class names.
A staticmethod is a method on a class that doesn't take any arguments and doesn't act on attributes of the class. A classmethod is a method on a class that gets the class automatically as an attribute.
Your use of inheritance was fine.
Quote from the Execution Model:
The scope of names defined in a class block is limited to the class
block; it does not extend to the code blocks of methods – this
includes generator expressions since they are implemented using a
function scope.
This mean that there is no name b in the scope of function a. You should refer to it via class or instance object.

calling class/static method from class variable in python

I'm trying to make a ImageLoader class handle the loading and processing of image resources like this:
class ImageLoader:
TileTable = __loadTileTable('image path', some other variable)
#staticmethod
def _loadTileTable(arg1, arg2):
blah blah
however, on compile i get: NameError: name '_loadTileTable' is not defined
If i replace the second line with TileTable = ImageLoader.__loadTileTable('image path', some other variable) then i get NameError: name 'ImageLoader' is not defined
As i'm going from C# to Python, static classes with static methods is what i'd use to implement this. However, i'm open to how I'd do this in general in python (that is, call static library functions that are only grouped together by their functionality).
UPDATE:
After reading both answers, I'm getting a picture that what i'm trying to do probably isn't right.
How would I go about imlementing ImageLoader so that I can do this:
Assuming that tile table returned an array
module1.py
aTile = ImageLoader.TileTable[1]
module2.py
anotherTile = ImageLoader.TileTable[2]
ideally, i'd populate TileTable just once.
Update:
Thanks for all the answers, I found my last answer to populating TileTable just once in the python modules doco
"A module can contain executable
statements as well as function
definitions. These statements are
intended to initialize the module.
They are executed only the first time
the module is imported somewhere"
As for static class, i'm going to forgo classes and just make a module level variable.
Answering just the updated question, what you would do in Python is make TileTable a variable called tile_table in a module called imageloader. There is no reason at all to put any of this inside a class.
So then you get:
module1.py
import imageloader
aTile = imageloader.tile_table[1]
module2.py
import imageloader
anotherTile = imageloader.tile_table[2]
and imageload.py looks something like:
def _loadTileTable(arg1, arg2):
pass # blah blah
tile_table = _loadTileTable('image path', other_var)
Think of a Python module as a singleton instance in other languages (which in fact it is) and you'll be able to reconcile this with any OO preconceptions you inherited from other languages.
In Python, the code in the class block is first executed, then the resultant namespace is passed to the class initializer. The code you wrote could have also been written as:
TileTable = _loadTileTable(arg1, arg2)
#staticmethod
def _loadTileTable(arg1, arg2):
pass # blah blah
ImageLoader = type('ImageLoader', (), {'TileTable': TileTable, '_loadTileTable': _loadTileTable})
del TileTable
del _loadTileTable
As you can see, the call of _loadTileTable appears before the definition of it. In your example, within the class definition, the call to _loadTileTable must come after the definition of _loadTileTable.
One possible fix is to simply re-arrange the class definition.
class ImageLoader:
def _loadTileTable(arg1, arg2):
pass # blah, blah
TileTable = _loadTileTable('image path', other_var)
Note that I removed the 'staticmethod', because at the point where _loadTileTable is called, it's being called as a function and not a method. If you really want it to be available after class initialization, you can define it as a static method after the fact.
class ImageLoader:
def _loadTileTable(arg1, arg2):
pass # blah, blah
TileTable = _loadTileTable('image path', other_var)
_loadTileTable = staticmethod(_loadTileTable)
Class-level variables which get updated are a bad, bad thing. Our default expectation is that object instances are stateful and classes are stateless.
In this case, we're trying to "magically" initialize a collection as a class variable, which is a toweringly bad idea. A collection is simply an object with simple instance-level attributes.
The magical Tile Table should not be a concealed, static part of the ImageLoader. There is no possible reason for that. It should be an argument to the ImageLoader if you want to avoid loading it more than once.
Separating these promotes testability. It's not arbitrary. It's how unit testing gets done.
What you want is this.
class ImageLoader( object ):
def __init__( self, theTileTable ):
self.tile_table= theTileTable
class TileTable( object ):
def __init__( self, path, some_other_arg ):
self.tileTable= self._loadTileTable( path, some_other_arg )
def _loadTileTable(arg1, arg2):
blah blah
No static anything. Independent units. More easily testable. No weird dependencies. No magic.
Is there a design reason you're using a static method? If so, because you're not overloading the class initialization, you'll need to declare the variable after the method definition.
But, if you do this, you'lll get a new error:
NameError: name 'arg1' is not defined
The reason for this is because you're executing the method within the class before the class is even instantiated, therefore you never have a chance to pass the arguments to the method.
So, the proper way to do this is to overload the __init__() method so that assignment to TileTable only happens when the class is constructed:
class ImageLoader(object):
def __init__(self, arg1, arg2):
self.TileTable = self._loadTileTable(arg1, arg2)
#staticmethod
def _loadTileTable(arg1, arg2):
print arg1, arg2
This gives you the ability to call ImageLoader._loadTileTable() without having an instance, but then it also allows you to create the TileTable instance variable upon creating an instance.
Using a Class method
In response to my comment about the possible need for a classmethod, here is an example that covers this:
class ImageLoader:
#classmethod
def _loadTileTable(cls, arg1, arg2):
return arg1, arg2
# We're creating the class variable outside of the class definition. If you're doing
# this in a module, no one will ever notice.
ImageLoader.TileTable = ImageLoader._loadTileTable('foo', 'bar')
There might be a better way to do this, I don't know. But I do think that this covers what you are looking for:
>>> i = ImageLoader()
>>> i
<__main__.ImageLoader instance at 0x100488f80>
>>> ImageLoader.TileTable
('foo', 'bar')
>>> i.TileTable
('foo', 'bar')
There you have an instance i that has access to the class variable, but ImageLoader.TileTable is still available from the class object without the need for an instance.

Categories

Resources