Python - Recommended way to dynamically add methods to a class

I have a class where I want to initialize the self.listN and add_to_listN for each list item, for example. from attrs = ['list1', 'list2'] I want list1 and list2 initialized as empty lists and the add_to_list1 and add_to_list2 methods that must be created. Each add_to_listN method must take two parameters, for example value and unit , and add a tuple (value, unit) to the corresponding listN .

At the end, the class should look like this:

 class Foo(): def __init__(self): self.list1 = [] self.list1 = [] def add_to_list1(value, unit): self.list1.append((value, unit)) def add_to_list2(value, unit): self.list2.append((value, unit)) 

Leaving aside all the checks and the rest of the class, I came up with the following:

 class Foo(): def __init__(self): for attr in ['list1', 'list2']: setattr(self, attr, []) setattr(self, 'add_to_%s' % attr, self._simple_add(attr)) def _simple_add(self, attr): def method(value, unit=None): getattr(self, attr).append((value, unit)) return method 

I also tested other solutions, such as those suggested here , and I would like to do it “correctly”, so my questions are:

  • Are / should these methods (be) actually a classmethod or not?
  • Are there any costs for creating methods in __init__ , in which case is there an alternative?
  • Where is the best place to run the for loop and add these methods? Within the class definition? From this?
  • Is the use of metaclasses in this case?

Update

Although Benjamin Hodgson makes some good points , I am not asking for a (possibly better) alternative way to do this, but for the better use of these tools I mentioned. I use a simplified example so as not to focus on the details.

To clarify my questions: add_to_listN methods should be optional, and not replace setters / getters (so I still want to be able to do l1 = f.list1 and f.list1 = [] with f = Foo() ).

+4
source share
2 answers

You make a design mistake. You can override __getattr__ , __getattr__ attribute name and return a closure that does what you want, but it is weird to dynamically generate methods, and weird code is bad code. It often happens that you need to do this, but this is not one of them.

Instead of generating methods n , which each of them does the same for one of the objects n , why not just write one method that parameterizes n ? Something like this:

 class Foo: def __init__(self): self.lists = [ [], [] ] def add(self, row, value): self.lists[row].append(value) 

Then foo.add1(x) becomes just foo.add(1, x) ; foo.add2(x) becomes foo.add(2, x) , etc. There is one method, parametrized along the axis of variation, which caters for all cases, rather than litans of special generated methods. It is much simpler.

Do not mix data on your system with data names on your system .

+2
source

I think that Benjamin did not understand what exactly Nick was trying to do.

The fact is that we can recommend when we need to dynamically add methods to the class during instance creation. I vote for Nick’s approach, because that’s exactly what I wanted to do. I made dynamic rules from some descriptive logic, and the rules should have been methods in the class. This means that methods are defined not during class development, but during class instance creation, since descriptive logic is loaded at that moment. I used the decorator that Nick showed in this post, and now it works just fine.

Thanks to Nick for the simple code and yet a powerful solution for the real world!

0
source

Source: https://habr.com/ru/post/1241424/


All Articles