Edit: I misunderstood the feature currently. It's not designed for multiple dispatch:
NOTE: While it would be possible to provide a multiple dispatch implementation using this syntax, its implementation would require using sys._getframe() , which is frowned upon. Also, designing and implementing an efficient multiple dispatch mechanism is hard, which is why previous attempts were abandoned in favor of functools.singledispatch() . (See PEP 443 , especially its section "Alternative approaches".) In the future we may come up with a satisfactory multiple dispatch design, but we don't want such a design to be constrained by the overloading syntax defined for type hints in stub files. It is also possible that both features will develop independent from each other (since overloading in the type checker has different use cases and requirements than multiple dispatch at runtime -- e.g. the latter is unlikely to support generic types).
====
I've been off in Java-land for a while, and I'm returning to Python 3.5. I want to use the new type hinting feature, but I'm having trouble with method overloading. From my reading of the feature, this should be supported.
Here's a quick little class that I'm working on:
licensing.pyi (note the pyi)
import typing
import gitlab
class LicensingChecker(object):
@typing.overload
def __init__(self, url: str, api_key: str) -> None: ...
@typing.overload
def __init__(self, gl: gitlab.Gitlab) -> None: ...
def iter_projects(self) -> typing.Iterator[str]: ...
licensing.py
import gitlab
import string
class LicenseChecker(object):
def __init__(self, gl):
self.gl = gl
def __init__(self, url, api_key):
self.gl = gitlab.Gitlab(url, api_key)
def iter_projects(self):
p = set()
for i in string.ascii_lowercase:
for x in self.gl.projects.search(i):
if x not in p:
p.add(x)
yield x.name
This is a toy example, but the idea is rather conventional. I provide two constructors one that takes an already existing gitlab client and another that will instantiate it. (There's no need for dual constructors for this script, but I saw @typing.overload
and wanted to see how it works.)
Pycharm and Cpython seem to be happy with this code, but the first constructor is inaccessible -- like @typing.overload
decorator isn't working:
>>> import gitlab
>>> import licensing
>>> licensing.LicenseChecker(gitlab.Gitlab('https://blah.blah.blah/gitlab', 'hunter2'))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: __init__() missing 1 required positional argument: 'api_key'
Is there something special I have to do to get the overloading working? Presently, I'm just invoking either the built-in REPL or ipython.
PEP 484 introduced type hints — a way to make Python feel statically typed. While type hints can help structure your projects better, they are just that — hints — and by default do not affect the runtime.
Type hints work best in modern Pythons. Annotations were introduced in Python 3.0, and it's possible to use type comments in Python 2.7. Still, improvements like variable annotations and postponed evaluation of type hints mean that you'll have a better experience doing type checks using Python 3.6 or even Python 3.7.
Dart doesn't have overloading as it is our experience that overloading leads to confusion. Especially when you intend to override a method but accidentally overload it. We think that optional arguments (named or not) are a better alternative. Overloading is orthogonal to type annotations.
Method Overloading allows us to write different versions of a method (i.e. a single class can contain more than one methods (Sub / Functions) of same name but of different implementation). And compiler will automatically select the appropriate method based on parameters passed.
Method Overloading is a Compile time polymorphism. In method overloading, more than one method shares the same method name with different signature in the class.
Method Overriding: Method Overriding is a Run time polymorphism. In method overriding, derived class provides the specific implementation of the method that is already provided by the base class or parent class. In method overriding, return type must be same or co-variant (return type may vary in same direction as the derived class).
There is an overloading package for Python 3.5+. Whith this package, it's possible to redefined methods, but with distinct type hints and its decorator will find out, which overloaded method should be called.
When Mypy checks the file, it collects the @overload definitions as type hints. It then uses the first non- @overload definition as the implementation. All @overload definitions must come before the implementation, and multiple implementations are not allowed.
Untyped Python does not support overloading. Your second __init__
is overwriting the first one, thus the error. You need to write a single __init__
with runtime type-checking:
def __init__(self, arg1, arg2=None):
if isinstance(arg1, gitlab.Gitlab) and arg2 is None:
self.gl = arg1
elif arg1 is not None and arg2 is not None:
self.gl = gitlab.Gitlab(arg1, arg2)
else:
raise TypeError('........')
(there is functools.singledispatch
which can simulate overloading with only one argument changing type but it is not suitable for your case)
The @typing.overload
decorator just tells the type checker there can be multiple combinations of arguments, it does not mean you could write the implementation in two different functions with the same name now. From PEP 484:
Uses of the
@overload
decorator as shown above are suitable for stub files. In regular modules, a series of@overload
-decorated definitions must be followed by exactly one non-@overload
-decorated definition (for the same function/method). The@overload
-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-@overload
-decorated definition, while the latter is used at runtime but should be ignored by a type checker.
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