How do I check if method is a class?

Type() or isinstance() doesn’t work here, because it always points out missing position arguments. So if I have for example something like super(), how can I get the information, whether it is a class or not?

Here is a simple way to test what something is via introspection.

# Create function
def abc():
    pass

abc.__class__
<class 'function'>

# Create class
class Something:
    pass

Something.__class__
<class 'type'>

# Create instance of class
one_instance = Something()

one_instance.__class__
<class '__main__.Something'>

# type() does work.  Try lowercase.
type(abc)
<class 'function'>

type(Something)
<class 'type'>

type(is_instance)
<class '__main__.Something'>

1 Like

I think you are using some of the terms a bit sloppy and I am not quite sure what you are asking. What do you mean with “method”? Normally methods are functions attached to a class that automatically get based in self or cls when accessed. But I don’t think that is the meaning you are using.

Can you maybe provide an example of where you want to make the distinction and why?

2 Likes

I think you are asking if there is a way to retrieve information about whether or not an object is callable, and what arguments it expects if it is. In general, no. You can use inspect.signature to get information for user-defined functions and classes, but this information is generally not available for built-in callables.

It generally is available, and if not, report that as a bug in CPython. __text_signature__ should be set where possible.

Looks like Add inspect.signature support for more builtins · Issue #107161 · python/cpython · GitHub is currently open.

well, in Geany super() is red and a class is blue :face_with_peeking_eye:

1 Like

You can in a way reverse engineer by checking what attributes are defined inside a class:

class SomeClass:

    def __init__(self, attr1, attr2):

        self.attr1 = attr1
        self.attr2 = attr2

    def some_method(self):

        print('Yes, I am a class function (ahem, method).')

some_object = SomeClass(1,2)

# Check object (or class, indirectly) attributes
class_attributes = list(name for name in dir(some_object) if not name.startswith('__'))

print(class_attributes)

# Run results
>>> ['attr1', 'attr2', 'some_method']

I am going to assume that there was a typo in the issue title and that you meant ‘... in a class’ as opposed to ‘... is a class’. Otherwise, that would be like asking: “How can you tell if an apple is an orange”, which wouldn’t make sense. They are two completely different things.

This of course assumes that you aren’t searching for dunder based methods.

Actually, it is possible. I am in the process of learning Python, so I am sorry for any naming errors. This question is just an interest and there is no particular problem or code behind it. As functions and classes may have the same notation in the code, I am simply wondering whether I am able to decide on their nature, whether they are just methods or classes. Sometimes I still feel confused about the location of a certain object in the structure, so it would be helpful to know, what I am dealing with.

Well, I am not sure if this is what I am looking for. Attribute __class__ tels me a type. I dont need to know the type of the object, I am fine just if it is a class, or better to say if it is an instance of a class.

I dont know, I am asking if an object is an instance of a class. For example __class__ looks like a method, but it is not a method. Same could be with classes as you can missmatch them with methods. So there should be a programatic way - instead of looking into the core or module code - what they literary are.

The result <class 'type'> means that Something is a type. You didn’t ask for the type of some Something instance; you asked for the type of Something itself. For everything that you create with class, that type is type, unless you use the metaclass hooks to change that.

It’s really important to make sure you properly distinguish between classes themselves, and instances of those classes.

It’s also really important that you understand that classes define types. When you say “x is a Foo instance”, that means the same thing as saying “the type of x is Foo”.

It’s also really important that you understand that Python takes “everything is an object” very seriously. In Python, classes are, themselves, objects. And type is the name for the type that they have, which is to say, the name of the class of which they are instances.

(This, of course, implies that type is an object. And, yes, it has a type: itself.)

Every object is an instance of a type - although some of those types might not be implemented using the class keyword in Python. The distinction between built-in types and types created using class is usually not significant.

So I did some research and it looks like in Python is not so straightforward. Some core objects may be encoded into C, so I cannot mine from Python code easily.

That takes me back to Python documentation, which unfortunately have a very poor index so it is sometimes hard to dig the information in its structure. Or help() which is neither of 100% success. It provided some region of code for str, super but not for __class__.

It’s still not clear to me what practical problem you hope to solve by performing this check, so it’s hard to be precise about the logic for the check.

Whether or not some core object types are implemented in C is not important here. On the Python level - in Python code - they would still be Python classes (=types).

I may be repeating what others have already said, but perhaps this still helps:

  • Everything you can refer to by name is an object.
  • object is the parent object type of all objects (including itself).
  • To find out the specific class (=type) of any object x, you can call type(x).
  • Every class (or type) is itself also an object, an instance of the class with the name type.
  • To find out the class hierarchy of some class, you can call mro.
  • Functions and methods are also objects:
def fun():
     pass
class A:
     pass

>>> type(fun)
<class 'function'>
>>> type(fun).mro()
[<class 'function'>, <class 'object'>]

>>> x = A()
>>> type(x)
<class '__main__.A'>
>>> type(type(x))  # same as type(A)
<class 'type'>
>>> type(A)
<class 'type'>
>>> A.mro()
[<class '__main__.A'>, <class 'object'>]
1 Like

At runtime, there is no distinction between “type” and “class”, like there was in Python 2. (Static type hinting has reintroduced a distinction that’s best left undiscussed here.)

All objects are instances of some class. That’s what type tells you. Related is the isinstance function, which tells you if a given value is an instance of a given class.

The two are not quite identical. Every object has one class from which it was instantiated, which is that type tells you. Every object, however, can be considered an instance of at least one class, due to inheritance. For example, because int is a subclass of object:

>>> type(3)
<class 'int'>
>>> isinstance(3, int)
True
>>> isinstance(3, object)
True

Even classes are instance of some class, namely of type (or a subclass of type, if you get into metaclasses).

>>> type(int)
<class 'type'>

If you want to tie your brain into a knot, consider this:

>>> type(type)
<class 'type'>

type is an instance of itself.


Also, you are confusing “method” with “attribute”. __class__ is indeed an attribute, but it is not a method. Given a definition like

class Foo:
    def bar(self):
        ...

we see the class attribute Foo.bar has as its value a function; it’s this function that we (informally) refer to as a method. (If you want to get formal, we’d have to start talking about the descriptor protocol, but let’s not do that here; it’s getting too far afield from your question.)

1 Like