Python dynamic property binding and__slots__Tutorial
When developing entity classes with a slightly larger amount of data (such as e-commerce product models, user information classes on social platforms), have you also stepped through these pitfalls?
- A colleague randomly added a bunch of instances to a student during testing.
s.temp_xxxI forgot to delete the temporary attributes. As a result, the data was confused during subsequent debugging, and the problem could not be found for a long time. - After the system went online, it was discovered that hundreds of thousands of small objects occupied far more memory than expected, and the server resources directly alarmed.
- When taking over a piece of legacy code, it is impossible to figure out which core attributes are "specified" by a certain class. You can only go through all the instantiations, which is very costly to maintain.
At this time, Python’s__slots__It can help you control these "excessive freedom" behaviors. But before we get into it, we need to briefly review one of Python's most flexible features: Dynamic binding of properties and methods at runtime.
1. Python’s dynamic binding mechanism
Python is a purely dynamic language. Unlike Java and C++, class attributes and methods are locked during compilation. While the code is running, you can add new properties or functions to a single instance or even the entire class at any time, which is extremely flexible.
1.1 Dynamically bind attributes to a single instance
This is the most basic operation: just assign a property name to the instance that does not exist.
Although this operation is arbitrary, it can easily lead to different instances of the same class having completely different sets of properties, and the code will become difficult to maintain.
1.2 Dynamically bind methods to a single instance
Not only attributes, but also methods can be bound to only a certain instance. But please note: you must passtypes.MethodTypeWrap the function and use the instance itself asselfPass it in.
1.3 Dynamically bind properties/methods to the entire class
If you want all instances to use a new property or method, you can assign a value directly to the class. In this way, both the old instance created before and the new instance created later will have this new member.
Dynamic binding gives Python great flexibility, which is especially suitable for writing prototypes and doing temporary testing. But "excessive freedom" also leads to the problems mentioned earlier. Is there a way to retain the convenience of animal binding while also putting a little "tightening spell" on the animal?__slots__That's the answer.
2. Use__slots__Put a "tightening spell" on the class
__slots__Is a class variable, usually defined as a tuple or list, which lists the attribute names that instances of the class can only have. Once defined, instances cannot add attributes that are not in this whitelist.
2.1 The most basic usage
Declared directly inside the class__slots__ = ('允许的属性1', '允许的属性2', ...)That’s it.
In this way, each instance can only support attributes in the whitelist, avoiding data pollution caused by "sliding" and making the intention of the code clearer: see__slots__Just know what core attributes this class has.
2.2 Things to note in inheritance scenarios
When a class has an inheritance relationship,__slots__There are two pitfalls that are easy to step into:
-
Subclasses do not inherit from parent classes by default.
__slots__limit If the parent class defines__slots__, but the subclass is not explicitly defined, then instances of the subclass will also have the attributes allowed by the parent class + their own default__dict__(That is, you can still add any attributes dynamically), then__slots__The memory optimization effect will also disappear. -
Explicit definition of subclasses
__slots__Finally, the allowed attributes are the union of "parent class + child class" subclass__slots__You only need to declare the additional attributes you need, and there is no need to repeat the attributes already listed in the parent class.
Tips: If you don’t need additional attributes in the subclass and want to strictly inherit everything from the parent class
__slots__Restrictions can be written in subclasses__slots__ = ()(empty tuple), which maintains the limit but does not enable__dict__。
2.3 Modern Python development in progress__slots__The three hidden values of
🔹 Save memory (the most important thing)
Python assigns one to each instance by default__dict__Dictionary to store attributes. The dictionary itself is a very heavy structure. When the number of instances reaches hundreds of thousands or even millions, the memory overhead is considerable. Instead of using__slots__After that, Python no longer creates instances for__dict__, instead using a more compact fixed space to store attribute values, the memory footprint can be reduced several times or even more.
🔹 with@propertyPerfectly compatible
Some students are worried: using__slots__can no longer be used@propertyThe decorator does the attribute checksum calculation. In fact, it’s nothing to worry about. Just put@propertyThe corresponding private variables are also added__slots__Just whitelist.
🔹 When shouldn't be used__slots__
- If your class needs frequently dynamically extended attributes (for example, when writing a crawler, insert a new attribute into the instance every time a field is grabbed), don't use it
__slots__, otherwise the flexibility will be lost. - If you have a lot of dependencies in your project
obj.__dict__orvars(obj)To do batch operations on attributes (such as serialization, reflection), use__slots__This will make all these codes invalid.
3. Suggestions for practical application scenarios
according to__slots__characteristics, the following situations are its best uses:
-
Entity classes created in bulk For example, a single record in log analysis, candidate products in recommendation systems, and transaction snapshots in high-frequency trading. The memory saving effect is very obvious.
-
Internal classes of framework/library It can prevent users from adding attributes to your core objects by "slipping" to a certain extent, ensuring the stability of the framework during runtime.
-
Business classes that require strict control of attributes For example, the account class of the financial system is only allowed to define
id、balance、create_timeand other fixed fields to prevent data from being accidentally contaminated or tampered with.
4. Quick comparison summary
__slots__It has never been a "must have option" for Python development, but using it well in the appropriate scenarios can make your code more stable, save more memory, and have better performance. Next time you design a class that will be instantiated a lot, you might as well ask yourself: "Are the properties of this class already fixed? Do you need to use__slots__Come and take care of it? "

