In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-04-11 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article mainly explains "how Python turns a class method into multiple methods". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "how Python turns a class method into multiple methods".
1. How does ddt achieve parameterization?
Let's review the writing of the ddt library in the previous article:
Import unittest from ddt import ddt,data,unpack @ ddt class MyTest (unittest.TestCase): @ data ((3,1), (- 1,0), (1.2,1.0)) @ unpack def test (self, first, second): pass
Ddt provides four decorators: one @ ddt added to the class, and three @ data, @ unpack, and @ file_data added to the class methods (not mentioned earlier).
Let's first look at the role of the three decorators added to the class methods:
# ddt version (win): 1.2.1 def data (* values): global index_len index_len = len (str (len (values) return idata (values) def idata (iterable): def wrapper (func): setattr (func, DATA_ATTR, iterable) return func return wrapper def unpack (func): setattr (func, UNPACK_ATTR) True) return func def file_data (value): def wrapper (func): setattr (func, FILE_ATTR, value) return func return wrapper
Their combined effect is to add attributes to the class method setattr (). When will these attributes be used? Let's take a look at the @ ddt decorator source code added to the class:
The first layer of the for loop iterates through all the class methods, followed by two branches of if/elif, corresponding to DATA_ATTR/FILE_ATTR, that is, the two sources of the corresponding parameters: data (@ data) and file (@ file_data).
The elif branch has the logic to parse the file, which is similar to processing data, so we skip it and focus on the previous if branch. The logic of this part is very clear, and the main tasks completed are as follows:
Parameter key-value pairs of ergodic class methods
Create a new method name based on the original method and parameter pair
Get the document string of the original method
Unpack parameters of tuples and list types
Add a new test method to the test class and bind parameters to the document string
Analyzing the source code, you can see that the @ data, @ unpack and @ file_data decorators mainly set properties and pass parameters, while the @ ddt decorator is the core processing logic.
This scheme of dispersing decorators (adding them to classes and class methods respectively) and then combining them is not elegant. Why can't it be used uniformly? Later, we will analyze its unspeakable hidden, press the table first, and see what other implementation schemes are like.
2. How to realize parameterization of parameterized?
Let's review the writing of the parameterized library in the previous article:
Import unittest from parameterized import parameterized class MyTest (unittest.TestCase): @ parameterized.expand ([(3mem1), (- 1d0), (1.5d1.0)]) def test_values (self, first, second): self.assertTrue (first > second)
It provides a decorator class @ parameterized, the source code is as follows (version 0.7.1), mainly do some initial checksum parameter parsing, not our focus, skip.
We focus on the expand () method of this decorator class, which is written in its documentation comments:
A "brute force" method of parameterizing test cases. Creates new test cases and injects them into the namespace that the wrapped function is being defined in. Useful for parameterizing tests in subclasses of 'UnitTest', where Nose test generators don't work.
The two key actions are "creates new test cases (create a new test unit)" and "inject them into the namespace … (injected into the namespace of the original method)".
On the first point, it is similar to ddt, except that some differences in naming style, as well as different parsing and binding of parameters, are not worth paying much attention to.
The biggest difference is, how to make the new test method effective?
Parameterized uses an "injection" approach:
Inspect is a powerful standard library, which is used to obtain the information of the program call stack. The purpose of the first three sentences of code is to take out f_locals, which means "local namespace seen by this frame", where f_locals refers to the local namespace of the class.
When it comes to local namespaces, you might think of locals (), but we mentioned in a previous article that "locals () and globals () read and write problems." locals () is readable and unwritable, so this code uses f_locals.
3. How to realize parameterization of pytest?
As usual, take a look at the writing in the previous article:
Import pytest @ pytest.mark.parametrize ("first,second", [(3jing1), (- 1d0), (1.5d1.0)]) def test_values (first,second): assert (first > second)
First see "mark", pytest built-in some tags, such as parametrize, timeout, skipif, xfail, tryfirst, trylast, etc., but also support user-defined tags, you can set execution conditions, group filter execution, and modify the original test behavior, and so on.
The usage is also very simple, however, the source code is much more complicated. Let's just focus on parametrize. Let's take a look at the core code:
According to the passed parameter pair, it copies the call information of the original test method and stores it in the list to be called. Unlike the two libraries analyzed earlier, it does not create new test methods here, but reuses existing methods. By looking up the Metafunc class to which parametrize () belongs, you can trace the usage of the _ calls list:
Finally, it is executed in the Function class:
The funny thing is, here we can see a few lines of God's notes.
Reading (dabbling in) the source code of pytest is really asking for trouble. However, it can be roughly seen that when it implements parameterization, it uses the scheme of the generator, and the test method is called once after traversing a parameter, while the previous ddt and parameterized parse all the parameters at once, generate n new test methods, and then give them to the test framework to schedule.
By contrast, the ideas of the first two libraries are clear, and because they are designed simply to achieve parameterization, unlike pytest, which has any markup and too much abstract design, it is easier to read and understand. The first two libraries give full play to the dynamic characteristics of Python, setting class properties or injecting local namespaces, while pytest seems to be a slightly clumsy idea borrowed from some static language.
At this point, I believe you have a deeper understanding of "how Python turns a class method into multiple methods". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.