>  기사  >  백엔드 개발  >  Python의 매직 메소드 자세히 살펴보기

Python의 매직 메소드 자세히 살펴보기

高洛峰
高洛峰원래의
2017-03-24 16:07:261403검색
<h2>머리말</h2> <p>파이썬에서는 "__" 이중 밑줄로 묶인 모든 메소드를 통칭하여 "매직 메소드"라고 합니다. 예를 들어 우리는 </p> <pre class="brush:php;toolbar:false">__init__</pre> <p>와 가장 많이 접촉합니다.<br>살면서 다시는 만날 수 없는 마법의 방법이 있으므로 간단히 소개하겠습니다. <br>그리고 몇 가지 마법의 방법도 있습니다. , 능숙하게 사용하세요. 복잡한 논리를 간단한 API로 캡슐화하는 등 매우 아름다운 코드를 구성할 수 있습니다. <br>이 기사의 편집 아이디어는 Rafe Kettler의 블로그: Python Magic Methods 가이드에서 차용했으며 일부 코드 예제가 추가되었습니다. <br>소개 순서는 대략적으로 일반적인 것이 먼저 소개되고, 희귀한 것이 나중에 소개됩니다. <br>이 기사에 사용된 코드 예제는 내 github에서 다운로드할 수 있습니다. </p> <h2>생성 및 초기화</h2>rree<p>우리는 객체가 초기화될 때 호출되는 것을 일반적으로 <br>실제로는 "생성자"라고 이해합니다. call </p> <pre class="brush:php;toolbar:false">__init__</pre> <p>가 호출되면 </p> <pre class="brush:php;toolbar:false">x = SomeClass()</pre> <p>가 가장 먼저 실행되지 않지만 </p> <pre class="brush:php;toolbar:false">__init__</pre> <p>가 실행됩니다. 정확하게 말하면 </p> <pre class="brush:php;toolbar:false">__new__</pre> <p>와 </p> <pre class="brush:php;toolbar:false">__new__</pre> <p>는 함께 "생성자"를 구성하며 </p> <pre class="brush:php;toolbar:false">__init__</pre> <p>는 클래스를 만들고 이 클래스의 인스턴스를 반환하는 데 사용됩니다. 🎜></p> <pre class="brush:php;toolbar:false">__new__</pre>는 전달된 매개변수로 인스턴스를 초기화합니다. <p></p> <pre class="brush:php;toolbar:false">__init__</pre>는 인스턴스 생성 과정에서 반드시 호출되지만 <p></p> <pre class="brush:php;toolbar:false">__new__</pre>는 반드시 호출되는 것은 아닙니다. <p></p> <pre class="brush:php;toolbar:false">__init__</pre>를 사용하여 인스턴스를 역직렬화하면 <p></p> <pre class="brush:php;toolbar:false">pickle.load</pre>가 호출되지 않습니다. <p></p> <pre class="brush:php;toolbar:false">__init__</pre> 메서드는 항상 클래스의 인스턴스를 반환해야 하지만 <p></p> <pre class="brush:php;toolbar:false">__new__</pre>는 None을 제외한 어떤 값도 반환할 수 없습니다. 예를 들어 다음 예는 다음과 같습니다. <p>class Foo(object):<br> def __init__(self):<br> print 'foo __init__'<br> return None # 반드시 None을 반환해야 합니다. 그렇지 않으면 TypeError<br>가 발생합니다. be throw def __del__(self ):<br> print 'foo __del__'<br>실제로 클래스 생성을 제어하려는 경우가 아니면 <br></p> <pre class="brush:php;toolbar:false">__init__</pre>를 거의 사용하지 않습니다. <p><br></p> <pre class="brush:php;toolbar:false">__new__</pre>를 설명하려면 <p></p> <pre class="brush:php;toolbar:false">__new__</pre>(메타클래스)를 소개하는 경우가 많습니다. <p>더 깊이 알고 싶다면 내 다른 블로그인 Python의 메타클래스 이해<br><br></p> <pre class="brush:php;toolbar:false">metaclass</pre>의 오버로딩도 Python 문서에 자세히 소개되어 있습니다. <p>객체 수명 주기가 끝나면 <br></p> <pre class="brush:php;toolbar:false">__new__</pre>가 호출됩니다. <p></p> <pre class="brush:php;toolbar:false">__del__</pre>는 "생성자"로 이해될 수 있습니다. 가비지 수집될 때 개체의 개체입니다. <p>는 좀 오해하기 쉽습니다. 사실 </p> <pre class="brush:php;toolbar:false">__del__</pre> <p>는 <br></p> <pre class="brush:php;toolbar:false">__del__</pre>의 구현이 아니지만 <p></p> <pre class="brush:php;toolbar:false">x.__del__()</pre>가 실행될 때 <p></p> <pre class="brush:php;toolbar:false">del x</pre>가 호출되는 경우가 많습니다. . .<p>이 문장을 어떻게 이해할까요? 위의 Foo 클래스 코드를 예시로 사용해 보세요. </p>foo = Foo()<p>foo.__del__()<br>print foo<br> del foo<br>print foo # NameError, foo가 정의되지 않았습니다<br><br></p> <pre class="brush:php;toolbar:false">del x</pre> <br>가 호출되면 객체 자체는 여전히 존재합니다. 그러나 <br><pre class="brush:php;toolbar:false">x.__del__()</pre>가 호출되면 객체는 그대로 존재합니다. 더 이상 foo 객체가 아닙니다. <p> 인터프리터가 종료될 때 객체가 여전히 존재하는 경우 </p> <pre class="brush:php;toolbar:false">foo.__del__()</pre> <p>가 정확하게 실행된다는 보장은 없습니다. 따라서 <br></p> <pre class="brush:php;toolbar:false">del foo</pre>는 좋은 프로그래밍 습관을 대체할 수 없습니다. <p>예를 들어 소켓을 처리할 때 적시에 완료된 연결을 닫습니다. </p> <p>속성 액세스 제어<br></p>Python의 클래스 캡슐화가 부족하다고 불평하는 사람들이 항상 있습니다. 예를 들어 Python이 비공개 속성을 정의한 다음 공개적으로 액세스 가능한 getter 및 setter를 제공할 수 있기를 바랍니다. Python은 실제로 매직 메소드를 통해 캡슐화를 달성할 수 있습니다. <h2></h2> <pre class="brush:php;toolbar:false">__del__</pre> <p></p>이 메소드는 존재하지 않는 속성에 액세스하려고 할 때의 동작을 정의합니다. 따라서 이 메서드를 오버로드하면 맞춤법 오류를 찾아 리디렉션하거나 더 이상 사용되지 않는 일부 속성에 대해 경고할 수 있습니다. <h3></h3> <pre class="brush:php;toolbar:false">__del__</pre> <p></p> <pre class="brush:php;toolbar:false">__getattr__(self, name)</pre>는 속성을 할당하고 수정할 때의 동작을 정의하는 캡슐화 솔루션입니다. <h3>객체의 특정 속성이 존재하는지 여부에 관계없이 속성에 값을 할당할 수 있으므로 속성 값에 대해 사용자 정의 작업을 수행할 수 있습니다. 한 가지 주의할 점은 </h3> <pre class="brush:php;toolbar:false">__setattr__(self, name, value)</pre> <p>를 구현할 때 "무한 재귀" 오류를 피하는 것입니다. 이에 대해서는 아래 코드 예제에서 언급하겠습니다. <br></p> <pre class="brush:php;toolbar:false">__setattr__</pre> <p></p> <pre class="brush:php;toolbar:false">__setattr__</pre>는 속성을 삭제할 때의 동작을 정의한다는 점을 제외하면 <h3><pre class="brush:php;toolbar:false">__delattr__(self, name)</pre></h3>와 매우 유사합니다. <p></p> <pre class="brush:php;toolbar:false">__delattr__</pre>를 구현하는 것은 "무한 재귀" 오류를 방지하는 것입니다. <p></p> <pre class="brush:php;toolbar:false">__setattr__</pre> <p></p> <pre class="brush:php;toolbar:false">__delattr__</pre>는 속성에 액세스할 때의 동작을 정의합니다. 반면 <h3><pre class="brush:php;toolbar:false">__getattribute__(self, name)</pre></h3>는 속성이 존재하지 않는 경우에만 작동합니다. <p>따라서 </p> <pre class="brush:php;toolbar:false">__getattribute__</pre> <p>를 지원하는 Python 버전에서는 <br></p> <pre class="brush:php;toolbar:false">__getattr__</pre>를 호출하기 전에 <p></p> <pre class="brush:php;toolbar:false">__getattribute__</pre>를 사용해야 합니다. <p></p> <pre class="brush:php;toolbar:false">__getattr__</pre>'무한 재귀' 오류도 방지하세요. <p></p> <pre class="brush:php;toolbar:false">__getattribute__</pre> <p>를 구현하지 않는 것이 가장 좋다는 점을 기억해야 합니다. 이 접근 방식은 거의 눈에 띄지 않고 버그가 발생하기 쉽기 때문입니다. <br></p> <pre class="brush:php;toolbar:false">__getattribute__</pre> <p>:<br>def __setattr__(self, name, value):</p> self.name = value<p> # 속성이 할당될 때마다, __setattr__이 호출되므로 계속 호출하면 무한 재귀가 발생합니다. <br>따라서 올바른 작성 방법은 다음과 같습니다.<br>def __setattr__(self, name, value):<br> self.__dict__[name] = value<br></p> <pre class="brush:php;toolbar:false">__getattribute__</pre> <br><br>가 다음에 나타나는 경우 구현<pre class="brush:php;toolbar:false">del self.name</pre> <p> 这样的代码也会出现”无限递归”错误,这是一样的原因。<br>下面的例子很好的说明了上面介绍的4个魔术方法的调用情况:<br>class Access(object):<br>    def __getattr__(self, name):<br>        print '__getattr__'<br>        return super(Access, self).__getattr__(name)<br>    def __setattr__(self, name, value):<br>        print '__setattr__'<br>        return super(Access, self).__setattr__(name, value)<br>    def __delattr__(self, name):<br>        print '__delattr__'<br>        return super(Access, self).__delattr__(name)<br>    def __getattribute__(self, name):<br>        print '__getattribute__'<br>        return super(Access, self).__getattribute__(name)<br>access = Access()<br>access.attr1 = True  # __setattr__调用<br>access.attr1  # 属性存在,只有__getattribute__调用<br>try:<br>    access.attr2  # 属性不存在, 先调用__getattribute__, 后调用__getattr__<br>except AttributeError:<br>    pass<br>del access.attr1  # __delattr__调用</p> <h2>描述器对象</h2> <p>我们从一个例子来入手,介绍什么是描述符,并介绍</p> <pre class="brush:php;toolbar:false">__get__</pre> <p>, </p> <pre class="brush:php;toolbar:false">__set__</pre> <p>, </p> <pre class="brush:php;toolbar:false">__delete__</pre> <p> 的使用。(放在这里介绍是为了跟上一小节介绍的魔术方法作对比)<br>我们知道,距离既可以用单位”米”表示,也可以用单位”英尺”表示。现在我们定义一个类来表示距离,它有两个属性: 米和英尺。<br>class Meter(object):<br>    '''Descriptor for a meter.'''<br>    def __init__(self, value=0.0):<br>        self.value = float(value)<br>    def __get__(self, instance, owner):<br>        return self.value<br>    def __set__(self, instance, value):<br>        self.value = float(value)<br>class Foot(object):<br>    '''Descriptor for a foot.'''<br>    def __get__(self, instance, owner):<br>        return instance.meter * 3.2808<br>    def __set__(self, instance, value):<br>        instance.meter = float(value) / 3.2808<br>class Distance(object):<br>    meter = Meter()<br>    foot = Foot()<br>d = Distance()<br>print d.meter, d.foot  # 0.0, 0.0<br>d.meter = 1<br>print d.meter, d.foot  # 1.0 3.2808<br>d.meter = 2<br>print d.meter, d.foot  # 2.0 6.5616<br>在上面例子中,在还没有对Distance的实例赋值前, 我们认为meter和foot应该是各自类的实例对象, 但是输出却是数值。这是因为</p> <pre class="brush:php;toolbar:false">__get__</pre> <p>发挥了作用.<br>我们只是修改了meter,并且将其赋值成为int,但foot也修改了。这是</p> <pre class="brush:php;toolbar:false">__set__</pre> <p>发挥了作用.<br>描述器对象(Meter、Foot)不能独立存在, 它需要被另一个所有者类(Distance)所持有。<br>描述器对象可以访问到其拥有者实例的属性,比如例子中Foot的</p> <pre class="brush:php;toolbar:false">instance.meter</pre> <p>。<br>在面向对象编程时,如果一个类的属性有相互依赖的关系时,使用描述器来编写代码可以很巧妙的组织逻辑。在Django的ORM中, models.Model中的InterField等字段, 就是通过描述器来实现功能的。<br>一个类要成为描述器,必须实现</p> <pre class="brush:php;toolbar:false">__get__</pre> <p>, </p> <pre class="brush:php;toolbar:false">__set__</pre> <p>, </p> <pre class="brush:php;toolbar:false">__delete__</pre> <p> 中的至少一个方法。下面简单介绍下:</p> <h3><pre class="brush:php;toolbar:false">__get__(self, instance, owner)</pre></h3> <p>参数instance是拥有者类的实例。参数owner是拥有者类本身。</p> <pre class="brush:php;toolbar:false">__get__</pre> <p>在其拥有者对其读值的时候调用。</p> <h3><pre class="brush:php;toolbar:false">__set__(self, instance, value)</pre></h3> <pre class="brush:php;toolbar:false">__set__</pre> <p>在其拥有者对其进行修改值的时候调用。</p> <h3><pre class="brush:php;toolbar:false">__delete__(self, instance)</pre></h3> <pre class="brush:php;toolbar:false">__delete__</pre> <p>在其拥有者对其进行删除的时候调用。</p> <h2>构造自定义容器(Container)</h2> <p>在Python中,常见的容器类型有: dict, tuple, list, string。<br>其中tuple, string是不可变容器,dict, list是可变容器。<br>可变容器和不可变容器的区别在于,不可变容器一旦赋值后,不可对其中的某个元素进行修改。<br>比如定义了</p> <pre class="brush:php;toolbar:false">l = [1, 2, 3]</pre> <p>和</p> <pre class="brush:php;toolbar:false">t = (1, 2, 3)</pre> <p>后, 执行</p> <pre class="brush:php;toolbar:false">l[0] = 0</pre> <p>是可以的,但执行</p> <pre class="brush:php;toolbar:false">t[0] = 0</pre> <p>则会报错。<br>如果我们要自定义一些数据结构,使之能够跟以上的容器类型表现一样,那就需要去实现某些协议。<br>这里的协议跟其他语言中所谓的”接口”概念很像,一样的需要你去实现才行,只不过没那么正式而已。<br>如果要自定义不可变容器类型,只需要定义</p> <pre class="brush:php;toolbar:false">__len__</pre> <p> 和 </p> <pre class="brush:php;toolbar:false">__getitem__</pre> <p>方法;<br>如果要自定义可变容器类型,还需要在不可变容器类型的基础上增加定义</p> <pre class="brush:php;toolbar:false">__setitem__</pre> <p> 和 </p> <pre class="brush:php;toolbar:false">__delitem__</pre> <p>。<br>如果你希望你的自定义数据结构还支持”可迭代”, 那就还需要定义</p> <pre class="brush:php;toolbar:false">__iter__</pre> <p>。</p> <h3><pre class="brush:php;toolbar:false">__len__(self)</pre></h3> <p>需要返回数值类型,以表示容器的长度。该方法在可变容器和不可变容器中必须实现。</p> <h3><pre class="brush:php;toolbar:false">__getitem__(self, key)</pre></h3> <p>当你执行</p> <pre class="brush:php;toolbar:false">self[key]</pre> <p>的时候,调用的就是该方法。该方法在可变容器和不可变容器中也都必须实现。<br>调用的时候,如果key的类型错误,该方法应该抛出TypeError;<br>如果没法返回key对应的数值时,该方法应该抛出ValueError。</p> <h3><pre class="brush:php;toolbar:false">__setitem__(self, key, value)</pre></h3> <p>当你执行</p> <pre class="brush:php;toolbar:false">self[key] = value</pre> <p>时,调用的是该方法。</p> <h3><pre class="brush:php;toolbar:false">__delitem__(self, key)</pre></h3> <p>当你执行</p> <pre class="brush:php;toolbar:false">del self[key]</pre> <p>的时候,调用的是该方法。</p> <h3><pre class="brush:php;toolbar:false">__iter__(self)</pre></h3> <p>该方法需要返回一个迭代器(iterator)。当你执行</p> <pre class="brush:php;toolbar:false">for x in container:</pre> <p> 或者使用</p> <pre class="brush:php;toolbar:false">iter(container)</pre> <p>时,该方法被调用。</p> <h3><pre class="brush:php;toolbar:false">__reversed__(self)</pre></h3> <p>如果想要该数据结构被內建函数</p> <pre class="brush:php;toolbar:false">reversed()</pre> <p>支持,就还需要实现该方法。</p> <h3><pre class="brush:php;toolbar:false">__contains__(self, item)</pre></h3> <p>如果定义了该方法,那么在执行</p> <pre class="brush:php;toolbar:false">item in container</pre> <p> 或者 </p> <pre class="brush:php;toolbar:false">item not in container</pre> <p>时该方法就会被调用。<br>如果没有定义,那么Python会迭代容器中的元素来一个一个比较,从而决定返回True或者False。</p> <h3><pre class="brush:php;toolbar:false">__missing__(self, key)</pre></h3> <pre class="brush:php;toolbar:false">dict</pre> <p>字典类型会有该方法,它定义了key如果在容器中找不到时触发的行为。<br>比如</p> <pre class="brush:php;toolbar:false">d = {'a': 1}</pre> <p>, 当你执行</p> <pre class="brush:php;toolbar:false">d[notexist]</pre> <p>时,</p> <pre class="brush:php;toolbar:false">d.__missing__['notexist']</pre> <p>就会被调用。<br>下面举例,使用上面讲的魔术方法来实现Haskell语言中的一个数据结构。<br># -*- coding: utf-8 -*-<br>class FunctionalList:<br>    ''' 实现了内置类型list的功能,并丰富了一些其他方法: head, tail, init, last, drop, take'''<br>    def __init__(self, values=None):<br>        if values is None:<br>            self.values = []<br>        else:<br>            self.values = values<br>    def __len__(self):<br>        return len(self.values)<br>    def __getitem__(self, key):<br>        return self.values[key]<br>    def __setitem__(self, key, value):<br>        self.values[key] = value<br>    def __delitem__(self, key):<br>        del self.values[key]<br>    def __iter__(self):<br>        return iter(self.values)<br>    def __reversed__(self):<br>        return FunctionalList(reversed(self.values))<br>    def append(self, value):<br>        self.values.append(value)<br>    def head(self):<br>        # 获取第一个元素<br>        return self.values[0]<br>    def tail(self):<br>        # 获取第一个元素之后的所有元素<br>        return self.values[1:]<br>    def init(self):<br>        # 获取最后一个元素之前的所有元素<br>        return self.values[:-1]<br>    def last(self):<br>        # 获取最后一个元素<br>        return self.values[-1]<br>    def drop(self, n):<br>        # 获取所有元素,除了前N个<br>        return self.values[n:]<br>    def take(self, n):<br>        # 获取前N个元素<br>        return self.values[:n]<br>我们再举个例子,实现Perl语言的autovivification,它会在你每次引用一个值未定义的属性时为你自动创建数组或者字典。<br>class AutoVivification(dict):<br>    """Implementation of perl's autovivification feature."""<br>    def __missing__(self, key):<br>        value = self[key] = type(self)()<br>        return value<br>weather = AutoVivification()<br>weather['china']['guangdong']['shenzhen'] = 'sunny'<br>weather['china']['hubei']['wuhan'] = 'windy'<br>weather['USA']['California']['Los Angeles'] = 'sunny'<br>print weather<br>结果输出:{'china': {'hubei': {'wuhan': 'windy'}, 'guangdong': {'shenzhen': 'sunny'}}, 'USA':    {'California': {'Los Angeles': 'sunny'}}}<br>在Python中,关于自定义容器的实现还有更多实用的例子,但只有很少一部分能够集成在Python标准库中,比如Counter, OrderedDict等</p> <h2>上下文管理</h2> <pre class="brush:php;toolbar:false">with</pre> <p>声明是从Python2.5开始引进的关键词。你应该遇过这样子的代码:<br>with open('foo.txt') as bar:<br>    # do something with bar<br>在with声明的代码段中,我们可以做一些对象的开始操作和清除操作,还能对异常进行处理。<br>这需要实现两个魔术方法: </p> <pre class="brush:php;toolbar:false">__enter__</pre> <p> 和 </p> <pre class="brush:php;toolbar:false">__exit__</pre> <p>。</p> <h3><pre class="brush:php;toolbar:false">__enter__(self)</pre></h3> <pre class="brush:php;toolbar:false">__enter__</pre> <p>会返回一个值,并赋值给</p> <pre class="brush:php;toolbar:false">as</pre> <p>关键词之后的变量。在这里,你可以定义代码段开始的一些操作。</p> <h3><pre class="brush:php;toolbar:false">__exit__(self, exception_type, exception_value, traceback)</pre></h3> <pre class="brush:php;toolbar:false">__exit__</pre> <p>定义了代码段结束后的一些操作,可以这里执行一些清除操作,或者做一些代码段结束后需要立即执行的命令,比如文件的关闭,socket断开等。如果代码段成功结束,那么exception_type, exception_value, traceback 三个参数传进来时都将为None。如果代码段抛出异常,那么传进来的三个参数将分别为: 异常的类型,异常的值,异常的追踪栈。<br>如果</p> <pre class="brush:php;toolbar:false">__exit__</pre> <p>返回True, 那么with声明下的代码段的一切异常将会被屏蔽。<br>如果</p> <pre class="brush:php;toolbar:false">__exit__</pre> <p>返回None, 那么如果有异常,异常将正常抛出,这时候with的作用将不会显现出来。<br>举例说明:<br>这该示例中,IndexError始终会被隐藏,而TypeError始终会抛出。<br>class DemoManager(object):<br>    def __enter__(self):<br>        pass<br>    def __exit__(self, ex_type, ex_value, ex_tb):<br>        if ex_type is IndexError:<br>            print ex_value.__class__<br>            return True<br>        if ex_type is TypeError:<br>            print ex_value.__class__<br>            return  # return None<br>with DemoManager() as nothing:<br>    data = [1, 2, 3]<br>    data[4]  # raise IndexError, 该异常被__exit__处理了<br>with DemoManager() as nothing:<br>    data = [1, 2, 3]<br>    data['a']  # raise TypeError, 该异常没有被__exit__处理<br>输出:<br><type 'exceptions.IndexError'><br><type 'exceptions.TypeError'><br>Traceback (most recent call last):<br>  ...</p> <h2>对象的序列化</h2> <p>Python对象的序列化操作是pickling进行的。pickling非常的重要,以至于Python对此有单独的模块</p> <pre class="brush:php;toolbar:false">pickle</pre> <p>,还有一些相关的魔术方法。使用pickling, 你可以将数据存储在文件中,之后又从文件中进行恢复。<br>下面举例来描述pickle的操作。从该例子中也可以看出,如果通过pickle.load 初始化一个对象, 并不会调用</p> <pre class="brush:php;toolbar:false">__init__</pre> <p>方法。<br># -*- coding: utf-8 -*-<br>from datetime import datetime<br>import pickle<br>class Distance(object):<br>    def __init__(self, meter):<br>        print 'distance __init__'<br>        self.meter = meter<br>data = {<br>    'foo': [1, 2, 3],<br>    'bar': ('Hello', 'world!'),<br>    'baz': True,<br>    'dt': datetime(2016, 10, 01),<br>    'distance': Distance(1.78),<br>}<br>print 'before dump:', data<br>with open('data.pkl', 'wb') as jar:<br>    pickle.dump(data, jar)  # 将数据存储在文件中<br>del data<br>print 'data is deleted!'<br>with open('data.pkl', 'rb') as jar:<br>    data = pickle.load(jar)  # 从文件中恢复数据<br>print 'after load:', data<br>值得一提,从其他文件进行pickle.load操作时,需要注意有恶意代码的可能性。另外,Python的各个版本之间,pickle文件可能是互不兼容的。<br>pickling并不是Python的內建类型,它支持所有实现pickle协议(可理解为接口)的类。pickle协议有以下几个可选方法来自定义Python对象的行为。</p> <h3><pre class="brush:php;toolbar:false">__getinitargs__(self)</pre></h3> <p>如果你希望unpickle时,</p> <pre class="brush:php;toolbar:false">__init__</pre> <p>方法能够调用,那么就需要定义</p> <pre class="brush:php;toolbar:false">__getinitargs__</pre> <p>, 该方法需要返回一系列参数的元组,这些参数就是传给</p> <pre class="brush:php;toolbar:false">__init__</pre> <p>的参数。<br>该方法只对</p> <pre class="brush:php;toolbar:false">old-style class</pre> <p>有效。所谓</p> <pre class="brush:php;toolbar:false">old-style class</pre> <p>,指的是不继承自任何对象的类,往往定义时这样表示: </p> <pre class="brush:php;toolbar:false">class A:</pre> <p>, 而非</p> <pre class="brush:php;toolbar:false">class A(object):</pre> <h3><pre class="brush:php;toolbar:false">__getnewargs__(self)</pre></h3> <p>跟</p> <pre class="brush:php;toolbar:false">__getinitargs__</pre> <p>很类似,只不过返回的参数元组将传值给</p> <pre class="brush:php;toolbar:false">__new__</pre> <h3><pre class="brush:php;toolbar:false">__getstate__(self)</pre></h3> <p>在调用</p> <pre class="brush:php;toolbar:false">pickle.dump</pre> <p>时,默认是对象的</p> <pre class="brush:php;toolbar:false">__dict__</pre> <p>属性被存储,如果你要修改这种行为,可以在</p> <pre class="brush:php;toolbar:false">__getstate__</pre> <p>方法中返回一个state。state将在调用</p> <pre class="brush:php;toolbar:false">pickle.load</pre> <p>时传值给</p> <pre class="brush:php;toolbar:false">__setstate__</pre> <h3><pre class="brush:php;toolbar:false">__setstate__(self, state)</pre></h3> <p>一般来说,定义了</p> <pre class="brush:php;toolbar:false">__getstate__</pre> <p>,就需要相应地定义</p> <pre class="brush:php;toolbar:false">__setstate__</pre> <p>来对</p> <pre class="brush:php;toolbar:false">__getstate__</pre> <p>返回的state进行处理。</p> <h3><pre class="brush:php;toolbar:false">__reduce__(self)</pre></h3> <p>如果pickle的数据包含了自定义的扩展类(比如使用C语言实现的Python扩展类)时,就需要通过实现</p> <pre class="brush:php;toolbar:false">__reduce__</pre> <p>方法来控制行为了。由于使用过于生僻,这里就不展开继续讲解了。<br>令人容易混淆的是,我们知道, </p> <pre class="brush:php;toolbar:false">reduce()</pre> <p>是Python的一个內建函数, 需要指出</p> <pre class="brush:php;toolbar:false">__reduce__</pre> <p>并非定义了</p> <pre class="brush:php;toolbar:false">reduce()</pre> <p>的行为,二者没有关系。</p> <h3><pre class="brush:php;toolbar:false">__reduce_ex__(self)</pre></h3> <pre class="brush:php;toolbar:false">__reduce_ex__</pre> <p> 是为了兼容性而存在的, 如果定义了</p> <pre class="brush:php;toolbar:false">__reduce_ex__</pre> <p>, 它将代替</p> <pre class="brush:php;toolbar:false">__reduce__</pre> <p> 执行。<br>下面的代码示例很有意思,我们定义了一个类Slate(中文是板岩的意思)。这个类能够记录历史上每次写入给它的值,但每次</p> <pre class="brush:php;toolbar:false">pickle.dump</pre> <p>时当前值就会被清空,仅保留了历史。<br># -*- coding: utf-8 -*-<br>import pickle<br>import time<br>class Slate:<br>    '''Class to store a string and a changelog, and forget its value when pickled.'''<br>    def __init__(self, value):<br>        self.value = value<br>        self.last_change = time.time()<br>        self.history = []<br>    def change(self, new_value):<br>        # 修改value, 将上次的valeu记录在history<br>        self.history.append((self.last_change, self.value))<br>        self.value = new_value<br>        self.last_change = time.time()<br>    def print_changes(self):<br>        print 'Changelog for Slate object:'<br>        for k, v in self.history:<br>            print '%s    %s' % (k, v)<br>    def __getstate__(self):<br>        # 故意不返回self.value和self.last_change,<br>        # 以便每次unpickle时清空当前的状态,仅仅保留history<br>        return self.history<br>    def __setstate__(self, state):<br>        self.history = state<br>        self.value, self.last_change = None, None<br>slate = Slate(0)<br>time.sleep(0.5)<br>slate.change(100)<br>time.sleep(0.5)<br>slate.change(200)<br>slate.change(300)<br>slate.print_changes()  # 与下面的输出历史对比<br>with open('slate.pkl', 'wb') as jar:<br>    pickle.dump(slate, jar)<br>del slate  # delete it<br>with open('slate.pkl', 'rb') as jar:<br>    slate = pickle.load(jar)<br>print 'current value:', slate.value  # None<br>print slate.print_changes()  # 输出历史记录与上面一致</p> <h2>运算符相关的魔术方法</h2> <p>运算符相关的魔术方法实在太多了,也很好理解,不打算多讲。在其他语言里,也有重载运算符的操作,所以我们对这些魔术方法已经很了解了。</p> <h3>比较运算符</h3> <h3><pre class="brush:php;toolbar:false">__cmp__(self, other)</pre></h3> <p>如果该方法返回负数,说明</p> <pre class="brush:php;toolbar:false">self < other</pre><p>; 返回正数,说明</p><pre class="brush:php;toolbar:false">self > other</pre> <p>; 返回0说明</p> <pre class="brush:php;toolbar:false">self == other</pre> <p>。<br>强烈不推荐来定义</p> <pre class="brush:php;toolbar:false">__cmp__</pre> <p>, 取而代之, 最好分别定义</p> <pre class="brush:php;toolbar:false">__lt__</pre> <p>等方法从而实现比较功能。</p> <pre class="brush:php;toolbar:false">__cmp__</pre> <p>在Python3中被废弃了。</p> <h3><pre class="brush:php;toolbar:false">__eq__(self, other)</pre></h3> <p>定义了比较操作符</p> <pre class="brush:php;toolbar:false">==</pre> <p>的行为.</p> <h3><pre class="brush:php;toolbar:false">__ne__(self, other)</pre></h3> <p>定义了比较操作符</p> <pre class="brush:php;toolbar:false">!=</pre> <p>的行为.</p> <h3><pre class="brush:php;toolbar:false">__lt__(self, other)</pre></h3> <p>定义了比较操作符</p> <pre class="brush:php;toolbar:false"><</pre><p>的行为.</p><h3><pre class="brush:php;toolbar:false">__gt__(self, other)</pre></h3><p>定义了比较操作符</p><pre class="brush:php;toolbar:false">></pre> <p>的行为.</p> <h3><pre class="brush:php;toolbar:false">__le__(self, other)</pre></h3> <p>定义了比较操作符</p> <pre class="brush:php;toolbar:false"><=</pre><p>的行为.</p><h3><pre class="brush:php;toolbar:false">__ge__(self, other)</pre></h3><p>定义了比较操作符</p><pre class="brush:php;toolbar:false">>=</pre> <p>的行为.<br>下面我们定义一种类型Word, 它会使用单词的长度来进行大小的比较, 而不是采用str的比较方式。<br>但是为了避免 </p> <pre class="brush:php;toolbar:false">Word('bar') == Word('foo')</pre> <p> 这种违背直觉的情况出现,并没有定义</p> <pre class="brush:php;toolbar:false">__eq__</pre> <p>, 因此Word会使用它的父类(str)中的</p> <pre class="brush:php;toolbar:false">__eq__</pre> <p>来进行比较。<br>下面的例子中也可以看出: 在编程语言中, 如果</p> <pre class="brush:php;toolbar:false">a >=b and a <= b</pre><p>, 并不能推导出</p><pre class="brush:php;toolbar:false">a == b</pre><p>这样的结论。<br/># -*- coding: utf-8 -*-<br/>class Word(str):<br/> '''存储单词的类,定义比较单词的几种方法'''<br/> def __new__(cls, word):<br/> # 注意我们必须要用到__new__方法,因为str是不可变类型<br/> # 所以我们必须在创建的时候将它初始化<br/> if ' ' in word:<br/> print "Value contains spaces. Truncating to first space."<br/> word = word[:word.index(' ')] # 单词是第一个空格之前的所有字符<br/> return str.__new__(cls, word)<br/> def __gt__(self, other):<br/> return len(self) > len(other)<br>    def __lt__(self, other):<br>        return len(self) < len(other)<br/> def __ge__(self, other):<br/> return len(self) >= len(other)<br>    def __le__(self, other):<br>        return len(self) <= len(other)<br/>print 'foo < fool:', Word('foo') < Word('fool') # True<br/>print 'foolish > fool:', Word('foolish') > Word('fool')  # True<br>print 'bar >= foo:', Word('bar') >= Word('foo')  # True<br>print 'bar <= foo:', Word('bar') <= Word('foo') # True<br/>print 'bar == foo:', Word('bar') == Word('foo') # False, 用了str内置的比较方法来进行比较<br/>print 'bar != foo:', Word('bar') != Word('foo') # True</p><h3>一元运算符和函数</h3><h3><pre class="brush:php;toolbar:false">__pos__(self)</pre></h3><p>实现了’+'号一元运算符(比如</p><pre class="brush:php;toolbar:false">+some_object</pre><p>)</p><h3><pre class="brush:php;toolbar:false">__neg__(self)</pre></h3><p>实现了’-'号一元运算符(比如</p><pre class="brush:php;toolbar:false">-some_object</pre><p>)</p><h3><pre class="brush:php;toolbar:false">__invert__(self)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">~</pre><p>号一元运算符(比如</p><pre class="brush:php;toolbar:false">~some_object</pre><p>)</p><h3><pre class="brush:php;toolbar:false">__abs__(self)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">abs()</pre><p>內建函数.</p><h3><pre class="brush:php;toolbar:false">__round__(self, n)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">round()</pre><p>内建函数. 参数n表示四舍五进的精度.</p><h3><pre class="brush:php;toolbar:false">__floor__(self)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">math.round()</pre><p>, 向下取整.</p><h3><pre class="brush:php;toolbar:false">__ceil__(self)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">math.ceil()</pre><p>, 向上取整.</p><h3><pre class="brush:php;toolbar:false">__trunc__(self)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">math.trunc()</pre><p>, 向0取整.</p><h3>算术运算符</h3><h3><pre class="brush:php;toolbar:false">__add__(self, other)</pre></h3><p>实现了加号运算.</p><h3><pre class="brush:php;toolbar:false">__sub__(self, other)</pre></h3><p>实现了减号运算.</p><h3><pre class="brush:php;toolbar:false">__mul__(self, other)</pre></h3><p>实现了乘法运算.</p><h3><pre class="brush:php;toolbar:false">__floorp__(self, other)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">//</pre><p>运算符.</p><h3><pre class="brush:php;toolbar:false">__p__(self, other)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">/</pre><p>运算符. 该方法在Python3中废弃. 原因是Python3中,pision默认就是true pision.</p><h3><pre class="brush:php;toolbar:false">__truep__</pre>(self, other)</h3><p>实现了true pision. 只有你声明了</p><pre class="brush:php;toolbar:false">from __future__ import pision</pre><p>该方法才会生效.</p><h3><pre class="brush:php;toolbar:false">__mod__(self, other)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">%</pre><p>运算符, 取余运算.</p><h3><pre class="brush:php;toolbar:false">__pmod__(self, other)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">pmod()</pre><p>內建函数.</p><h3><pre class="brush:php;toolbar:false">__pow__(self, other)</pre></h3><p>实现了</p><pre class="brush:php;toolbar:false">**</pre><p>操作. N次方操作.</p><h3><pre class="brush:php;toolbar:false">__lshift__(self, other)</pre></h3><p>实现了位操作</p><pre class="brush:php;toolbar:false"><<</pre><p>.</p><h3><pre class="brush:php;toolbar:false">__rshift__(self, other)</pre></h3><p>实现了位操作</p><pre class="brush:php;toolbar:false">>></pre> <p>.</p> <h3><pre class="brush:php;toolbar:false">__and__(self, other)</pre></h3> <p>实现了位操作</p> <pre class="brush:php;toolbar:false">&</pre> <p>.</p> <h3><pre class="brush:php;toolbar:false">__or__(self, other)</pre></h3> <p>实现了位操作</p> <pre class="brush:php;toolbar:false">|</pre> <h3><pre class="brush:php;toolbar:false">__xor__(self, other)</pre></h3> <p>实现了位操作</p> <pre class="brush:php;toolbar:false">^</pre> <h3>反算术运算符</h3> <p>这里只需要解释一下概念即可。假设针对some_object这个对象:<br>some_object + other<br>上面的代码非常正常地实现了some_object的</p> <pre class="brush:php;toolbar:false">__add__</pre> <p>方法。那么如果遇到相反的情况呢?<br>other + some_object<br>这时候,如果other没有定义</p> <pre class="brush:php;toolbar:false">__add__</pre> <p>方法,但是some_object定义了</p> <pre class="brush:php;toolbar:false">__radd__</pre> <p>, 那么上面的代码照样可以运行。<br>这里的</p> <pre class="brush:php;toolbar:false">__radd__(self, other)</pre> <p>就是</p> <pre class="brush:php;toolbar:false">__add__(self, other)</pre> <p>的反算术运算符。<br>所以,类比的,我们就知道了更多的反算术运算符, 就不一一展开了:</p> <pre class="brush:php;toolbar:false">__rsub__(self, other)</pre> <pre class="brush:php;toolbar:false">__rmul__(self, other)</pre> <pre class="brush:php;toolbar:false">__rmul__(self, other)</pre> <pre class="brush:php;toolbar:false">__rfloorp__(self, other)</pre> <pre class="brush:php;toolbar:false">__rp__(self, other)</pre> <pre class="brush:php;toolbar:false">__rtruep__(self, other)</pre> <pre class="brush:php;toolbar:false">__rmod__(self, other)</pre> <pre class="brush:php;toolbar:false">__rpmod__(self, other)</pre> <pre class="brush:php;toolbar:false">__rpow__(self, other)</pre> <pre class="brush:php;toolbar:false">__rlshift__(self, other)</pre> <pre class="brush:php;toolbar:false">__rrshift__(self, other)</pre> <pre class="brush:php;toolbar:false">__rand__(self, other)</pre> <pre class="brush:php;toolbar:false">__ror__(self, other)</pre> <pre class="brush:php;toolbar:false">__rxor__(self, other)</pre> <h3>增量赋值</h3> <p>这也是只要理解了概念就容易掌握的运算。举个例子:<br>x = 5<br>x += 1  # 这里的+=就是增量赋值,将x+1赋值给了x<br>因此对于</p> <pre class="brush:php;toolbar:false">a += b</pre> <p>, </p> <pre class="brush:php;toolbar:false">__iadd__</pre> <p> 将返回</p> <pre class="brush:php;toolbar:false">a + b</pre> <p>, 并赋值给a。<br>所以很容易理解下面的魔术方法了:</p> <pre class="brush:php;toolbar:false">__iadd__(self, other)</pre> <pre class="brush:php;toolbar:false">__isub__(self, other)</pre> <pre class="brush:php;toolbar:false">__imul__(self, other)</pre> <pre class="brush:php;toolbar:false">__ifloorp__(self, other)</pre> <pre class="brush:php;toolbar:false">__ip__(self, other)</pre> <pre class="brush:php;toolbar:false">__itruep__(self, other)</pre> <pre class="brush:php;toolbar:false">__imod__(self, other)</pre> <pre class="brush:php;toolbar:false">__ipow__(self, other)</pre> <pre class="brush:php;toolbar:false">__ilshift__(self, other)</pre> <pre class="brush:php;toolbar:false">__irshift__(self, other)</pre> <pre class="brush:php;toolbar:false">__iand__(self, other)</pre> <pre class="brush:php;toolbar:false">__ior__(self, other)</pre> <pre class="brush:php;toolbar:false">__ixor__(self, other)</pre> <h3>类型转化</h3> <h3><pre class="brush:php;toolbar:false">__int__(self)</pre></h3> <p>实现了类型转化为int的行为.</p> <h3><pre class="brush:php;toolbar:false">__long__(self)</pre></h3> <p>实现了类型转化为long的行为.</p> <h3><pre class="brush:php;toolbar:false">__float__(self)</pre></h3> <p>实现了类型转化为float的行为.</p> <h3><pre class="brush:php;toolbar:false">__complex__(self)</pre></h3> <p>实现了类型转化为complex(复数, 也即1+2j这样的虚数)的行为.</p> <h3><pre class="brush:php;toolbar:false">__oct__(self)</pre></h3> <p>实现了类型转化为八进制数的行为.</p> <h3><pre class="brush:php;toolbar:false">__hex__(self)</pre></h3> <p>实现了类型转化为十六进制数的行为.</p> <h3><pre class="brush:php;toolbar:false">__index__(self)</pre></h3> <p>在切片运算中将对象转化为int, 因此该方法的返回值必须是int。用一个例子来解释这个用法。<br>class Thing(object):<br>    def __index__(self):<br>        return 1<br>thing = Thing()<br>list_ = ['a', 'b', 'c']<br>print list_[thing]  # 'b'<br>print list_[thing:thing]  # []<br>上面例子中, </p> <pre class="brush:php;toolbar:false">list_[thing]</pre> <p>的表现跟</p> <pre class="brush:php;toolbar:false">list_[1]</pre> <p>一致,正是因为Thing实现了</p> <pre class="brush:php;toolbar:false">__index__</pre> <p>方法。<br>可能有的人会想,</p> <pre class="brush:php;toolbar:false">list_[thing]</pre> <p>为什么不是相当于</p> <pre class="brush:php;toolbar:false">list_[int(thing)]</pre> <p>呢? 通过实现Thing的</p> <pre class="brush:php;toolbar:false">__int__</pre> <p>方法能否达到这个目的呢?<br>显然不能。如果真的是这样的话,那么</p> <pre class="brush:php;toolbar:false">list_[1.1:2.2]</pre> <p>这样的写法也应该是通过的。<br>而实际上,该写法会抛出TypeError: </p> <pre class="brush:php;toolbar:false">slice indices must be integers or None or have an __index__ method</pre> <p><br>下面我们再做个例子,如果对一个dict对象执行</p> <pre class="brush:php;toolbar:false">dict_[thing]</pre> <p>会怎么样呢?<br>dict_ = {1: 'apple', 2: 'banana', 3: 'cat'}<br>print dict_[thing]  # raise KeyError<br>这个时候就不是调用</p> <pre class="brush:php;toolbar:false">__index__</pre> <p>了。虽然</p> <pre class="brush:php;toolbar:false">list</pre> <p>和</p> <pre class="brush:php;toolbar:false">dict</pre> <p>都实现了</p> <pre class="brush:php;toolbar:false">__getitem__</pre> <p>方法, 但是它们的实现方式是不一样的。<br>如果希望上面例子能够正常执行, 需要实现Thing的</p> <pre class="brush:php;toolbar:false">__hash__</pre> <p> 和 </p> <pre class="brush:php;toolbar:false">__eq__</pre> <p>方法.<br>class Thing(object):<br>    def __hash__(self):<br>        return 1<br>    def __eq__(self, other):<br>        return hash(self) == hash(other)<br>dict_ = {1: 'apple', 2: 'banana', 3: 'cat'}<br>print dict_[thing]  # apple</p> <h3><pre class="brush:php;toolbar:false">__coerce__(self, other)</pre></h3> <p>实现了混合模式运算。<br>要了解这个方法,需要先了解</p> <pre class="brush:php;toolbar:false">coerce()</pre> <p>内建函数: 官方文档上的解释是, coerce(x, y)返回一组数字类型的参数, 它们被转化为同一种类型,以便它们可以使用相同的算术运算符进行操作。如果过程中转化失败,抛出TypeError。<br>比如对于</p> <pre class="brush:php;toolbar:false">coerce(10, 10.1)</pre> <p>, 因为10和10.1在进行算术运算时,会先将10转为10.0再来运算。因此</p> <pre class="brush:php;toolbar:false">coerce(10, 10.1)</pre> <p>返回值是(10.0, 10.1).</p> <pre class="brush:php;toolbar:false">__coerce__</pre> <p>在Python3中废弃了。</p> <h2>其他魔术方法</h2> <p>还没讲到的魔术方法还有很多,但有些我觉得很简单,或者很少见,就不再累赘展开说明了。</p> <h3><pre class="brush:php;toolbar:false">__str__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">str()</pre> <p>时调用。</p> <h3><pre class="brush:php;toolbar:false">__repr__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">repr()</pre> <p>时调用。</p> <pre class="brush:php;toolbar:false">str()</pre> <p>和</p> <pre class="brush:php;toolbar:false">repr()</pre> <p>都是返回一个代表该实例的字符串,<br>主要区别在于: str()的返回值要方便人来看,而repr()的返回值要方便计算机看。</p> <h3><pre class="brush:php;toolbar:false">__unicode__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">unicode()</pre> <p>时调用。</p> <pre class="brush:php;toolbar:false">unicode()</pre> <p>与</p> <pre class="brush:php;toolbar:false">str()</pre> <p>的区别在于: 前者返回值是unicode, 后者返回值是str。unicode和str都是</p> <pre class="brush:php;toolbar:false">basestring</pre> <p>的子类。<br>当你对一个类只定义了</p> <pre class="brush:php;toolbar:false">__str__</pre> <p>但没定义</p> <pre class="brush:php;toolbar:false">__unicode__</pre> <p>时,</p> <pre class="brush:php;toolbar:false">__unicode__</pre> <p>会根据</p> <pre class="brush:php;toolbar:false">__str__</pre> <p>的返回值自动实现,即</p> <pre class="brush:php;toolbar:false">return unicode(self.__str__())</pre> <p>;<br>但返回来则不成立。<br>class StrDemo2:<br>    def __str__(self):<br>        return 'StrDemo2'<br>class StrDemo3:<br>    def __unicode__(self):<br>        return u'StrDemo3'<br>demo2 = StrDemo2()<br>print str(demo2)  # StrDemo2<br>print unicode(demo2)  # StrDemo2<br>demo3 = StrDemo3()<br>print str(demo3)  # <__main__.StrDemo3 instance><br>print unicode(demo3)  # StrDemo3</p> <h3><pre class="brush:php;toolbar:false">__format__(self, formatstr)</pre></h3> <pre class="brush:php;toolbar:false">"Hello, {0:abc}".format(a)</pre> <p>等价于</p> <pre class="brush:php;toolbar:false">format(a, "abc")</pre> <p>, 等价于</p> <pre class="brush:php;toolbar:false">a.__format__("abc")</pre> <p>。<br>这在需要格式化展示对象的时候非常有用,比如格式化时间对象。</p> <h3><pre class="brush:php;toolbar:false">__hash__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">hash()</pre> <p>时调用, 返回值是数值类型。</p> <h3><pre class="brush:php;toolbar:false">__nonzero__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">bool()</pre> <p>时调用, 返回True或者False。<br>你可能会问, 为什么不是命名为</p> <pre class="brush:php;toolbar:false">__bool__</pre> <p>? 我也不知道。<br>我只知道该方法在Python3中改名为</p> <pre class="brush:php;toolbar:false">__bool__</pre> <p>了。</p> <h3><pre class="brush:php;toolbar:false">__dir__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">dir()</pre> <p>时调用。通常实现该方法是没必要的。</p> <h3><pre class="brush:php;toolbar:false">__sizeof__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">sys.getsizeof()</pre> <p>时调用。返回对象的大小,单位是bytes。</p> <h3><pre class="brush:php;toolbar:false">__instancecheck__(self, instance)</pre></h3> <p>对实例调用</p> <pre class="brush:php;toolbar:false">isinstance(instance, class)</pre> <p>时调用。 返回值是布尔值。它会判断instance是否是该类的实例。</p> <h3><pre class="brush:php;toolbar:false">__subclasscheck__(self, subclass)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">issubclass(subclass, class)</pre> <p>时调用。返回值是布尔值。它会判断subclass否是该类的子类。</p> <h3><pre class="brush:php;toolbar:false">__copy__(self)</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">copy.copy()</pre> <p>时调用。返回”浅复制”的对象。</p> <h3><pre class="brush:php;toolbar:false">__deepcopy__(self, memodict={})</pre></h3> <p>对实例使用</p> <pre class="brush:php;toolbar:false">copy.deepcopy()</pre> <p>时调用。返回”深复制”的对象。</p> <h3><pre class="brush:php;toolbar:false">__call__(self, [args...])</pre></h3> <p>该方法允许类的实例跟函数一样表现:<br>class XClass:<br>    def __call__(self, a, b):<br>        return a + b<br>def add(a, b):<br>    return a + b<br>x = XClass()<br>print 'x(1, 2)', x(1, 2)<br>print 'callable(x)', callable(x)  # True<br>print 'add(1, 2)', add(1, 2)<br>print 'callable(add)', callable(add)  # True</p> <h2>Python3中的差异</h2> <p>Python3中,str与unicode的区别被废除了,因而</p> <pre class="brush:php;toolbar:false">__unicode__</pre> <p>没有了,取而代之地出现了</p> <pre class="brush:php;toolbar:false">__bytes__</pre> <p>.<br>Python3中,pision默认就是true pision, 因而</p> <pre class="brush:php;toolbar:false">__p__</pre> <p>废弃.</p> <pre class="brush:php;toolbar:false">__coerce__</pre> <p>因存在冗余而废弃.</p> <pre class="brush:php;toolbar:false">__cmp__</pre> <p>因存在冗余而废弃.</p> <pre class="brush:php;toolbar:false">__nonzero__</pre> <p>改名为</p> <pre class="brush:php;toolbar:false">__bool__</pre> <div></div> <!--<p class='doc-content-pic doc-pic'><img src="https://img.php.cn/upload/article/000/000/013/b418c5819b5ebecfe1f9367c41f9fb08-0.jpg" / alt="Python의 매직 메소드 자세히 살펴보기" > </p>-->

위 내용은 Python의 매직 메소드 자세히 살펴보기의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.