5

hasattr documentation says that it takes an object and an attribute name and lets you know if that attribute exists on that object.

I have discovered that it seems to work on class names too (i.e. not an instance object).

Something like:

class A:
    def Attr1(self):
        pass

> hasattr(A, 'Attr1')
True
> 

I would like to use this to make some test code easier to write, but don't want to be bitten later in case this is a side effect of the implementation and not really intended.

Please don't ask to see the test code to see if I can do something else, as that is not really the question.

Is there any official python stance on this? I presume the object referred to, in the documentation is talking about an instance object.

I tried googling (and looking at some questions in StackOverflow), but didn't seem to find anything.

  • 2
    *"I presume the object referred to, in the documentation is talking about an instance object"* - no, any object, including the class itself. – jonrsharpe Apr 27 '15 at 16:07
  • 1
    That's normal. Remember that `instance.method(stuff ...)` is in fact syntactic sugar for `Class.method(instance, stuff ...)`, i.e. those methods are in fact attributes of the class. – tobias_k Apr 27 '15 at 16:08
  • @jonrsharpe: That is great! Is there any reference for that. Seems a bit strange to me :-) – Programmer Person Apr 27 '15 at 16:10
  • @ProgrammerPerson if the documentation meant a specific kind of object, it would say that. *Everything in Python is an object*; you can run `hasattr` on anything. – jonrsharpe Apr 27 '15 at 16:11
  • @tobias_k: I understand that methods are attributes. What I am worried about is using `hasattr(A, blah)`, instead of `hasattr(x, blah)` where `x = A()`. – Programmer Person Apr 27 '15 at 16:11
  • 1
    Classes *are* instance objects; they are instances of `type` (or whatever the metaclass of the class is). – chepner Apr 27 '15 at 16:13
  • @jonrsharpe: I am not disputing :-). Just want a reference (even for the sentence that everything is an object...) Asyou can tell, I am new to python... – Programmer Person Apr 27 '15 at 16:14
  • 1
    @ProgrammerPerson oh, come on; first Google hit for *"python everything is an object"*: http://stackoverflow.com/q/865911/3001761 – jonrsharpe Apr 27 '15 at 16:16
  • @jonrsharpe: Come on :-). Everything is an object has multiple interpretations. Like 5 is an object. Do you include: Type T is an object? chepner's comment comes close to an answer for that. – Programmer Person Apr 27 '15 at 16:25
  • btw, thanks everyone! I will wait a few hours before accepting an answer. – Programmer Person Apr 27 '15 at 16:25
  • @ProgrammerPerson there's no *"interpretation"* here. `5` is an `int` object. `int` is a `type` object. Functions, classes, modules; all are objects of various kinds. Python is *wholly object-oriented*, it doesn't have the "primitive" data types of e.g. Java. – jonrsharpe Apr 27 '15 at 16:29
  • @jonrsharpe: There is, for someone new to python coming from other languages. Hence the confusion. I can understand saying every thing that can be passed around (including functions) are objects. But class names could still be considered non-objects. Anyway, seems like my question has been answered. – Programmer Person Apr 27 '15 at 19:47

3 Answers3

7

The fact that it works on a class in addition to an instance is intentional. In fact, hasattr should work on any object that you pass to it. Basically, it does something like this:

def hasattr(obj, attribute):
    try:
        getattr(obj, attribute)
    except:
        return False
    return True

You can rely on that and not be afraid of getting bit by a change later. Note, there is some discussion on python-dev about hasattr being broken by design. The gist of it is that hasattr catches any exception which can be misleading.


Note that, in python classes are themselves instances of type.

>>> class Foo(object):
...   pass
... 
>>> type(Foo)
<type 'type'>

so everything is an instance of something1.

1type is an instance of itself which is something that would be impossible to do in pure python...

mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Interesting. I didn't realize `hasattr()` was broken like that. – Kevin Apr 27 '15 at 18:46
  • @Kevin -- Yep. I've even seen people mention that it'll catch crazy stuff like `StopIteration` and `SystemExit` -- But I'm not sure if that's true. In any event, I've seen a number of people writing their own versions... `return getattr(obj, attr, sentinel) is not sentinel` – mgilson Apr 27 '15 at 18:47
  • I just looked into this and it's [apparently fixed in 3.2](https://bugs.python.org/issue9666)... no word on whether 2.7 users are out of luck. – Kevin Apr 27 '15 at 18:49
  • Your second paragraph answers it for me. – Programmer Person Apr 27 '15 at 19:49
3

I do not have a reference on the "official Python stance" at hand, but this is perfectly normal and intentional. Remember that

instance_of_SomeClass.some_method(parameters, ...)

is in fact syntactic sugar for

SomeClass.some_method(instance_of_SomeClass, parameters, ...)

i.e. those methods are in fact attributes of the class and thus can be tested with hasattr.

tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • Good explanation. Gives the answer as to why methods are attributes of a class. That is, class attributes. – Nameless Apr 01 '21 at 23:49
1

Just want a reference (even for the sentence that everything is an object...)

I recommend you to read this chapter (or the whole book if you have the time):

http://www.diveintopython.net/getting_to_know_python/everything_is_an_object.html

geckon
  • 8,316
  • 4
  • 35
  • 59