Stroking the line between classes and functions

I have a number of functions that serve to classify data. Each function is passed the same input. The purpose of this system is to be able to abandon the new classification functions at its discretion without the need to adjust anything.

To do this, I use the classes_in_module function, taken from here . Then each classifier in one python file will be run on each input.

However, I find that the implementation of the classifier as a class or function is kludgy. Classes mean instantiation and execution, while functions do not have a pure introspection to allow me to query for a name or use inheritance to define common values.

Here is an example. Firstly, the implementation of the class:

 class AbstractClassifier(object): @property def name(self): return self.__class__.__name__ class ClassifierA(AbstractClassifier): def __init__(self, data): self.data = data def run(self): return 1 

This can then be used in this way, considering that classifier_list is the result of classes_in_module in a file containing ClassifierA among others:

 result = [] for classifier in classifier_list: c = classifier(data) result.append(c.run()) 

However, this seems a little silly. This class is obviously static, and it does not need to maintain its own state, since it is used once and discarded. The classifier is really a function, but then I lose the ability to have a common name property - I would have to use the ugly introspection technique sys._getframe().f_code.co_name and replicate this code for each classifier function. And any other common properties between classifiers will also be lost.

What do you think? Should I just accept this misuse of classes? Or is there a better way?

+5
source share
3 answers

If you do not need multiple instances of the class (and it seems this is not the case), create one instance of the class and change the run value to __call__ :

 class AbstractClassifier(object): @property def name(self): return self.__class__.__name__ class ClassifierA(AbstractClassifier): def __call__(self, data): return 1 ClassifierA = ClassifierA() # see below for alternatives 

and then in another code:

 result = [] for classifier in classifier_list: result.append(classifier(data)) 

Instead of ClassifierA = ClassifierA() (which is not very elegant), you can do:

 classifier_list = [c() for c in (ClassifierA, ClassifierB, ...)] 

This method allows you to maintain your classes as needed if you need to create more instances of them; if you no longer need to have more than one instance, you can use the decorator for IAYG (create an instance on the go;):

 def instantiate(cls): return cls() @instantiate class ClassifierZ(object): def __call__(self, data): return some_classification 
+1
source

Functions may have item data. You can also find the name of the function using the func_name attribute.

 def classifier(data): return 1 classifier.name = classifier.func_name print(classifier.name) #classifier 

If you want several functions to behave the same way, you can use a decorator.

 function_tracker = [] def add_attributes(function): function.name = function.func_name function.id = len(function_tracker) function_tracker.append(function) return function @add_attributes def classifier(data): return 1 print(classifier.name, classifier.id) # 'classifier', 0 

Will this work to avoid classes in your particular case?

+2
source

To use an instance of a class as a function:

 class ClassifierA(AbstractClassifier): def __init__(self, data): self.data = data def __call__(self): return 1 result = [] for classifier in classifier_list: c = classifier(data) result.append(c()) 

Or just use the functions:

 classifier_list = [] def my_decorator(func): classifier_list.append(func) return func @my_decorator def classifier_a(data): return 1 result = [] for classifier in classifier_list: c = classifier(data) result.append(c) 
+1
source

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


All Articles