4

Let's say I have the following descriptor:

class MyDescriptor(object):

    def __init__(self, name, type_):
        self.name = name
        self.type_ = type_

    def __set__(self, obj, value):
        assert isinstance(value, self.type_)
        obj.__dict__[self.name] = value

Is there a way to access type_ from an object employing MyDescriptor?

i.e.

class MyObject(object):
    x = MyDescriptor('x', int)

my_object = MyObject()
my_object.x = 5
print my_object.x.type_

As far as I'm aware, this will raise AttributeError as my_object.x is an int. But, I'm wondering if there's a good way to associate metadata with descriptors.

EDIT: adjusted wording to indicate that there's one instance of a descriptor per class.

3
  • I don't think there's any reason to name the field type_ with the underscore. For the parameter it makes sense but self.type doesn't shadow anything so it's fine. Commented May 11, 2016 at 17:46
  • Check out stackoverflow.com/questions/21629397/… Commented May 11, 2016 at 17:47
  • @alex hall Good point! But, while that's true, it results in code like self.__class__.x.type_ or my_object.__class__.x.type in practice. Which, I suppose isn't terrible. Commented May 11, 2016 at 17:48

2 Answers 2

3

Is there a way to access type_ from the object instance which owns the MyDescriptor instance?

There is no object instance which owns the MyDescriptor instance. There is one instance of MyDescriptor which is stored on the class of which the descriptor is an attribute (MyObject in your example). That's how descriptors work. You can access this descriptor instance via the class as described in user2357112's answer, but be aware that you're accessing class-level data. If you want to store instance-level data with the descriptor, you need to store it on the instance itself (i.e., on the object passed as obj to your __set__/__get__) rather than on the descriptor.

Sign up to request clarification or add additional context in comments.

1 Comment

Marking this as the solution since it revealed the incorrect assumption in my question and led to some helpful edits and a better course of action in the end. Thanks!
2

You need to access the actual descriptor object. For your descriptor, that can be done with

type(my_object).x.type_

or

MyObject.x.type_

For descriptors where MyObject.x is not the actual descriptor object, such as functions on Python 2, you may need to find the descriptor by looking in the class __dict__, or looking through the dicts of all classes in the MRO if you want a generic way to find inherited descriptors. (For the specific case I just mentioned, you can also use the __func__ attribute of the unbound method object, but that won't work for other descriptors.)

1 Comment

This is true, but the question indicates that the OP thinks there is a separate descriptor object for each instance of MyObject. There is not. So you can do this, but, as described in my answer, it may not do what the OP hopes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.