2011-05-23 18 views
15

¿Cómo puedo verificar si una propiedad es configurable o eliminable en Python?Comprobando si la propiedad es configurable/eliminable

El mejor que he encontrado hasta ahora es

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

¡Una buena pregunta! Y su solución parece la mejor solución que existe. –

+2

Prefiero decir 'obj .__ class __. Prop_name.fset' a tu idioma de' type (obj) .__ dict __ ["prop_name"]. Fset', pero creo que ambos son válidos, y estoy de acuerdo con BasicWolf que tu la respuesta es probablemente la mejor. –

Respuesta

8

Este es un buen caso en que usted debe suscribirse a "Es más fácil pedir perdón que pedir permiso" la filosofía, y simplemente manejar la excepción de propiedad caso es no configurable/eliminable.

try: 
    x.prop = 42 
except AttributeError: 
    pass 
+2

Buena respuesta. Consideré esto, pero automáticamente estoy construyendo UI desde las propiedades y usando su "settability" para decidir establecer el indicador 'ItemIsEditable'. Supongo que podría consultar con 'x.prop = x.prop' o cambiar mi diseño. –

+2

@Neil: Si escribió el código en cuestión y sabe que decir 'x.prop = x.prop' siempre será seguro, entonces esa comprobación estaría bien. Sin embargo, los diseñadores de propiedades pueden hacer cosas inesperadas, como acceder a la base de datos o incrementar un contador o cambiar el estado interno de su sistema, por lo que evitaría llamarlos a menos que no haya otro enfoque. La solución que mencionas en tu pregunta me parece mejor. –

1

No creo que haya ninguna manera de saber por adelantado sin intentarlo. No puede saber con certeza si un objeto tiene un extraño __setattr__ o similar que romperá la abstracción que está tratando de utilizar.

1

El siguiente programa prueba tres funciones diseñadas para averiguar si una propiedad de clase o instancia admite operaciones CRUD. La clase o instancia es el primer argumento para las funciones can_*, y el segundo argumento es el nombre de la propiedad que debe verificarse. La comprobación de tipos se realiza automáticamente para garantizar que las funciones se utilizan como se espera. Tenga en cuenta que esto está diseñado para funcionar solo con propiedades creadas con la clase property del módulo 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() 
+0

Este enfoque ya está dado en la pregunta. Sin embargo, como señala Daenyth en su respuesta, no funciona en general. –

+0

Eso puede ser cierto, pero dependiendo del código con el que esté trabajando, puede funcionar de manera específica, lo que puede ser suficiente para algunos. –

+0

Sí, eso es correcto. Y este tipo de solución es que terminé haciendo en mi código. –

Cuestiones relacionadas