• 魔法方法和属性


    在python中,有的名称会在前面和后面都加上两个下划线,这种写法很特别,同时表示名字有特殊含义,所以绝不要在自己的程序中使用这种名字。

    在python中,这种名字组成的集合所包含的方法称为魔法(或特殊)方法。

    如果对象实现了这些方法中的某一个,那么这个方法会在特殊的情况下(确切的说是根据名字)被python调用。

    很久以前(Python2.2中),对象的工作方式就有了很大的变化。这种改变产生了一些影响,但对于刚开始使用python的人来说,大多数都不重要。

    值得注意的是,尽管可能是用的是新版的python,但有一些特性不会在老式类上起作用。

    为了确保类是新型的,应该把赋值语句__metaclass__=type放在你的模块的最开始。或者(直接或者间接)子类化内建类object。

     

    1.构造方法

    首先要讨论的第一个魔法方法是构造方法。构造方法是一个很奇特的名字,它代表着类似于以前例子中使用过的那种名为init的初始化方法。

    但构造方法和其他普通方法不同的地方在于,当一个对象被创建后,会立即调用构造方法。

    在python中创建一个构造方法很容易。只要把init方法的名字从简单的init修改为魔法版本的__init__即可:

    >>> class Foobar:
    ...     def __init__(self):
    ...             self.somevar = 42
    ...
    >>>
    >>> f = Foobar()
    >>> f.somevar
    42

    如果要给构造方法传几个参数的话,会发生什么情况了?

    >>> class Foobar:
    ...     def __init__(self,value=42):   #参数可选
    ...         self.somevar = value   #有点类似于函数的传参
    ...

    参数可选,传个参数试试

    >>> f = Foobar('This is a constructor argument')
    >>> f.somevar
    'This is a constructor argument'

    在所有的魔法方法中,__init__是使用最多的一个。

    2.重写一般方法和特殊的构造方法

    在继承的知识中,每个类都有可能拥有一个或者多个超类,它们从超类那里继承行为方式。

    如果一个方法在B类的一个实力被调用(或一个属性被访问),但在B类中没有找到方法,那么就会取它的超类里面找。

    >>> class A:
    ...     def hello(self):
    ...         print("Hello,I'm A.")
    ...
    >>> class B(A):
    ...     pass
    ...
    >>> a = A()
    >>> b =B()
    >>> a.hello()
    Hello,I'm A.
    >>> b.hello()   #A继承了一个叫hello的方法,被B继承。
    Hello,I'm A.

    因为B类没有自己的构造方法,所以当hello被调用时,原始的信息就被打印出来。

    在子类中增加功能的最基本的方法是增加方法,但是也可以重写一些超类的方法来定义继承的行为。

    >>> class B(A):
    ...     def hello(self):
    ...         print("Hello,I")
    ...
    >>> b.hello()
    Hello,I

    重写是继承机制中的一个重要内容,对于构造方法尤为重要。

    构造方法用来初始化新创建对象的状态,大多数字类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码。

    虽然重写的机制对于所有方法都是一样的,但是当处理构造方法比重写普通方法时,更可能遇到特别的问题:如果一个类的构造方法被重写,那么就需要调用超类(你所继承的类)的构造方法,否则可能不会被正确的初始化。

    考虑下面的Bird类:

    class Bird:
        def __init__(self):
            self.hungry = True
        def ear(self):
            if self.hungry :
                print('Aaaah...')
                self.hungry = False
            else:
                print('No,thanks')

    定义了鸟最基本的能力——吃,

    Aaaah...
    No,thanks

    吃过之后,它就不再饥饿了,加入子类SongBird。

    class SongBird(Bird):
        def __init__(self):
            self.sound = 'Squawk'
        def sing(self):
            print(self.sound)

    一样可以生成对象,并且调用其中的方法。

    sb = SongBird()
    sb.sing()
    
    结果:
    Squawk

    SongBird是Bird的子类,能否继承其中的方法了?试一下

    sb.ear()
    结果:
    Traceback (most recent call last):
      File "I:/untitled/cx/11月/函数.py", line 23, in <module>
        sb.ear()
      File "I:/untitled/cx/11月/函数.py", line 5, in ear
        if self.hungry :
    AttributeError: 'SongBird' object has no attribute 'hungry'

    Why?Why?...

    异常很清楚的说明了错误:SongBird没有hungry的特性。

    原因是这样的:在SongBird中,构造方法被重写,但新的构造方法没有任何关于hungry特性的代码。

    为了达到预期的效果,SongBird的构造方法必须被重写,有两种方法能够达到这一目的:调用未绑定的构造方法,或者使用super函数。

    3.调用未绑定的超类的构造方法

    调用超类的构造方法其实很简单,只需要在刚才的例子上小小的改动。

    class SongBird(Bird):
        def __init__(self):
            Bird.__init__(self)  #就是如此简单
            self.sound = 'Squawk'
        def sing(self):
            print(self.sound)

    结果:

    sb.ear()
    
    Aaaah...

    为什么会有这样的结果了?在调用一个实例方法的时候,该方法的self参数会被自动绑定到实例上(这称为绑定方法)。

    如果直接调用类的方法(比如:Bird.__init__),那么就没有实例会被绑定。

    这样就可以自由的提供需要的self参数了,这样的方法称为未绑定的方法。

    4.使用super函数

    如果你不想坚守旧版本的Python阵营,也可以使用super函数,但是它只能在新式类中使用。当前的类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法。

    class SongBird(Bird):
        def __init__(self):
            super(SongBird,self).__init__()
            self.sound = 'Squawk'
        def sing(self):
            print(self.sound)
    
    sb = SongBird()
    sb.ear()
    sb.ear(
    
    结果:
    Aaaah...
    No,thanks
  • 相关阅读:
    使用MVC模型的几个常见误区
    ModelViewControl
    真的简单,还是盲目乐观?
    Kernel Korner Why and How to Use Netlink Socket
    我们手机平台的几个基础模型
    彩信库(mmslib)设计备忘录
    消极状态集
    文摘《十三》
    文摘《十二》
    文摘《十一》
  • 原文地址:https://www.cnblogs.com/yangmingxianshen/p/7801127.html
Copyright © 2020-2023  润新知