3

A Python install on Linux identifies 187 subclasses of the object class through this query:

kali@kali:~$ python3 -c 'print(len("".__class__.__mro__[1].__subclasses__()))'

The same query in an IDLE shell identifies 342 subclasses, and in the IDE PyCharm only 217!

Can the user decide which subclasses are operative in a given environment, or are subclasses rigorously enforced by the vendor?

rdre8
  • 33
  • 6
  • what do you mean "in the tuple" ? What did you expect ? – azro Jul 09 '22 at 06:35
  • I have edited the original question to clarify. – rdre8 Jul 09 '22 at 08:21
  • Why do you need to understand that ? Some things, if not needed, may be better left unknown :D – azro Jul 09 '22 at 08:23
  • Thanks Azro. Because certain subclasses, such as subprocess.Popen(), are useful but not always available. That's why I am asking if the user can amend the subclasses available in an environment to the full range in Python documentation. You seem like a knowledgeable chap Azro, and i would certainly appreciate your input. – rdre8 Jul 09 '22 at 08:35
  • I've never seen any environement where classes were missing, do you have an example ? – azro Jul 09 '22 at 08:36
  • Hi Azro, I gave an example originally. An IDLE shell has a very full list of 342 subclasses, including subprocess.Popen and subprocess.CompletedProcess. Yet these and many other subclasses are not present on the list of only 187 on a Python3 install in Kali Linux. – rdre8 Jul 09 '22 at 09:01
  • 1
    Kali is a very specialized distribution, and perhaps not representative of Linux in general. – tripleee Jul 09 '22 at 18:47
  • 2
    IDLE shows a lot more subclasses of `object` at startup, because *IDLE is written in Python* - it apparently imports or defines a total of 155 classes. The imported classes are not in any sense "missing" in other environments, they simply haven't been imported and therefore `object` doesn't know about them. – jasonharper Jul 09 '22 at 18:51

1 Answers1

2

When performing the check on various setups it seems your query is based on properties of the object class:

"".__class__.__mro__
(<class 'str'>, <class 'object'>)

Thus your query can be translated as:

len(object.__subclasses__())

Let's rephrase your question as: Why does the count of subclasses of the class object vary with respect to the context?

The key is: Your query literally counts the number of classes inheriting from the class object (read more about this specific class) at the moment of querying and this count definitely depends on your version of python, environment and imports.

For sure initialization of python in both cases are not equivalent as the number of objects inheriting from object are different.

For instance, defining a class depending - explicitly or not - on object is sufficient to change this count:

>>> len(object.__subclasses__())
282
>>> class A(object):
...    pass
...
>>> len(object.__subclasses__())
283
>>> class B:
...     pass
...
>>> len(object.__subclasses__())
284

Importing a package will indeed change this count as well:

>>> import pandas as pd
>>> len(object.__subclasses__())
712

Notice that it also depends on the environment. So basically it depends on the PYTHONPATH and installed modules that can be found in this path:

> activate base
(base) > python -c "print(len(object.__subclasses__()))"
202
(base) > activate test
(test) > python -c "print(len(object.__subclasses__()))"
139

So the answer is almost certainly because the IDLE your ran is not the same python version or it have not the same environment or it has different modules imported than the PyCharm IDE.

As pointed by @jasonharper IDLE might have imported python classes that does increase the count.

So of you need to keep this check you will have to fix the context to make it reproducible. You can use environments or containers with specific images for that. Or design another check that is more resilient.

jlandercy
  • 7,183
  • 1
  • 39
  • 57
  • 1
    I have edited the original question to clarify the problem. – rdre8 Jul 09 '22 at 07:37
  • 1
    @rdre8, I have update my answer to address your updated question. Looking forward for your feedback. – jlandercy Jul 09 '22 at 18:50
  • Thank you jlandercy, the detail was very helpful indeed. I assume that you were switching between two venvs (base and test) in your last example. Can you really switch with the 'activate venv_name' command, because I thought it was a matter of deactivating one first and then using source venv_name/bin/activate to activate the other? – rdre8 Jul 10 '22 at 21:08
  • You are welcome. I used conda in this example which by default deactivate when activating new environment, hence the decrease in count. See nested environment in documentation (https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html#nested-activation). Cheers – jlandercy Jul 10 '22 at 23:39