Determine if given class attribute is a property or not, Python object

后端 未结 3 947
臣服心动
臣服心动 2020-12-14 00:58

It\'s all in the title. Here is the following example:

class A(object):
    my_var = 5

    def my_method(self, drink=\'beer\'):
        return \'I like %s\'         


        
相关标签:
3条回答
  • 2020-12-14 01:11

    To add to the John La Rooy's answer (and bugmenot123's comment), it's easy to extend the code to check for arbirary attribute names.


    Let's define a class with a property, and its instance:

    class MyClass:
        not_a_property = None
        @property
        def my_property(self):
                pass
        def my_method(self):
                pass
    
    my_object = MyClass()
    

    We can simply use any getattr with an arbitrary string to check if the attribute of the class of the given object is a property, just like John La Rooy demonstrated:

    >>> isinstance(getattr(type(my_object), 'not_a_property'), property)
    False
    >>> isinstance(getattr(type(my_object), 'my_property'), property)
    True
    >>> isinstance(getattr(type(my_object), 'my_method'), property)
    False
    

    To get for all property method names of an object, you can loop through dir of the class, like this:

    for attr in dir(type(my_object)):
        print(
                f'{attr} is a property method:'.ljust(42),
                isinstance(getattr(type(my_object), attr), property)
        )
    

    The loop above prints the following output:

    __class__ is a property method:            False
    __delattr__ is a property method:          False
    __dict__ is a property method:             False
    __dir__ is a property method:              False
    __doc__ is a property method:              False
    __eq__ is a property method:               False
    __format__ is a property method:           False
    __ge__ is a property method:               False
    __getattribute__ is a property method:     False
    __gt__ is a property method:               False
    __hash__ is a property method:             False
    __init__ is a property method:             False
    __init_subclass__ is a property method:    False
    __le__ is a property method:               False
    __lt__ is a property method:               False
    __module__ is a property method:           False
    __ne__ is a property method:               False
    __new__ is a property method:              False
    __reduce__ is a property method:           False
    __reduce_ex__ is a property method:        False
    __repr__ is a property method:             False
    __setattr__ is a property method:          False
    __sizeof__ is a property method:           False
    __str__ is a property method:              False
    __subclasshook__ is a property method:     False
    __weakref__ is a property method:          False
    my_method is a property method:            False
    my_property is a property method:          True
    not_a_property is a property method:       False
    
    0 讨论(0)
  • 2020-12-14 01:24

    You need to look at the class (this is the case for descriptors in general), which for objects you can find via the __class__ attribute or by using the type function:

    >>> obj.__class__.my_property
    <property object at 0xb74bd16c>
    

    or by

    >>> type(obj).my_property
    <property object at 0xb720b93c>
    

    These result in the same "property object" as if you were to directly check the attribute of the class (implying you know the class' name in your code instead of checking it dynamically like you probably should rather do):

    >>> A.my_property
    <property object at 0xb7312345>
    

    So to test if a specific attribute of an object is a property, this would be one solution:

    >>> isinstance(type(obj).my_property, property)
    True
    
    0 讨论(0)
  • 2020-12-14 01:26

    I once asked a similar question. The trouble you'll run into, of course, is that you can't access the property through the instance to determine its type without calling the getter, which gets you the type of whatever the getter returns. So you have to access the property through its class rather than through the instance.

    property is already a type, so you can just compare directly to that. (I originally had some superfluous code here that got the property type out of a class that had a property. I thought this was necessary due to a typo when I was testing things.)

    obj_type = type(obj)
    
    for attr in dir(obj):
        if isinstance(getattr(type(obj), attr, None), property):
            print attr, "is a property"
    

    Don't worry about having an instance attribute with the same name. It's ignored in attribute lookup if there's a data descriptor of the same name on the class (property is a data descriptor).

    Of course, any class can be a data descriptor, not just property, so in theory you really want to check for __get__() and/or __set__() and/or __delete__() attributes on the type. But the problem with that approach is that all functions and methods are themselves descriptors and therefore would be caught by that check. It quickly becomes silly to try to find all the exceptions.

    0 讨论(0)
提交回复
热议问题