Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

3.5: Type Hinting and Method Overloading

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.

like image 490
fandingo Avatar asked May 31 '16 18:05

fandingo


People also ask

What is the purpose of type hinting in Python?

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.

Should I use type hinting in Python?

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.

Is there method overloading in Dart?

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.

What is method overloading in VB net?

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.

What is method overloading in Java?

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.

What is method overriding?

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).

Is it possible to overload a method in Python?

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.

How does mypy handle multiple @overload definitions?

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.


1 Answers

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.

like image 121
kennytm Avatar answered Oct 12 '22 21:10

kennytm