How do I write a function that adds a method to a class? I have:
class A:
def method(self):
def add_member(name):
self.new_method = def name...?
add_member("f1")
add_member("f2")
In order to answer what I'm trying to do. I'm trying to factor out some pyqt slots. I want to be able to call a function create_slider
that will create a QSlider
and a QLabel
and create the slider handling code, and make the slider-handler update the text in the QLabel
. Here's the slot that needs to be factored out:
def on_sample_slider(self, value):
self.samples = pow(4, value)
self.sample_label.setText('%d' % self.samples)
here's a method that generates some UI, but it would be nice to also have it generate the on_sample_slider method every time it is called:
def insert_labeled_slider(hbox, name, slider_target):
# name
hbox.addWidget(QLabel(name))
# label
label = QLabel()
label.setMinimumSize(40, 0)
hbox.addWidget(self.sample_label)
#slider
slider = QSlider(Qt.Horizontal)
slider.setRange(0, 6)
slider.setTracking(True)
slider.setPageStep(1)
hbox.addWidget(slider)
self.connect(self.sample_slider, SIGNAL('valueChanged(int)'),
self.on_sample_slider)
self.sample_slider.setValue(0)
return (label, slider)
Final code:
def attach_on_slider(obj, name, variable, label, base):
def on_slider(self, value):
variable = base**value
label.setText('%d' % variable)
# This next line creates a method from the function
# The first arg is the function and the second arg is the object
# upon which you want it to be a method.
method = types.MethodType(on_slider, obj)
obj.__dict__["on_slider_" + name] = method
return method
class A:
def insert_labeled_slider(hbox, name, label_name, variable):
# name
hbox.addWidget(QLabel(label_name))
# label
label = QLabel()
label.setMinimumSize(40, 0)
hbox.addWidget(label)
#slider
slider = QSlider(Qt.Horizontal)
slider.setRange(0, 6)
slider.setTracking(True)
slider.setPageStep(1)
hbox.addWidget(slider)
on_slider_method = attach_on_slider(self, name, variable, label, 4)
self.connect(slider, SIGNAL('valueChanged(int)'),
on_slider_method)
slider.setValue(0)
return (label, slider)
Here's an real example from your newly posted code:
import types
def attach_on_sample_slider(obj, base):
def on_sample_slider(self, value):
self.samples = base**value
self.sample_label.setText('%d' % self.samples)
# This next line creates a method from the function
# The first arg is the function and the second arg is the object
# upon which you want it to be a method.
obj.on_sample_slider = types.MethodType(on_sample_slider, obj)
You can now call it like
def some_method(self, foo):
attach_on_sample_slider(self, 4)
original post
Since you say the the member functions are identical, I would do it something like this
def make_method(name):
def method(self, whatever, args, go, here):
#whatever code goes here
method.__name__ = name
return method
class A(object):
method1 = make_method('method1')
method2 = make_method('method2')
Strictly speaking, passing in the name and setting the __name__
attribute on the new function isn't necessary but it can help with debugging. It's a little bit of duplication and can pay for itself. If you are going to skip that though, you might as well do
class A(object):
def method1(self, arg1, arg2):
#code goes here
method2 = method1
method3 = method1
This creates identical methods. Calling either of them will yield the same method.
The first form is more powerful because you can pass other arguments besides the name into make_method
and have the different versions of the returned method access those parameters in closure so they work differently. Here's a stupid example with functions (works the same with methods):
def make_opener(filename):
def opener():
return open(filename)
return opener
open_config = make_opener('config.cfg')
open_log = make_opener('log.log')
Here, they're all essentially the same function but do slightly different things because they have access to the value of filename
that they were created with. Closures are definitely something to look into if you're going to be doing a lot of this sort of thing.
There can be a lot more to this so if you have particular questions that this doesn't address, you should update your question.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With