3

I'm subclassing UUID and I was trying to figure out if UUID.hex is a regular member or a method decorated with @property. I had to look at the source code to figure it out, which left me wondering if there was another way.

>>> import uuid
>>> x = uuid.UUID('0000180000001000800000805f9b34fb')
>>> print([attr for attr in dir(x) if callable(getattr(x, attr))])
['__class__', '__delattr__', '__dir__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__int__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
>>> print([attr for attr in dir(x) if not callable(getattr(x, attr))])
['__doc__', '__module__', '__slots__', '__weakref__', 'bytes', 'bytes_le', 'clock_seq', 'clock_seq_hi_variant', 'clock_seq_low', 'fields', 'hex', 'int', 'is_safe', 'node', 'time', 'time_hi_version', 'time_low', 'time_mid', 'urn', 'variant', 'version']

The source code is:

    @property
    def hex(self):
        return '%032x' % self.int

It's a method decorated with @property. I was kinda expecting that hex would show up as callable(), but that's not the case. Is there any way I could tell that by examining the class or an object?

Thanks!

Leonardo
  • 1,533
  • 17
  • 28

1 Answers1

3

The property decorator in Python takes a method and wraps it in an attribute that's defined on the class. Then instances of that class are smart enough to behave differently when the property is referenced.

Let's set up a simple class with one property and one field, as well as an instance of the class, for testing

class A:

    def __init__(self):
        self.my_field = "foo"

    @property
    def my_property(self):
        return "foo"

a = A()

Then, if we examine this class in the REPL, we see that a.my_field and a.my_property are both "foo". More interestingly, A.my_field is an AttributeError and A.my_property is a property object (i.e. an instance of the property class. And that's exactly what we can use

def is_property(class_, name):
    try:
        return isinstance(getattr(class_, name), property)
    except AttributeError:
        return False

If the name doesn't exist on the class, then return False, as it's definitely not a property. If it does, then check that it is an instance of the property class. Call it like

is_property(A, 'my_field')
is_property(A, 'my_property')

(Note we use the class, not an instance; and the field name is a string)

Try it online!

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116
  • Your `is_property` function could just return `isinstance(getattr(class_, name, False), property)` ? – Alex May 31 '21 at 19:19