Is there I way that I can annotate a function to ensure that an object being passed into the function has a certain method or attribute, but where I don't care about its actual type?
Pycharm internally uses a syntax that looks like {b} to indicate what methods/attributes it's inferred are required for the object, but that doesn't appear to be valid Python syntax:
def func(a: {b}): # Error
a.b = 1
Is there a way to get the type checker to assist in duck typing, where I only care what methods/attributes the object has, not what the type of the objects are, and where I can't modify the types I want to check for?
Protocols can be used. I'm documenting it here because I found this to be a difficult topic to search for; especially checking for the existence of attributes.
For ensuring the presence of an attribute:
from typing import Protocol
class HasFoo(Protocol): # Define what's required
foo: int
class Foo: # This class fulfills the protocol implicitly
def __init__(self):
self.foo = 1
class Bar:
def __init__(self): # This class fails to implicitly fulfill the protocol
self.bar = 2
def foo_func(f: HasFoo):
pass
foo_func(Foo()) # Type check succeeds
foo_func(Bar()) # Type check fails
Note the type hint after foo. It's required for that line to be syntactically valid, and the type must match the inferred type of the checked attributes. typing.Any can be used as a placeholder if you care about the existence of foo, but not its type.
Similarly, the same can be done for checking methods:
class HasFoo(Protocol):
def foo(self):
pass
class Foo:
def foo(self):
pass
class Bar:
def bar(self):
pass
def func(f: HasFoo):
pass
func(Foo()) # Succeeds
func(Bar()) # Fails
Type checking was done via Pycharm 2020.2.2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With