如何在Python中检查属性是否可设置或可删除?
到目前为止我发现的最好的是
type(obj).__dict__["prop_name"].fset is not None
答案 0 :(得分:8)
这是一个很好的情况,当你应该订阅“请求宽恕而不是权限”的理念时,如果属性不可设置/可删除,只需处理异常。
try:
x.prop = 42
except AttributeError:
pass
答案 1 :(得分:1)
我认为没有任何方法可以在不尝试的情况下预先知道。您无法确定某个对象是否有一个奇怪的__setattr__
或类似的东西会破坏您尝试使用的抽象。
答案 2 :(得分:1)
以下程序测试三个函数,用于确定类或实例属性是否支持CRUD操作。类或实例是can_*
函数的第一个参数,第二个参数是应该检查的属性的名称。自动完成类型检查以确保按预期使用功能。请注意,此设计仅适用于使用property
模块中的builtins
类创建的属性。
#! /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()