網頁

2015年7月5日 星期日

[Python] property繼承的寫法

主題: property繼承的寫法


假設我們有一個擁有name property的class A:

class A(object):
        def __init__(self):
                print ("A init")
        @property
        def name(self):
                print ("A name getter")
        @name.setter
        def name(self, x):
                print ("A name setter")
我們想要對A的name property繼承,並且改寫。 改寫的方式想要繼承A原本的一些code再附加新的class的一些code,可以這樣寫:
class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.fget(self)
                print ("B name getter")

        @name.setter
        def name(self, x):
                super(B, B).name.fset(self, x)
                print ("B name setter")

或者把fget和fset換成__get__和__set__
class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.__get__(self)
                print ("B name getter")

        @name.setter
        def name(self, x):
                super(B, B).name.__set__(self, x)
                print ("B name setter")

為什麼可以這樣? 有興趣的人可以去研究一下 property這個class

還有一點要注意, 其實這樣的寫法是"定義B的自己版本name property", 換句話說,
B.name和A.name是兩個不同的版本。
也就是如果B只有定義getter或是setter,那麼這個property也只會剩下getter或是setter的能力:


#!/usr/bin/python

class A(object):
        def __init__(self):
                print ("A init")
        @property
        def name(self):
                print ("A name getter")
        @name.setter
        def name(self, x):
                print ("A name setter")


class B(A):
        def __init__(self):
                print ("B init")

        @property
        def name(self):
                super(B, B).name.__get__(self)
                print ("B name getter")

b = B()
b.name
b.name = 3

結果:
B init
A name getter
B name getter
Traceback (most recent call last):
  File "./property.py", line 25, in 
    b.name = 3
AttributeError: can't set attribute

Shell 已返回1

結論:

1. child class要改寫parent class的property最好全部都改寫,除非你知道你在做什麼,你真的想閹割parent class的setter or getter or deleter ?
2. child class若要呼叫parent class的class method(memer data), 那就要用 super(B, B).name的寫法
3. property class有實作"descriptor protocol"(__get__, __set__, __delete__這三個function),
property class的__get__會去呼叫 property class的instance method: fget
property class的__set__會去呼叫 property class的instance method: fset
property class的__delete__會去呼叫 property class的instance method: fdel

沒有留言:

張貼留言