rnd om
rnd om

Reputation: 355

how do i filter for only instance methods - not class methods

working through "Learning Python: Powerful Object-Oriented Programming'

chapter 28 has you create a class that will list all instance attributes of an object.

then the book offers some ideas, such as listing all attributes up the inheritance tree. when doing so, i used the @classmethod decorator shown below - and was wondering if there's a way to filter those types of methods out of my listing:

"""Assorted class utilities and tools"""


class ShowAttrs(object):
    """
    A class to show all available (including inherited, excluding special) attributes
    """
    @classmethod
    def getAttrs(cls, child_cls):
        my_attrs = [_ for _ in child_cls.__dict__ if _.startswith('_') is False]
        my_name = child_cls.__name__
        listed_attrs = [my_name + ': ' + ', '.join(my_attrs)]
        try:
            bases = child_cls.__bases__
            inherited_attrs = []
            for base in bases[::-1]:
                if base.__name__ != 'ShowAttrs' and base.__name__ != 'object':
                    inherited_lists = [ShowAttrs.getAttrs(base)]
                    for _ in inherited_lists:
                        inherited_attrs.extend(_)
        except NameError:
            return
        inherited_attrs.extend(listed_attrs)
        return inherited_attrs

    def __repr__(self):
        child_cls = self.__class__
        all_attrs = ShowAttrs.getAttrs(child_cls)
        len_attrs = reversed(list(range(len(all_attrs))))
        all_attrs_unique = [ x for i,x in zip(len_attrs,all_attrs[::-1]) if i <= all_attrs.index(x) ]
        return '\n'.join(reversed(all_attrs_unique))


if __name__ == '__main__':


    class Parent(ShowAttrs):
        var3 = 'Parent'

        def parentMethod(self):
            print('this is a Parent')

    class Child(Parent):
        var2 = 'Child'

        def childMethod(self):
            print('this is a Child')


    class GrandChild(Child):
        var1 = 'GrandChild'

        @classmethod
        def howCanIFilterThisOneOut(cls):
            pass

        def grandchildMethod(self):
            print('this is a GrandChild')

        def grandchildMethod2(self):
            pass

        def grandchildMethod3(self):
            pass

    class GrandChild2(Child):
        var11 = 'GrandChild2'


    class GreatGrandChild(GrandChild, GrandChild2):
        var0 = 'GreatGrandChild'

    x = GreatGrandChild()
    print(x)

when i run this:

Python 3 x = GreatGrandChild() print(x)

Console 
Parent: var3, parentMethod
Child: var2, childMethod
GrandChild2: var11
GrandChild: var1,howCanIFilterThisOneOut, grandchildMethod, grandchildMethod2, grandchildMethod3
GreatGrandChild: var0

but howCanIFilterThisOneOut is a classmethod, not an instance method. so just wondering if it's possible to differentiate.

thanks

sandbox to try it: https://edube.org/sandbox/af4390bc-77aa-11ec-ab3f-0242157e55ca

Upvotes: 0

Views: 155

Answers (1)

AKX
AKX

Reputation: 169184

isinstance(x, classmethod) does the trick.

my_attrs = [
  name for (name, value) 
  in child_cls.__dict__.items() 
  if not name.startswith('_') and not isinstance(value, classmethod)
]

As an aside, your code could simplify, with duplicate removal and all, into something like

import inspect

def get_fields(cls):
    seen = set()
    for cls in inspect.getmro(cls)[::-1]:
        if cls is object:
            continue
        attr_names = {
            name
            for name in cls.__dict__
            if name not in seen and not name.startswith("_")
        }
        seen.update(attr_names)
        yield (cls.__name__, sorted(attr_names))

Upvotes: 1

Related Questions