0

I am trying to specify the type for an instance variable using PEP 484's python 2 syntax. However, I haven't found any way to add types without initializing the variable in python 2, equivalent to the following python 3:

value: int

My normal work around for this is to declare the type of the variable in __init__ when instantiating the variable. However, this doesn't work for Protocols where the type of the instance variable should be part of the Protocol (types in __init__ seem to not count). Here's an example in Python 3 where I use a default implementation:

from typing_extensions import Protocol
class A(Protocol):
    value: int

    def get_value(self) -> int:
        return self.value

This would then highlight errors if value isn't initialized properly:

class B(A):
    pass
B()  # error: Cannot instantiate abstract class 'B' with abstract attribute 'value'

However, converting this to python 2 type comments fails to pass mypy. It gives the same error with or without the __init__ declaration.

class A(Protocol):
    def __init__(self):
        # type: () -> None
        self.value = 0  # type: int
    def get_value(self):
        # type: () -> int
        return self.value  # error: "A" has no attribute "value"

Is there some special syntax for declaring variable types without initializing them in python 2?

2
  • I guess that's why Protocol is in typing_extensions in 2.7 rather than typing. Commented Sep 11, 2019 at 10:04
  • 1
    @BoarGules This is an extremely unhelpful comment because it implies this is an explicit decision made in mypy. It seems much more like a bug. Commented Sep 11, 2019 at 17:39

1 Answer 1

1

Mypy's protocols use class variables to define attributes. Otherwise mypy does not make a particularly fine distinction between class vs instance variables. Taking these two things together, you can write code like the following:

from typing_extensions import Protocol

class A(Protocol):
    value = None  # type: int

    def get_value(self):
        # type: () -> int
        return self.value

# below here it's just to validate that the protocol works

class B(object):
    def __init__(self, value):
        # type: (int) -> None
        self.value = value

    def get_value(self):
        # type: () -> int
        return self.value


a = B(42)  # type: A
Sign up to request clarification or add additional context in comments.

3 Comments

This works, to my surprise! A.value is a class variable not an instance variable; however, mypy seems to also accept objects with instance variables as implementing A. Changing B to have def __init__(self): self.value = 42 (instance variable) typechecks fine, which was exactly what I was looking for.
If you update your answer to use an instance variable in B I'll accept this.
Done! I think in the process of updating this answer I started to understand the question better.

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.