3

I am new to Python but have already read a number of times the principle that everything in Python is an object.

Does that mean that everything is an instance of some class?

As an example, suppose we have a function f. Please then consider running the following.

def f(x):
    return x

print(type(f))

I get <class 'function'>. Does that mean somewhere there is a class called function of which f is an instance? Is it then possible to create a function using g = function(some argument here) as if I had defined the class function myself?

Cabbage
  • 151
  • 4
  • Technically, yes - you could try to instance a function `g` like `g = f.__class__()`, but you'll find it needs a `code` argument and if you have a look at `f.__code__`, you'll quickly find that's not easy to instance - you'd be building a Python compiler, or using the existing one. It's a bad idea - what problem were you hoping to solve with this, because it appears this is an XY problem? – Grismar Dec 28 '20 at 07:46
  • @Grismar Thank you for your comment. I am not solving any specific problems. I am new to Python and I was just trying to understand a bit more about "everything is an object in Python". – Cabbage Dec 28 '20 at 08:00

2 Answers2

2

You can create a function instance by using the def keyword.
It is a subclass of some generic class function. You can compare it to some virtual class which requires to implement the __call__ method.
Using the __call__ method you can use any object as a function:

class Hello:
    def __call__(self, name):
        print(f'Hello {name}')

h = Hello()
print(h('Cabbage')) # -> 'Hello Cabbage'
2

Yes, in Python 3 everything is an object and hence an instance of some class. We can check this explicitly with isinstance.

def f(x):
    return x

print(isinstance(f, object)) # True

Interestingly, the name function is not defined in builtins, but we can use it just fine, as you've already identified, by saying

function = type(f)

It's worth noting that built-in functions and (bound) methods have different types than regular functions.

class A:
  def foo(self):
    pass

print(type(f))      # <class 'function'>
print(type(abs))    # <class 'builtin_function_or_method'>
print(type(A.foo)   # <class 'function'>
print(type(A().foo) # <class 'method'>

We can use help(function) (where function is defined as above) to get some more info on the constructor.

class function(object)
 |  function(code, globals, name=None, argdefs=None, closure=None)
 |  
 |  Create a function object.
 |  
 |  code
 |    a code object
 |  globals
 |    the globals dictionary
 |  name
 |    a string that overrides the name from the code object
 |  argdefs
 |    a tuple that specifies the default argument values
 |  closure
 |    a tuple that supplies the bindings for free variables
 |  
 |  Methods defined here:
 |  
 |  __call__(self, /, *args, **kwargs)
 |      Call self as a function.
 |  
 |  __get__(self, instance, owner, /)
 |      Return an attribute of instance, which is of type owner.
 |  
 |  __repr__(self, /)
 |      Return repr(self).
 |  
 |  ----------------------------------------------------------------------
 |  Static methods defined here:
 |  
 |  __new__(*args, **kwargs) from builtins.type
 |      Create and return a new object.  See help(type) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __annotations__
 |  
 |  __closure__
 |  
 |  __code__
 |  
 |  __defaults__
 |  
 |  __dict__
 |  
 |  __globals__
 |  
 |  __kwdefaults__

As has already been pointed out in the comments, actually calling this behemoth is nontrivial and I can't immediately find any good documentation on how to do so on Python's website.

Silvio Mayolo
  • 62,821
  • 6
  • 74
  • 116