检查属性是否可设置/删除

16 投票
3 回答
1084 浏览
提问于 2025-04-16 18:12

我该如何检查一个属性在Python中是否可以设置或删除呢?

到目前为止,我找到的最好方法是

type(obj).__dict__["prop_name"].fset is not None

3 个回答

1

下面这个程序测试了三个函数,这些函数的目的是检查一个类或者实例的属性是否支持CRUD操作。这里的类或实例是传给can_*函数的第一个参数,而第二个参数是需要检查的属性名称。程序会自动进行类型检查,以确保这些函数的使用是符合预期的。请注意,这些函数只适用于使用builtins模块中的property类创建的属性。

#! /usr/bin/env python3


def main():
    for kind in Test, TestG, TestS, TestGS, TestD, TestGD, TestSD, TestGSD:
        print(kind.__name__, 'Class')
        print('  can_get:', can_get(kind, 'data'))
        print('  can_set:', can_set(kind, 'data'))
        print('  can_del:', can_del(kind, 'data'))
        print()
        instance = kind('Hello, world!')
        print(kind.__name__, 'Instance')
        print('  can_get:', can_get(instance, 'data'))
        print('  can_set:', can_set(instance, 'data'))
        print('  can_del:', can_del(instance, 'data'))
        print()


def can_get(obj, key):
    return _get_property(obj, key).fget is not None


def can_set(obj, key):
    return _get_property(obj, key).fset is not None


def can_del(obj, key):
    return _get_property(obj, key).fdel is not None


def _get_property(obj, key):
    if not isinstance(obj, type):
        obj = type(obj)
    pro = vars(obj).get(key)
    if not isinstance(pro, property):
        raise TypeError('{.__name__}.{} is not a property'.format(obj, key))
    return pro


class Test:

    def __init__(self, value):
        self.__data = value

    def get_data(self):
        return self.__data

    def set_data(self, value):
        self.__data = value

    def del_data(self):
        del self.__data

    data = property()


class TestG(Test):

    data = property(fget=Test.get_data)


class TestS(Test):

    data = property(fset=Test.set_data)


class TestGS(Test):

    data = property(fget=Test.get_data, fset=Test.set_data)


class TestD(Test):

    data = property(fdel=Test.del_data)


class TestGD(Test):

    data = property(fget=Test.get_data, fdel=Test.del_data)


class TestSD(Test):

    data = property(fset=Test.set_data, fdel=Test.del_data)


class TestGSD(Test):

    data = property(fget=Test.get_data, fset=Test.set_data, fdel=Test.del_data)


if __name__ == '__main__':
    main()
1

我觉得在尝试之前是没办法提前知道的。你不能确定一个对象是否有奇怪的 __setattr__ 或者类似的东西,这可能会破坏你想要使用的抽象概念。

8

这是一个很好的例子,说明你应该遵循“请求原谅比请求许可更容易”的原则,也就是说,遇到问题时直接处理错误就行,特别是当某个属性不能被设置或删除时。

try:
    x.prop = 42
except AttributeError:
    pass

撰写回答