Python class syntax is a good idea?

I am tempted to define my Python classes as follows:

class MyClass(object): """my docstring""" msg = None a_variable = None some_dict = {} def __init__(self, msg): self.msg = msg 

Declares object variables (msg, a_variable, etc.) at the top, like Java, is it good or bad or doesn't it matter? I know this is unnecessary, but still tempting.

+4
source share
4 answers

When you declare a class, Python will parse its code and put everything in the class namespace; then the class will be used as a template for all objects obtained from it, but any object will have its own copy of the link.
Please note that you always have a link; as such, if you can change the reference object, the change will be reflected in all the places in which it is used. However, the slot for the participantโ€™s data is unique for each instance, and therefore, its assignment to a new object is not reflected in any other place in which it is used.

Note. Michael Ford has a very nice blog post on how the class instance works; if you are interested in this topic, I offer you a short reading.

In any case, for all practical applications, there are two main differences between your two approaches:

  • The name is already available at the class level, and you can use it without instantiating a new object; this may seem neat for declaring constants in namespaces, but in many cases the module name may already be good.
  • The name is added at the class level - this means that you cannot easily mock it during unit tests, and if you have any expensive operation, you will receive it at the very moment of import.

Typically, as I look through the code, I see that members declared at the class level are a little suspicious; there are many good utilities for them, but it is likely that they exist as a habit of previous experience with other programming languages.

+1
source

Defining variables in a class definition is similar to making a variable available between each instance of that class. In Java terms, this is a bit like introducing a static variable. However, there are big differences, as shown below.

 class MyClass(object): msg = "ABC" print MyClass.msg #prints ABC a = MyClass() print a.msg #prints ABC a.msg = "abc" print a.msg #prints abc print MyClass.msg #prints ABC print a.__class__.msg #prints ABC 

As you can see from the above code, this is not exactly the same, because while a variable can be accessed via self.msg , when it is assigned a value, it is not assigned to a variable defined in the class scope.

One of the drawbacks of this method with the method is that it can lead to errors because it adds the hidden state of the class. Say someone left self.msg = "ABC" from the constructor (or more realistic code was reorganized and only one of the definitions was changed)

 a = MyClass() print a.msg #prints ABC #somewhere else in the program MyClass.msg = "XYZ" #now the same bit of code leads to a different result, despite the expectation that it #leads to the same result. a = MyClass() print a.msg #prints XYZ 

It is much better to avoid the definition of msg at the class level, and then you avoid the problems:

 class MyClass(object): pass print MyClass.msg #AttributeError: type object 'MyClass' has no attribute 'msg' 
+8
source

Declaring variables directly inside a class definition makes them class variables instead of instance variables. Class variables are somewhat similar to static variables in Java and should be used as MyClass.a_variable . But they can also be used as self.a_variable , which is a problem because naive programmers can treat them as instance variables. For example, your variable "some_dict" will be used by each instance of MyClass , so if you add the key "k" to it, it will be visible to any instance.

If you always remember to reassign class variables, then there are almost no differences in instance variables. Only the initial definition in MyClass will remain. But in any case, this is not a good practice, as you may encounter difficulties when you do not reinstall these variables!

Better write the class as follows:

 class MyClass(object): """ Some class """ def __init__(self, msg): self.__msg = msg self.__a_variable = None self.__some_dict = {} 

Using two underscores for "private" variables ( pseudo-private! ) Is optional. If variables are to be publicly accessible, just keep their names without the __ prefix.

+6
source

Meticulous. The two msg attributes are actually stored in two different dictionaries. One dwarfs the other, but the msg attribute, which goes astray, still takes up space in the dictionary. Thus, it is not used and still takes up some memory.

 class MyClass(object): msg = 'FeeFiFoFum' def __init__(self, msg): self.msg = msg m=MyClass('Hi Lucy') 

Please note that we have 'Hi Lucy' as the meaning.

 print(m.__dict__) # {'msg': 'Hi Lucy'} 

Note that the MyClass dict (accessed via m.__class__ ) still has FeeFiFoFum .

 print(m.__class__.__dict__) # {'__dict__': <attribute '__dict__' of 'MyClass' objects>, '__module__': '__main__', '__init__': <function __init__ at 0xb76ea1ec>, 'msg': 'FeeFiFoFum', 'some_dict': {}, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': 'my docstring', 'a_variable': None} 

Another (possibly simpler) way to see this:

 print(m.msg) # Hi Lucy print(MyClass.msg) # FeeFiFoFum 
+4
source

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


All Articles