0
def add_info_extractor(self, ie):
    """Add an InfoExtractor object to the end of the list."""
    self._ies.append(ie)
    if not isinstance(ie, type):
        self._ies_instances[ie.ie_key()] = ie
        ie.set_downloader(self)

def get_info_extractor(self, ie_key):
    """
    Get an instance of an IE with name ie_key, it will try to get one from
    the _ies list, if there's no instance it will create a new one and add
    it to the extractor list.
    """
    ie = self._ies_instances.get(ie_key)
    if ie is None:
        ie = get_info_extractor(ie_key)()
        self.add_info_extractor(ie)
    return ie

The following is taken from a popular python repo, the youtube-dl. In an effor to become a better programmer I cam across this section and I'm having trouble understanding it.

Particularly the last method and how it does not enter infinite recursion if the ie_key is not found in the list.

As well as the isinstance comparision in the first method.

I understand the normal implementation is something to the effect of: isinstance('hello', str) , but how can type() be a type? Moreover what's the point of comparing an ie object to type?

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
willredington315
  • 199
  • 1
  • 13

2 Answers2

1

This certainly could cause infinite recursion. No updates seem to happen to self._ies_instances in between recursive calls, and as recursion is dependent on this case, it will continue.

Maybe this is a bug, but the code has never had a situation when ie_key is not in the dictionary?

As for your confusion with type, it's a result of Python Metaclasses (a great read). type acts both as a "function" to return the type of an object as well as a class to create a new type (when called with more arguments).

One reason you may want to check to see if something is an instance of type is to see if something is a metaclass:

>>> isinstance(1, type)
False
>>> isinstance("", type)
False
>>> isinstance({}, type)
False
>>> isinstance((), type)
False
>>> type(object) == type
True
>>> isinstance(object, type)
True
>>> isinstance(object(), type)
False
>>> class a(): pass
...
>>> isinstance(a, type)
False
>>> isinstance(a(), type)
False

As object is the 'base for all new style classes' (docs), it also acts as a metaclass (as shown above).

Community
  • 1
  • 1
alexoneill
  • 503
  • 3
  • 13
1

I believe the reason this avoids infinite recursion is that it never actually recurses at all! Look closely:

def get_info_extractor(self, ie_key):
    ...
    ie = get_info_extractor(ie_key)()

Note that the get_info_extractor whose definition we're reading is a method, and it calls a non-method function that just so happens to also be named get_info_extractor, and so it's not calling itself, and so there's no recursion.

jwodder
  • 54,758
  • 12
  • 108
  • 124