How do you know when looking at the list of attributes and methods listed in a dir which are attributes and which are methods?

StackOverflow https://stackoverflow.com/questions/880160

Question

I am working through trying to learn to program in Python and am focused on getting a better handle on how to use Standard and other modules. The dir function seems really powerful in the interpreter but I wonder if I am missing something because of my lack of OOP background. Using S.Lotts book I decided to use his Die class to learn more about syntax and use of classes and instances.

Here is the original code:

class Die(object):
''' simulate a six-sided die '''
def roll(self):
    self.value=random.randrange(1,7)
    return self.value
def getValue(self):
    return self.value

I was looking at that and after creating some instances I wondered if the word value was a keyword somehow and what the use of the word object in the class statement did and so I decided to find out by changing the class definition to the following:

class Die():
''' simulate a six-sided die '''
def roll(self):
    self.ban=random.randrange(1,7)
    return self.ban
def getValue(self):
    return self.ban

That change showed me that I got the same behavior from my instances but the following methods/attributes were missing from the instances when I did dir:

'__class__', '__delattr__', '__dict__', '__doc__', '__getattribute__',
 '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__',
_repr__', '__setattr__', '__str__', '__weakref__'

I also figured out that when I did a dir on an instance I had an additional keyword-ban which I finally figured out was an attribute of my instance. This helped me understand that I could use d1.ban to access the value of my instance. The only reason I could figure out that this was an attribute was I typed d1.happy and got an AttributeError I figured out that d1.GetValue was a method attached to Die because that is what the interpreter told me.

So when I am trying to use some complicated but helpful module like BeautifulSoup how can I know which of the things that are listed are attributes of my instance or methods of my instance after typing dir(instance). I would need to know this because this poking around has taught me that with attributes I am calling the result of a method and with methods I am invoking a function on my instance.

This question is probably too wordy but it sure did help me better understand the difference between attributes and methods. Specifically, when I look at the result of calling dir on an instance of my Die class I see this

['__doc__', '__module__', 'ban', 'getValue', 'roll']

So it would seem useful to know by looking at that list which are attributes and which are methods without having to resort to trial and error or result to typing in hasattr(myInstance,suspectedAttributeName).

After posting the question I tried

for each in dir(d1):
    print hasattr(d1,each)

which tells me strictly speaking that all methods are attributes. but I can't call a method without the () so it seems to me that the hasattr() is misleading.

Was it helpful?

Solution

Instead of: "print hasattr(d1,each)", try: "print each, type(getattr(d1,each))". You should find the results informative.

Also, in place of dir() try help(), which I think you're really looking for.

OTHER TIPS

Consider using the standard library's inspect module -- it's often the handiest approach to introspection, packaging up substantial chunks of functionality (you could implement that from scratch, but reusing well-tested, well-designed code is a good thing). See http://docs.python.org/library/inspect.html for all the details, but for example inspect.getmembers(foo, inspect.ismethod) is an excellent way to get all methods of foo (you'll get (name, value) pairs sorted by name).

which tells me strictly speaking that all methods are attributes. but I can't call a method without the () so it seems to me that the hasattr() is misleading.

Why is it misleading? If obj.ban() is a method, then obj.ban is the corresponding attribute. You can have code like this:

print obj.getValue()

or

get = obj.getValue
print get()

If you want to get a list of methods on an object, you can try this function. It's not perfect, since it will also trigger for callable attributes that aren't methods, but for 99% of cases should be good enough:

def methods(obj):
    attrs = (getattr(obj, n) for n in dir(obj))
    return [a for a in attrs if a.hasattr("__call__")]

This info module inspired from Dive into Python serves the purpose.

def info(obj, spacing=20, collapse=1, variables=False):
    '''Print methods and their doc Strings

    Takes any object'''
    if variables:
    methodList = [method for method in dir(obj)]
    else:
    methodList = [method for method in dir(obj) if callable(getattr(obj,method))]

    #print methodList


    print '\n'.join(['%s %s' %
            (method.ljust(spacing),
             " ".join(str(getattr(obj,method).__doc__).split()))
            for method in methodList])


if __name__=='__main__':
    info(list)

There is a built in method called callable. You can apply it to any object and it will return True/False depending on if it can be called. e.g.

>>> def foo():
...   print "This is the only function now"
...
>>> localDictionary = dir()
>>> for item in localDictionary:
...   print repr(item) + "is callable: " + str(callable(locals()[item]))
'__builtins__'is callable: False
'__doc__'is callable: False
'__name__'is callable: False
'foo'is callable: True

Note the locals() call will return a dictionary containing everything defined in your current scope. I did this because the items out of the dictionary are just strings, and we need to run callable on the actual object.

Ideally, when using a complicated library like BeautifulSoup, you should consult its documentation to see what methods each class provides. However, in the rare case where you don't have easily accessible documentation, you can check for the presence of methods using the following.

All methods, which themselves are objects, implement the __call__ method and can be checked using the callable() method which returns True, if the value being checked has the __call__ method.

The following code should work.

x = Die()
x.roll()

for attribute in dir(x) :
    print attribute, callable(getattr(x, attribute))

The above code would return true for all the methods and false for all non callable attributes (such as data members like ban). However, this method also returns True for any callable objects (like inner classes). you can also check if the type of the attribute is instancemethod

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top