Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Type hint for attribute that might not exist #1912

Unanswered
cjw296 asked this question in Q&A
Discussion options

Cross posting from Stack Overflow:

How do I do a type hint for attribute that might not exist on the object in Python?

For example:

class X:
 __slots__ = ('attr',)
 attr: int # either int or doesn't exist - what do I put here?

So, concretely:

>>> x = X()
>>> x.attr
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: 'X' object has no attribute 'attr'
>>> x.attr = 1
>>> x.attr
1

Slots may not always be involved, but I can see wanting to do something similar when specifying a Protocol.

You must be logged in to vote

Replies: 6 comments 8 replies

Comment options

Currently this is not supported. There was a discussion about potentially adding Missing[] special form, but it was declined.

Right now the most correct way is to have some attribute defined as such:

class MyClass:
 def __init__(self) -> None:
 self.attr: int | None = None
 def method(self) -> None:
 self.attr = 1 # or whatever
You must be logged in to vote
1 reply
Comment options

Well no, this isn't correct. attr not being present is indication to a walker looking for attributes to look further up in the tree, None is a valid value, so would stop that traversal and cannot be used.

Comment options

I'm curious what your desired behavior would be for such an attribute? Always emit an error/warning when accessing it, but also infer the resulting type as int?

You must be logged in to vote
4 replies
Comment options

In an ideal world, it would be an indication that mypy should report an error when the attribute is accessed other than through getattr(obj, 'attr', None).

Comment options

Also, if someone uses getattr, it tells the type checker what the attribute's type would be

Comment options

@ewjoachim - how so?

Comment options

Ah I understand that you were comparing

class X:
 y: Potential[int]

to

class X:
 y: int # might not exist

and in that case, of course, a type checker would need to complain if we access x.y without getattr (... or not in a try: except AttributeError?)

I was comparing

class X:
 y: Potential[int]

to

class X:
 pass
 # also, there might be a y

and in that case, it wouldn't even know that, if present, y would be an int. But your comparison makes more sense.

Comment options

I am running into this when trying to type the open search bulk load responses.

There's so many permutations of these objects that I really just wanna be able to type it as a single object type in the listwith certain attributes that may or may not exist. I can type this really easily in type script, but there seems to be zero ways to do it in Python.

You must be logged in to vote
1 reply
Comment options

@piyh - what does it look like in Typescript?

Comment options

This is a problem that is often ignored while being blatantly obvious.

Let's assume:

class Address:
 ...
class Person:
 name: str
 address: Address | None

Now, the only option to do a partial update of a person is TypedDict:

class PartialUpdatePerson(TypedDict):
 name: NotRequired[str]
 address: NotRequired[Address | None]

We need this.

You must be logged in to vote
0 replies
Comment options

I feel like the existing

NotRequired[TYPE]

would does exactly what we need, just right now limited to TypedDict.

So all we need now, is to allow it to be used in classes as well.

You must be logged in to vote
2 replies
Comment options

Following that line of thought, it might even make sense in regular code.

A variable only sometimes existing is a core part of python after all:

try:
 result: str = do_something_maybe_stupid()
except Exception as e:
 pass
# end def
result: NotRequired[str]
e: NotRequired[Exception]

Or

if foo == "bar":
 offset = 12
offset: NotRequired[int]
Comment options

What behaviour would NotRequired on a variable trigger on a type checker ? Type checkers already have all the info to know that a variable is maybe undefined, so I don't think there's value in making it explicit, given that the only thing that makes sense to do on such a variable is warn if it's used.

The only 2 ways to use a variable that might be undefined (as far as I can tell) are:

  • In a try: except NameError: block, and I don't think it's either pythonic nor something that I'd want a type checker to have a special case for (the same way that if you do:
    a: dict[str, str] = ...
    try:
     a[2]
    except KeyError:
     ...
    you still get a type checker error even though this could be normal Python code. Type checkers tend to not like that you write faulty code (regarding typing) and rely on exception catching to come back to the normal path.
  • locals().get("my_variable") and I don't expect a type checker to try and be smart if I start doing this kind of stuff.

So my point is: I don't see the value in doing this for local variables.

That said, using the already existing NotRequired for objects too makes sense :)

Comment options

Unfortunately, this is not a hypothetical. Here is an example of this in the wild, in a reasonably well-known package: https://github.com/perforce/p4python/blob/31ac0a69eb508dcf557c9a620f3a109f8fec5817/P4.py#L124

spec = P4.Spec()
# Attribute names are restricted, so most assignments are disallowed; the following will throw
# spec.foo = "foo"
# This will throw AttributeError, per above
# print(spec.comment)
# But it can be assigned to, which then makes it available
spec.comment = "make it so"
print(spec.comment) # This now prints as expected
You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /