Python学习之魔法方法

发布时间:2019-03-16 22:24:09编辑:auto阅读(1731)

     

    Python中会看到前后都加双下划线的函数名,例如 __init__(self),这类写法在Python中具有特殊的含义。如果对象使用了这类方法中的某一个,那么这个方法将会在特殊的情况下被执行,然而几乎不会直接调用此类方法。

    如果没有兼容旧版本Python代码的需要,我们在编写代码时应将所有类的写为新式类并且使用super函数这样的特性。

    在Python3.0中没有"旧式"的类,也不需要侠士的子类化Object或者将元类设置为type(代码起始行__metaclass__=type).那是因为所有的类都是隐式的成为Object的子类。如果没有明确超类的话,就会直接子类化;否则间接子类化。

     

    Python中的重写

     先看代码

    1 class A:
    2     def hello(self):
    3         print('hello i\'m a')
    4 class B(A):
    5     pass
    6 a=A()
    7 a.hello()
    8 b=B()
    9 b.hello()

    输出结果:

    hello i'm a
    hello i'm a

    B类继承A类,实例化B对象后可以调用A类中的hello函数,但并不能满足自己需求,我不仅要调用A类中的函数,而且还需要执行满足自己的命令(比如打印hello b)。此时我们就可以在子类中重写超类的函数以满足自己的需求。

    修改代码如下:

     1 class A:
     2     def hello(self):
     3         print('hello i\'m a')
     4 class B(A):
     5     def hello(self):
     6         print('hello i\'m b')
     7 a=A()
     8 a.hello()
     9 b=B()
    10 b.hello()

    输出结果:

    hello i'm a
    hello i'm b

     

    Python中的构造方法

     构造方法与其他方法不同,当一个对象被创建后,会立即调用构造方法。

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

     了解过继承的概念后我们知道,每个类都可能拥有一个或者多个超类,子类从父类那里继承父类的一些行为方式。不仅如此,我们也可以重写一些超类的方法来自定义继承行为。

    
    
    class Bird:
    def __init__(self):
    self.hungry=True
    def eat(self):
    if self.hungry:
    print('我在吃')
    self.hungry=False
    else:
    print('我吃饱了,谢谢')


    sb=Bird()
    sb.eat()
    sb.eat()
     

    打印结果:

    1 我在吃
    2 我吃饱了,谢谢

    通过代码可知道,鸟吃饱以后,将饥饿状态改为Flase,说明小鸟吃饱了,当在调用eat函数时候,则打印我吃饱了,谢谢。这是在通一个类中的__init__函数的使用。来看扩展案例。吃是鸟类的基本特征,可以将Bird作为鸟类的基类。现在我们写一个会唱歌的鸟,因为我们已经写好了一个鸟的基类,此时仅需继承它之后,我们的鸟不仅会唱歌而且默认的学会了吃的技能。

     1 class Bird:
     2     def __init__(self):
     3         self.hungry=True
     4     def eat(self):
     5         if self.hungry:
     6             print('ahhh')
     7             self.hungry=False
     8         else:
     9             print('no thanks')
    10 
    11 class SongBird(Bird):
    12     def __init__(self):
    13 
    14         self.sound='Squawk'
    15 
    16     def sing(self):
    17         print(self.sound)
    18 sb=SongBird()
    19 sb.sing()
    20 sb.eat()
    21 sb.eat()

    打印结果:

    1 Traceback (most recent call last):
    2 Squawk
    3   File "F:/Python培训/博客园随笔专用/文件操作/文件读写.py", line 20, in <module>
    4     sb.eat()
    5   File "F:/Python培训/博客园随笔专用/文件操作/文件读写.py", line 5, in eat
    6     if self.hungry:
    7 AttributeError: 'SongBird' object has no attribute 'hungry'

    不幸的是,我们的鸟可以触发唱歌的功能,但当调用父类的吃的功能时,就抛出了异常。再看父类中定义的eat函数,启动eat函数需要设置hungry属性。但不解的是,我们已经继承了鸟的基类Bird,Bird里也定义了hungry为什么不起作用呢。那是因为hungry属性是在当父类调用自己的构造函数时才起作用。由此可见,SingBird继承了Bird的所有功能,却未触发Bird的初始化功能。修改以下代码

     1 class Bird:
     2     def __init__(self):
     3         self.hungry=True
     4     def eat(self):
     5         if self.hungry:
     6             print('ahhh')
     7             self.hungry=False
     8         else:
     9             print('no thanks')
    10 
    11 class SongBird(Bird):
    12     def __init__(self):
    13         Bird.__init__(self)
    14         self.sound='Squawk'
    15     def sing(self):
    16         print(self.sound)
    17 sb=SongBird()
    18 sb.sing()
    19 sb.eat()
    20 sb.eat()

     输出结果:

    1 Squawk
    2 ahhh
    3 no thanks

    通过代码可以知道,我们在SongBird的初始化类时,调用了Bird的初始化函数。因此,Bird的构造函数得以触发。现在我们的鸟,不仅能唱歌而且具备基类中吃的行为。

    再看它执行过程。SongBird在初始化自身的同时,又将自己作为参数传递给它的父类,也就是告诉父类,你在造我的时候,要赋予我天生的技能(自己知道温饱)。也就是hungry属性被设置。

    使用Super函数

    以上方法是3.0以前的写法,新式类中将使用super函数解决以上问题。

     1 class Bird:
     2     def __init__(self):
     3         self.hungry=True
     4     def eat(self):
     5         if self.hungry:
     6             print('ahhh')
     7             self.hungry=False
     8         else:
     9             print('no thanks')
    10 
    11 class SongBird(Bird):
    12     def __init__(self):
    13         super(SongBird, self).__init__()
    14         self.sound='Squawk'
    15     def sing(self):
    16         print(self.sound)
    17 sb=SongBird()
    18 sb.sing()
    19 sb.eat()
    20 sb.eat()

    当前的类和对象被当做参数调用,而调用函数返回的对象的任何方法都是调用超类的方法。总结:显示的传递子类和子类对象并且调用构造函数但隐式的却是在执行父类的构造方法。

    基本的映射和序列规则

    __len__:返回集合中所含项目的数量。对于序列来说,返回的是元素的个数,对于映射来说返回的是 键值对的数量。

    __getitem__(self,key):返回与所给键对应的值。对于序列,键应该是0~n-1的整数(n是长度),对于映射,可以是任何类型的键。

    __setitem__(self,key,value):按一定方式存储和key相关的value.该值可以用__getitem__来获取。 注意:只能为可以修改的对象定义这个方法。

    __delitem__(self,key):该方法在对一部分对象使用del语句时调用。

     属性

     

关键字