Python classes, how to use them in style, and the principle of shared responsibility

I have been programming in Python for some time and have learned some Python-style knowledge, but still have a problem on how to use classes correctly. When I give an object-oriented lecture, I often find rules such as the principle of shared responsibility, which indicates

"The principle of shared responsibility says that a class should have one and only one, a reason for change."

Reading this, I can think of breaking one class into two, for example:

class ComplicatedOperations(object): def __init__(self, item): pass def do(self): ... ## lots of other functions class CreateOption(object): def __init__(self, simple_list): self.simple_list = simple_list def to_options(self): operated_data = self.transform_data(self.simple_list) return self.default_option() + operated_data def default_option(self): return [('', '')] def transform_data(self, simple_list): return [self.make_complicated_operations_that_requires_losts_of_manipulation(item) for item in simple_list] def make_complicated_operations_that_requires_losts_of_manipulation(self, item): return ComplicatedOperations(item).do() 

This, for me, raises many different questions; as:

  • When should you use class variables or pass arguments in class functions?
  • Should the ComplicatedOperations class be a class or just a collection of functions?
  • If the __init__ method is used to calculate the final result. This makes this class difficult to test.
  • What are the rules for pythons?

Edited after the answers:

So, reading Augusto’s theory, I get something like this:

 class ComplicatedOperations(object): def __init__(self): pass def do(self, item): ... ## lots of other functions def default_option(): return [('', '')] def complicate_data(item): return ComplicatedOperations().do(item) def transform_data_to_options(simple_list): return default_option() + [self.complicate_data(item) for item in simple_list] 

(A small bug with default_option has also been fixed.)

+6
source share
4 answers

When to use class variables or pass arguments in class functions

In your example, I would pass item to the do method. In addition, it is associated with programming in any language, gives the class only the necessary information (least authority) and passes everything that is not an internal algorithm for you through the parameters (Injection Dependency), therefore, if ComplicatedOperations does not need an element for initialization, do not specify its as an init parameter, and if it needs an element to complete this task, specify it as a parameter.

If the ComplicatedOperations class is a class or just a collection of functions

I would say it depends. If you use different types of operations, and they share some interface or contract, absolutely. If the operation reflects some concept, and all methods are associated with the class, of course. But if they are free and not related to each other, you can just use the functions or think about Single Responsability again and divide the methods into other classes.

If the init method is used to calculate the final result. This makes this class difficult to test.

No, the init method is for initialization, you have to do your work on the split method.

As a side note, due to lack of context, I did not understand what CreateOption . If it is used only as shown above, you can simply remove it ...

+1
source

I personally think of classes as concepts. I would define an Operation class that behaves like an operation, so it contains a do () method and every other method / property that can make it unique.

As Mimilson correctly says, if you cannot define and isolate a concept, perhaps a simple functional approach would be better.

To answer your questions:

  • you must use class attributes when a particular property is shared with instances (in class attributes, Python is initialized at compile time, so another object will see the same value. Normally class attributes must be constants). Use instance attributes to use object properties for use in your methods without passing them. This does not mean that you should put everything in yourself, but only what you consider characteristic of your object. Use past variables to have values ​​that do not take into account your object, and may depend on the state of external objects (or on program execution).
  • As stated above, I would save one operation of the class and use the list of Operation objects to perform your calculations.
  • The init method will simply instantiate the object and make all the processing necessary for the object to behave properly (in other words, make it read).
  • Just think about the ideas you are trying to model.
+1
source

A class is usually an object type. Class instances are specific objects of this type. A classic example is the Animal class. a cat will be an instance of Animal . (I assume that you mean those that belong to the instance, not the class object itself) should be used for instance attributes. In this case, for example, colour may be an attribute of a class that will be set as cat.colour = "white" or bear.colour = "brown" . Arguments should be used where the value may come from some source outside the class. If the Animal class has a sleep method, it may need to know the duration of sleep and posture in which the animal sleeps. duration will be the argument of the method, since it is not related to the animal, but posture will be a class variable, since it is determined by the animal.

In python, a class is usually used to group together a set of functions and variables that share state. Continuing the above example, a particular animal has a state that is shared between its methods and is determined by its attributes. If your class is just a group of functions that are in no way dependent on the state of the class, then they can just as easily be separate functions.

If __init__ used to calculate the final result (which should be stored in the class attribute, since __init__ cannot return the result), then you can also use the function. However, the general scheme is to do a lot of processing in __init__ several other, sometimes private, class methods. The reason for this is that large complex functions are often easier to test if they are broken down into smaller and more precise tasks, each of which can then be tested individually. However, this is usually done only when the class is needed anyway.

One approach to an entire business is to start by deciding what kind of functionality you need. When you have a group of functions or variables that all act or apply to the same object, then it's time to move them to the class. Remember that object-oriented programming (OOP) is a design method that is suitable for some tasks, but is not inherently a super-functional programming (in fact, some programmers will argue about the opposite!), Therefore there is no need to use classes, if not really necessary.

+1
source

Classes are an organizational structure. So, if you do not use them for organization, you are doing it wrong. :)

There are several different ways you can use them to organize:

  • Linking data to methods using the specified data defines one spot in which code will interact with this data.
  • Linking together as functions together provides an understandable api, since “everyone knows” that all mathematical functions are in a mathematical object
  • To provide a certain connection between methods, it establishes a "conveyer belt" of operations with a specific interface. Each operation is a black box and can be changed arbitrarily if it complies with the standard.
  • Abstract concept. This may include subclasses, data, methods, etc. Etc. Around some central idea, such as access to a database. Then this class becomes a component that you can use in other projects with a minimal amount of refitting.

If you do not need to do any organizational thing, as indicated above, then you need to go for simplicity and a program in a procedural and functional style. Python is a toolbox, not a hammer.

+1
source

All Articles