PapeK24
PapeK24

Reputation: 1126

Is it possible to self-reference type in Python attr

I am looking to do something like this:

@attr.s
class A(object):
    a_dict = attr.ib(factory=Dict, type=Dict[str, A], validator=optional(instance_of(Dict)))

It is possible to type it just as type=Dict but I wonder if you can self-reference like type=Dict[str, cls], but it might be limited by possibilities of Python.

Thanks.

Upvotes: 1

Views: 1317

Answers (3)

hynek
hynek

Reputation: 4146

If I interpret is correctly, what you want is this:

from typing import Dict, Optional

import attr

from attr.validators import optional, instance_of


@attr.s
class A(object):
    a_dict = attr.ib(
        factory=dict,
        type=Optional[Dict[str, "A"]],
        validator=optional(instance_of(dict))
    )


A({"key": A(None)})

And it passes mypy.

Please note:

  • You cannot use typing.Dict for factory because it's really just for type hints and fails if you try to instantiate it.
  • instance_of uses isinstance() internally and while isinstance({}, Dict) is True, I don't think it's the intended to be used like that.
  • If a_dict is optional as per validator, you also need to declare it optional using type annotations by wrapping it in an Optional[].

Upvotes: 1

entropy
entropy

Reputation: 850

cls and self are names given to classes and their instances by convention, when they are passed as arguments to class methods and instance methods respectively. Neither will be defined where you're trying to use them.

What you might be able to do instead, is enforce the type to be a non-object superclass of A, if there is any.

Upvotes: 1

Dan D.
Dan D.

Reputation: 74655

The issue is that class A(object): A results in NameError: name 'A' is not defined. What this means is that one can not reference a class by its name during its creation in its defining block.

I think that to get around this in typing, one can use a string instead: type=Dict[str, 'A']. I remember seeing this as how forward references are made but this might not be right.

Upvotes: 2

Related Questions