Reputation: 16711
So I have a button class that does something when clicked, but different buttons perform different functions. I was wondering if there is such a thing as anonymous inner classes in Python to override such a callback without creating a new class altogether for each type of button. I know that I can assign a callback attribute to call such a function, but I am just wondering if there is an anonymous inner class equivalent.
class Button:
def __init__(self):
# set image here
def update(self):
if mouse_clicked():
# do something
In Java I can create anonymous inner classes to override the update method for close, play, pause, and all other buttons without creating an entirely different class.
class Button {
Button() {
// set image here
}
public void update() {
if mouse_clicked() {
// do something
}
}
}
Upvotes: 1
Views: 1996
Reputation: 102029
Sure, you can (although probably shouldn't) just use type
:
In [1]: class Button:
...: def callback(self):
...: print('Hello')
...:
In [2]: button = type('', (Button,), {'callback': lambda self: print('World')})()
In [3]: button.callback()
World
You may prefer to define the function outside the expression, so as to be able to avoid code-golfing it:
In [5]: def callback(self):
...: print('World')
...: button = type('', (Button,), {'callback': callback})()
...:
In [6]: button.callback()
World
This does exactly what Java is doing, however it does so more explicitly, and thus, with a more cumbersome syntax. In fact in python you can define local classes:
In [7]: def function():
...: class MyButton(Button):
...: def callback(self):
...: print('Hello, from a local class!')
...: return MyButton()
...:
In [8]: button = function()
In [9]: button.callback()
Hello, from a local class!
The only difference with respect to Java is that you must give a name to the class and use it to create an instance. Using a decorator you could avoid this last step:
def auto_instantiator(*args, **kwargs):
def decorator(cls):
return cls(*args, **kwargs)
return decorator
Used as:
In [2]: class Button:
...: def callback(self):
...: print('Button')
...:
In [3]: @auto_instantiator() # here args that should be passed to __init__
...: class button(Button):
...: def callback(self):
...: print('New Button')
...: # no need for button = button(...)
In [4]: button.callback() # button is an *instance* of the button class
New Button
However, depending on how you are going to use that method, I'd suggest two different ways to handle the problem:
Actually all the actions of the buttons are the same, except for some data. In this case it's probably better to just create an instance attribute (or a property) to hold that data, and change the data instead of the method:
I mean something like this:
class Greeter:
def __init__(self, name):
self.name = name
def greet(self):
print('Hello, {.name}'.format(self))
You can just set the instance attribute to the callback you want:
button.callback = new_callback
Upvotes: 1
Reputation: 36462
You don't need to make an anonymous class -- python lets you replace methods with any callable (in fact, any object on the fly):
Button.update = lambda x: x*x
is perfectly valid.
EDIT: The Java approach doesn't actually save you from generating any class -- that class just doesn't have a name, so there's no "benefit" doing that.
Upvotes: 0