Python: 继承类函数(属性获取器)无效

1 投票
1 回答
618 浏览
提问于 2025-04-17 14:11

考虑以下代码:

class BaseClass(object):
    def _del_property(attr):
        """Abstract deller"""
        def del_attr(self):
            setattr(self, attr, None)
        return del_attr

    def _set_property(attr):
        """Abstract setter."""
        def set_attr(self, x):
            setattr(self, attr, x)            
        return set_attr

    def _get_property(attr):
        """Abstract getter"""
        def get_attr(self):
            getattr(self, attr)
        return get_attr

    _name = None
    name = property(fget=_get_property('_name'), fset=_set_property('_name'))


class Component(BaseClass):

    _material = None
    material = property(fget=_get_property('_material'), fset=_set_property('_material'), fdel=_del_property('_material'))

为什么 _get_property、_set_property 和 _del_property 这些方法没有被继承呢?我们该怎么做才能让它们被继承呢?

这些方法应该能在同一个源文件中的派生类中使用,也应该能在不同文件中的派生类中使用,只要这些派生类导入了这个源文件。

from filename import *

1 个回答

2

当你创建一个类的时候,Python会为这个类创建一个新的命名空间。Python会读取你在类里面写的代码块,然后把这些信息传递给type(或者对应的元类)。在这个情况下,Python会报错,因为在设置Component类的时候,_get_property并没有在这个范围内定义——可能是BaseClass._get_property,但那样可能也不能像你想的那样工作。

一个简单的解决办法是把这些函数放到模块级别,因为类的命名空间可以访问模块的命名空间:

def _del_property(attr):
    """Abstract deller"""
    def del_attr(self):
        setattr(self, attr, None)
    return del_attr

def _set_property(attr):
    """Abstract setter."""
    def set_attr(self, x):
        setattr(self, attr, x)            
    return set_attr

def _get_property(attr):
    """Abstract getter"""
    def get_attr(self):
        getattr(self, attr)
    return get_attr


class BaseClass(object):

    _name = None
    name = property(fget=_get_property('_name'), fset=_set_property('_name'))


class Component(BaseClass):

    _material = None
    material = property(fget=_get_property('_material'), fset=_set_property('_material'), fdel=_del_property('_material'))

也许我们在创建类的时候看看它会更有帮助:

class BaseClass(object):

    def _del_property(attr):
        """Abstract deller"""
        def del_attr(self):
            setattr(self, attr, None)
        return del_attr

    print type(_del_property)
print type(BaseClass._del_property)

这样会打印出:

<type 'function'>
<type 'instancemethod'>

所以,你在BaseClass里面处理的是一个普通的函数,但在type施展魔法后,它就变成了一个instancemethod


就我个人而言,我会创建一个方便的函数:

def property_api(name,fget=True,fset=True,fdel=True):
    return property(fget=_get_property(name) if fget else None,
                    fset=_set_property(name) if fset else None,
                    fdel=_del_property(name) if fdel else None)

然后你就可以使用它。如果你真的想的话,甚至可以把它放到BaseClass里作为一个staticmethod

 class BaseClass(object):
      property_api = staticmethod(property_api)

这样你的派生类看起来就会是:

 class DerivedClass(BaseClass):
      _material = None
      material = BaseClass.property_api('_material')

撰写回答