1

I found a pyi file which has the following def

def most_common(self, n: Optional[int] = ...) -> List[Tuple[_T, int]]: ...

How could this happen? List is not defined, and no implementation?


Just highlight some valuable suggestions here for followers:

List is imported from the typing module; it's not the same thing as list. The .pyi file doesn't need to import it because stub files are never executed; they just have to be syntactically valid Python

If you use from future import annotations, you won't have to import typing to use List et al. in function annotations in .py files, either, since function annotations will be treated as string literals. (Starting in Python 4, that will be the default behavior. See PEP 563 for details.)

Pythoner
  • 5,265
  • 5
  • 33
  • 49
  • How could what happen? Stub files aren't used by Python itself, only static checkers like `mypy`. – chepner Apr 16 '19 at 19:56

1 Answers1

2

You are looking at the pyi file which is used solely for annotations. It is never executed by the Python interpreter. You can learn more about pyi files by reading PEP484.

Using a debugger, put a breakpoint on the line where you call most_commonand then step into the method.

Python 3.7 implementation.

...\Lib\collections\__init__.py:

def most_common(self, n=None):
    '''List the n most common elements and their counts from the most
    common to the least.  If n is None, then list all element counts.

    >>> Counter('abcdeabcdabcaba').most_common(3)
    [('a', 5), ('b', 4), ('c', 3)]

    '''
    # Emulate Bag.sortedByCount from Smalltalk
    if n is None:
        return sorted(self.items(), key=_itemgetter(1), reverse=True)
    return _heapq.nlargest(n, self.items(), key=_itemgetter(1))

_heapq.nlargest (in ...\Lib\heapq.py) implementation:

def nlargest(n, iterable, key=None):
    """Find the n largest elements in a dataset.

    Equivalent to:  sorted(iterable, key=key, reverse=True)[:n]
    """

    # Short-cut for n==1 is to use max()
    if n == 1:
        it = iter(iterable)
        sentinel = object()
        if key is None:
            result = max(it, default=sentinel)
        else:
            result = max(it, default=sentinel, key=key)
        return [] if result is sentinel else [result]

    # When n>=size, it's faster to use sorted()
    try:
        size = len(iterable)
    except (TypeError, AttributeError):
        pass
    else:
        if n >= size:
            return sorted(iterable, key=key, reverse=True)[:n]

    # When key is none, use simpler decoration
    if key is None:
        it = iter(iterable)
        result = [(elem, i) for i, elem in zip(range(0, -n, -1), it)]
        if not result:
            return result
        heapify(result)
        top = result[0][0]
        order = -n
        _heapreplace = heapreplace
        for elem in it:
            if top < elem:
                _heapreplace(result, (elem, order))
                top, _order = result[0]
                order -= 1
        result.sort(reverse=True)
        return [elem for (elem, order) in result]

    # General case, slowest method
    it = iter(iterable)
    result = [(key(elem), i, elem) for i, elem in zip(range(0, -n, -1), it)]
    if not result:
        return result
    heapify(result)
    top = result[0][0]
    order = -n
    _heapreplace = heapreplace
    for elem in it:
        k = key(elem)
        if top < k:
            _heapreplace(result, (k, order, elem))
            top, _order, _elem = result[0]
            order -= 1
    result.sort(reverse=True)
    return [elem for (k, order, elem) in result]
DeepSpace
  • 78,697
  • 11
  • 109
  • 154
  • This looks to be python2, check out their python3 def file here. https://github.com/python/typeshed/blob/master/stdlib/3/collections/__init__.pyi – Pythoner Apr 16 '19 at 19:55
  • @Pythoner It's Python 3.7, not 2 – DeepSpace Apr 16 '19 at 19:56
  • @Pythoner You are looking at the pyi file which is used solely for typing annotations – DeepSpace Apr 16 '19 at 19:57
  • Thanks, can you elaborate more on how do you find the source? I used pycharm ide, it directed me to that pyi file, and I could barely understand their grammer? – Pythoner Apr 16 '19 at 19:57
  • 1
    @Pythoner I used the debugger in Pycharm. Put a breakpoint on the line where you call `most_common` and then step into the method. – DeepSpace Apr 16 '19 at 20:00
  • 1
    @Pythoner The stub file is meant to be used in conjunction with https://github.com/python/cpython/blob/3.7/Lib/collections/__init__.py. – chepner Apr 16 '19 at 20:00
  • Good to know, I found it on external lib, one more question here, is this grammer supported in python3? -> List[Tuple[_T, int]], is there a Backus-Naur Form? – Pythoner Apr 16 '19 at 20:03
  • That's just the return value part of a function annotation, supported since Python 3. – chepner Apr 16 '19 at 20:04
  • @chepner, why is 'list' becoming 'List', not compliable any more in my IDE. – Pythoner Apr 16 '19 at 20:11
  • 1
    @DeepSpace, very nice and detailed anwser, thanks so much! – Pythoner Apr 16 '19 at 20:12
  • 1
    `List` is imported from the `typing` module; it's not the same thing as `list`. The `.pyi` file doesn't need to import it because stub files are never *executed*; they just have to be *syntactically* valid Python. – chepner Apr 16 '19 at 20:14
  • 1
    If you use `from __future__ import annotations`, you won't have to import `typing` to use `List` et al. in function annotations in `.py` files, either, since function annotations will be treated as string literals. (Starting in Python 4, that will be the default behavior. See [PEP 563](https://www.python.org/dev/peps/pep-0563/) for details.) – chepner Apr 16 '19 at 20:16
  • @chepner, very nice to know, updated in my question list, valuable suggestions. – Pythoner Apr 17 '19 at 14:47