Completely master the double-down method in Python

WBOY
Release: 2022-07-21 17:50:37
forward
2147 people have browsed it
<p>This article brings you relevant knowledge about <a href="//m.sbmmt.com/course/list/31.html" target="_blank">Python</a>. There are some special methods in Python whose method names begin and end with double underscores, so they are also called double underscore methods. Let’s take a look at it together, I hope it will be helpful to everyone. </p> <p><img src="https://img.php.cn/upload/article/000/000/067/62d4f1fd38dfa174.jpg" alt="Completely master the double-down method in Python" ></p> <p>[Related recommendations: <a href="//m.sbmmt.com/course/list/31.html" target="_blank">Python3 video tutorial</a>]</p> <h2>Preface</h2> <p>Everyone has something to remember when writing Python code There is no such doubt. </p> <p>Why does the <code> </code> number in mathematics become a splicing function in string operations, such as <code>'ab' 'cd'</code>The result is <code>abcd</code>; and the number <code>*</code> becomes a repeated function, such as <code>'ab' * 2</code>, the result is <code>abab</code>. </p> <p>Why some objects<code>print</code>can output data, but <code>print</code>custom class objects output a bunch of incomprehensible code<code><__main__. MyCls object at 0x105732250></code>. </p> <p>It’s not because the system has been specially customized, but because there is a special type of method in Python that is automatically called on certain occasions. For example, after the <code>__add__</code> method is defined in the string class <code>str</code>, when the code encounters string addition <code>'ab' 'cd'</code>, it will Automatically call the <code>__add__</code> method to complete string splicing. </p> <p>Because the method names of this type of special method start and end with double underscores, they are also called double-underscore methods. </p> <p>There are many double download methods in Python. Today we will explain it in detail. </p> <p style="text-align:center"><img alt="" src="https://img.php.cn/upload/article/000/000/067/dc4eae5d11b7bd06ec193c866274280b-0.jpg"></p> <p style="text-align:center">Double download method in Python</p> <h2>1. The init method</h2> <p><code>__init__</code> is a method that many people come into contact with The first<code>Double down method</code>. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class A: def __init__(self, a): self.a = a</pre><div class="contentsignin">Copy after login</div></div><p>When calling <code>A()</code> to instantiate an object, the <code>__init__</code> method will be automatically called to complete the initialization of the object. </p><h2>2. Double under method of operator</h2><p>Define operator-related <code>double under method</code> in the class, you can directly add, subtract, multiply, divide, and compare on the class object Wait for operations. </p><p>Here, define a ruler class <code>Rule</code>, which contains an attribute <code>r_len</code> representing the length of the ruler. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class Rule: def __init__(self, r_len): self.r_len = r_len</pre><div class="contentsignin">Copy after login</div></div><h3>2.1 Comparison operators</h3><p>If you want to compare different rulers according to their length, you need to define comparison operators in the <code>Rule</code> class. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class Rule: def __init__(self, r_len): self.r_len = r_len # < 运算符 def __lt__(self, other): return self.r_len < other.r_len # <= 运算符 def __le__(self, other): return self.r_len <= other.r_len # > 运算符 def __gt__(self, other): return self.r_len > other.r_len # >= 运算符 def __ge__(self, other): return self.r_len >= other.r_len</pre><div class="contentsignin">Copy after login</div></div><p>Four comparisons <code><</code>, <code><=</code>, <code>></code> and <code>>=</code> are defined here operator, so that the <code>Rule</code> objects can be compared using the following code. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">rule1 = Rule(10) rule2 = Rule(5) print(rule1 > rule2) # True print(rule1 >= rule2) # True print(rule1 < rule2) # False print(rule1 <= rule2) # False</pre><div class="contentsignin">Copy after login</div></div><p>When <code>></code> is used to compare <code>rule1</code> and <code>rule2</code>, the <code>rule1</code> object will automatically call <code> __gt__</code> method, and pass the <code>rule2</code> object to the <code>other</code> parameter to complete the comparison. </p><p>The following is the double-under method of the comparison operator</p><p style="text-align:center"><img alt="" src="https://img.php.cn/upload/article/000/000/067/dc4eae5d11b7bd06ec193c866274280b-1.png"/></p><p style="max-width:90%">The double-under method of the comparison operator</p><h3>2.2 Arithmetic operators</h3><p>Can support addition, subtraction, multiplication and division of class objects. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __add__(self, other): return Rule(self.r_len + other.r_len)</pre><div class="contentsignin">Copy after login</div></div><p>The <code>__add__</code> method is defined here, corresponding to the <code> </code> operator. It will add the lengths of the two rulers and generate a new ruler. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">rule1 = Rule(10) rule2 = Rule(5) rule3 = rule1 + rule2</pre><div class="contentsignin">Copy after login</div></div><p>The following is the double-under method of arithmetic operators</p><p style="text-align:center"><img alt="" src="https://img.php.cn/upload/article/000/000/067/dc4eae5d11b7bd06ec193c866274280b-2.png"/></p><h3>2.3 Reverse arithmetic operator</h3><p>It supports other types of variables with <code>Rule</code>Class addition. Taking the <code>__radd__</code> method as an example </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __radd__(self, other): return self.r_len + other</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">rule1 = Rule(10) rule2 = 10 + rule1</pre><div class="contentsignin">Copy after login</div></div><p>When the program executes <code>10 rule1</code>, it will try to call the <code>__add__</code> of the <code>int</code> class but The <code>int</code> class class does not define a method for adding the <code>Rule</code> class object, so the program will call the <code> of the object </code>rule1<code> on the right of </code> <code> __radd__</code> method, and pass <code>10</code> to the <code>other</code> parameter. </p><p>So this operator is also called the right addition operator. The operators it supports are the same as the arithmetic operators above. Just add <code>r</code> before the method name. </p><h3>2.4 Incremental assignment operator</h3><p>The incremental assignment operators are <code> =</code>, <code>-=</code>, <code>*=</code>, <code>/=</code>etc. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __iadd__(self, other): self.r_len += other return self</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">rule1 = Rule(10) rule1 += 5</pre><div class="contentsignin">Copy after login</div></div><p>Except for the <code>__pmod__</code> method, everything else is the same as the arithmetic operators, with i added before the aspect name. </p><h3>2.4 Bit Operators</h3><p>This part supports binary operations such as negation, shift, AND or NOT. Since the <code>Rule</code> class does not involve bit operations, let's change to another example. </p><p>The class that defines binary string <code>BinStr</code>, contains the <code>bin_str</code> attribute, which represents a binary string. </p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class BinStr: def __init__(self, bin_str): self.bin_str = bin_str</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1010&#39;) #创建二进制字符串对象 print(x.bin_str) # 1010</pre><div class="contentsignin">Copy after login</div></div><p>Define a negation operator for <code>BinStr</code><code>~</code></p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;"># ~ 运算符 def __invert__(self): inverted_bin_str = &#39;&#39;.join([&#39;1&#39; if i == &#39;0&#39; else &#39;0&#39; for i in self.bin_str]) return BinStr(inverted_bin_str)</pre><div class="contentsignin">Copy after login</div></div><p><code>__invert__</code>方法中,遍历<code>bin_str</code>字符串,将每位取反,并返回一个新的<code>BinStr</code>类对象。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) invert_x = ~x print(invert_x.bin_str) # 0100</pre><div class="contentsignin">Copy after login</div></div><p>下面是位运算符的双下方法</p><p style="text-align:center"><img alt="" src="https://img.php.cn/upload/article/000/000/067/4894e53be3e9850194264d258e8620e0-3.png"/></p><p>这部分也支持反向位运算符和增量赋值位运算符,规则跟算数运算符一样,这里就不再赘述。</p><h2>3.字符串表示</h2><p>这部分涉及两个双下方法<code>__repr__</code>和<code>__format__</code>,在某些特殊场景,如<code>print</code>,会自动调用,将对象转成字符串。</p><p>还是以<code>BinStr</code>为例,先写<code>__repr__</code>方法。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __repr__(self): decimal = int(&#39;0b&#39;+self.bin_str, 2) return f&#39;二进制字符串:{self.bin_str},对应的十进制数字:{decimal}&#39;</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) print(x) # 输出:二进制字符串:1011,对应的十进制数字:11</pre><div class="contentsignin">Copy after login</div></div><p>当程序执行<code>print(x)</code>时,会自动调用<code>__repr__</code>方法,获取对象<code>x</code>对应的字符串。</p><p>再写<code>__format__</code>方法,它也是将对象格式化为字符串。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __format__(self, format_spec): return format_spec % self.bin_str</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">print(&#39;{0:二进制字符串:%s}&#39;.format(x)) # 输出:二进制字符串:1011</pre><div class="contentsignin">Copy after login</div></div><p>当<code>.format</code>方法的前面字符串里包含<code>0:</code>时,就会自动调用<code>__format__</code>方法,并将字符串传给<code>format_spec</code>参数。</p><h2>4.数值转换</h2><p>调用<code>int(obj)</code>、<code>float(obj)</code>等方法,可以将对象转成相对应数据类型的数据。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __int__(self): return int(&#39;0b&#39;+self.bin_str, 2)</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) print(int(x))</pre><div class="contentsignin">Copy after login</div></div><p>当调用<code>int(x)</code>时,会自动调用<code>__int__</code>方法,将二进制字符串转成十进制数字。</p><p>数值转换除了上面的两个外,还有<code>__abs__</code>、<code>__bool__</code>、<code>__complex__</code>、<code>__hash__</code>、<code>__index__</code>和<code>__str__</code>。</p><p><code>__str__</code>和<code>__repr__</code>一样,在<code>print</code>时都会被自动调用,但<code>__str__</code>优先级更高。</p><h2>5.集合相关的双下方法</h2><p>这部分可以像集合那样,定义对象长度、获取某个位置元素、切片等方法。</p><p>以<code>__len__</code>和<code>__getitem__</code>为例</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __len__(self): return len(self.bin_str) def __getitem__(self, item): return self.bin_str[item]</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) print(len(x)) # 4 print(x[0]) # 1 print(x[0:3]) # 101</pre><div class="contentsignin">Copy after login</div></div><p><code>len(x)</code>会自动调用<code>__len__</code>返回对象的长度。</p><p>通过<code>[]</code>方式获取对象的元素时,会自动调用<code>__getitem__</code>方法,并将切片对象传给<code>item</code>参数,即可以获取单个元素,还可以获取切片。</p><p>集合相关的双下方法还包括<code>__setitem__</code>、<code>__delitem__</code>和<code>__contains__</code>。</p><h2>6.迭代相关的双下方法</h2><p>可以在对象上使用<code>for-in</code>遍历。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __iter__(self): self.cur_i = -1 return self def __next__(self): self.cur_i += 1 if self.cur_i >= len(self.bin_str): raise StopIteration() # 退出迭代 return self.bin_str[self.cur_i]</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) for i in x: print(i)</pre><div class="contentsignin">Copy after login</div></div><p>当在<code>x</code>上使用<code>for-in</code>循环时,会先调用<code>__iter__</code>方法将游标<code>cur_i</code>置为初始值<code>-1</code>,然后不断调用<code>__next__</code>方法遍历<code>self.bin_str</code>中的每一位。</p><p>这部分还有一个<code>__reversed__</code>方法用来反转对象。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">def __reversed__(self): return BinStr(&#39;&#39;.join(list(reversed(self.bin_str))))</pre><div class="contentsignin">Copy after login</div></div><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">x = BinStr(&#39;1011&#39;) reversed_x = reversed(x) print(reversed_x) # 输出:二进制字符串:1101,对应的十进制数字:13</pre><div class="contentsignin">Copy after login</div></div><h2>7.类相关的双下方法</h2><p>做 web 开发的朋友,用类相关的双下方法会更多一些。</p><h3>7.1 实例的创建和销毁</h3><p>实例的创建是<code>__new__</code>和<code>__init__</code>方法,实例的销毁是<code>__del__</code>方法。</p><p><code>__new__</code>的调用早于<code>__init__</code>,它的作用是创建对象的实例(内存开辟一段空间),而后才将该实例传给<code>__init__</code>方法,完成实例的初始化。</p><p>由于<code>__new__</code>是类静态方法,因此它可以控制对象的创建,从而实现<strong>单例模式</strong>。</p><p><code>__del__</code>方法在实例销毁时,被自动调用,可以用来做一些清理工作和资源释放的工作。</p><h3>7.2 属性管理</h3><p>类属性的访问和设置。包括<code>__getattr__</code>、<code>__getattribute__</code>、<code>__setattr__</code>和<code>__delattr__</code>方法。</p><p><code>__getattr__</code>和<code>__getattribute__</code>的区别是,当访问类属性时,无论属性存不存在都会调用<code>__getattribute__</code>方法,只有当属性不存在时才会调用<code>__getattr__</code>方法。</p><h3>7.3 属性描述符</h3><p>控制属性的访问,一般用于把属性的取值控制在合理范围内。包括<code>__get__</code>、<code>__set__</code>和<code>__delete__</code>方法。</p><div class="code" style="position:relative; padding:0px; margin:0px;"><pre class="brush:py;">class XValidation: def __get__(self, instance, owner): return self.x def __set__(self, instance, value): if 0 <= value <= 100: self.x = value else: raise Exception(&#39;x不能小于0,不能大于100&#39;) def __delete__(self, instance): print(&#39;删除属性&#39;) class MyCls: x = XValidation() def __init__(self, n): self.x = n obj = MyCls(10) obj.x = 101 print(obj.x) # 抛异常:Exception: x不能小于0,不能大于100</pre><div class="contentsignin">Copy after login</div></div><p>上述例子,通过类属性描述符,可以将属性x的取值控制在<code>[0, 100]</code>之前,防止不合法的取值。</p> <h2>8.总结</h2> <p>虽然上面介绍的不是所有的双下方法,但也算是绝大多数了。</p> <p>虽然双下方法里可以编写任意代码,但大家尽量编写与方法要求一样的代码。如,在<code>__add__</code>方法实现的不是对象相加而是相减,虽然也能运行,但这样会造成很大困惑,不利于代码维护。</p> <p>【相关推荐:<a href="//m.sbmmt.com/course/list/31.html" target="_blank">Python3视频教程</a> 】</p>

The above is the detailed content of Completely master the double-down method in Python. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:jb51.net
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template