5

Let's consider any user-defined pythonic class. If I call dir(obect_of_class), I get the list of its attributes:

['__class__', '__delattr__', '__dict__', '__dir__', ... '__weakref__', 'bases', 
'build_full_name', 'candidates', ... 'update_name'].

You can see 2 types of attributes in this list:

  • built-in attributes,
  • user defined.

I need to override __dir__ so, that it will return only user defined attribltes. How I can do that?

It is clear, that if in overridden function I call itself, it gives me infinite recursion. So, I want to do somethig like this:

def __dir__(self):
        return list(filter(lambda x: not re.match('__\S*__', x), dir(self)))

but evade the infinite recursion.

In general, how can I modify a built-in function if I don't want to write it from scratch but want to modify the existing function?

1
  • Did you try using dir(ClassName) instead? Commented Jan 5, 2016 at 16:01

2 Answers 2

9

Use super to call parent's implementation of __dir__; avoid the recursion:

import re


class AClass:

    def __dir__(self):
        return [x for x in super().__dir__() if not re.match(r'__\S+__$', x)]

    def method(self):
        pass

>>> dir(AClass())
['method']
Sign up to request clarification or add additional context in comments.

4 Comments

Why using generators is better than using list(filter...))?
@VeLKerr, It's not a generator, but a list comprehension. For me, it's a lot easier to read.
Ok, it's working, but it's very strange because super()-object hasn't user defined fields. So, could you explain, why it's working?
@VeLKerr, Please follow the link the answer. super.
2

Do you want to do it on your custom class or globally for dir() function?

First approach (class-only):

class MyClass:
    def f(self):
        return None

    def __dir__(self):
        return list(filter(lambda x: not re.match('__\S*__', x), super().__dir__()))


print(dir(MyClass()))  # ['f'] 

Basically what's done here is calling __dir__() of superclass (not class itself) and filtering it in subclass.

Second approach (shadowing global dir function):

import re


def dir(obj):
    return list(filter(lambda x: not re.match('__\S*__', x), __builtins__.dir(obj)))

print(dir({}))  # ['clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']

Here all calls to dir() would be filtered. As you can see - it'll work for all types, including built-in types.

1 Comment

I want to override __dir()__ only for my class, but thanks a lot for the explanation of the global shadowing. P.S. super() works for me even without arguments (I edited the post).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.