Recursive function involving class












-4















def check_classes(cls):
if len(cls.__bases__) == 0:
return
else:
test_list =
for x in range(len(cls.__bases__)):
test_list += [cls] + check_classes(cls.__bases__[x])
for x in cls.__bases__:
return test_list + [x]


I currently have a recursive function that takes a class as its parameter and returns a list of all base classes. This works fine, but it has many duplicate classes in the list. I want to return a set instead of a list and was wondering how I could go about changing the code to do so.










share|improve this question




















  • 2





    If you want to return a set, why don't you just use a set?

    – MisterMiyagi
    Nov 25 '18 at 11:53











  • use 'return set(test_list + [x])'

    – Dinari
    Nov 25 '18 at 11:54






  • 1





    Why use this at all and not class.__mro__?

    – Martijn Pieters
    Nov 25 '18 at 11:59











  • Don't vanadalize your posts. I have rollbacked to previous sane version.

    – Madhur Bhaiya
    Nov 25 '18 at 12:51
















-4















def check_classes(cls):
if len(cls.__bases__) == 0:
return
else:
test_list =
for x in range(len(cls.__bases__)):
test_list += [cls] + check_classes(cls.__bases__[x])
for x in cls.__bases__:
return test_list + [x]


I currently have a recursive function that takes a class as its parameter and returns a list of all base classes. This works fine, but it has many duplicate classes in the list. I want to return a set instead of a list and was wondering how I could go about changing the code to do so.










share|improve this question




















  • 2





    If you want to return a set, why don't you just use a set?

    – MisterMiyagi
    Nov 25 '18 at 11:53











  • use 'return set(test_list + [x])'

    – Dinari
    Nov 25 '18 at 11:54






  • 1





    Why use this at all and not class.__mro__?

    – Martijn Pieters
    Nov 25 '18 at 11:59











  • Don't vanadalize your posts. I have rollbacked to previous sane version.

    – Madhur Bhaiya
    Nov 25 '18 at 12:51














-4












-4








-4








def check_classes(cls):
if len(cls.__bases__) == 0:
return
else:
test_list =
for x in range(len(cls.__bases__)):
test_list += [cls] + check_classes(cls.__bases__[x])
for x in cls.__bases__:
return test_list + [x]


I currently have a recursive function that takes a class as its parameter and returns a list of all base classes. This works fine, but it has many duplicate classes in the list. I want to return a set instead of a list and was wondering how I could go about changing the code to do so.










share|improve this question
















def check_classes(cls):
if len(cls.__bases__) == 0:
return
else:
test_list =
for x in range(len(cls.__bases__)):
test_list += [cls] + check_classes(cls.__bases__[x])
for x in cls.__bases__:
return test_list + [x]


I currently have a recursive function that takes a class as its parameter and returns a list of all base classes. This works fine, but it has many duplicate classes in the list. I want to return a set instead of a list and was wondering how I could go about changing the code to do so.







python class recursion set






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 26 '18 at 2:13







B. Nguyen

















asked Nov 25 '18 at 11:49









B. NguyenB. Nguyen

83




83








  • 2





    If you want to return a set, why don't you just use a set?

    – MisterMiyagi
    Nov 25 '18 at 11:53











  • use 'return set(test_list + [x])'

    – Dinari
    Nov 25 '18 at 11:54






  • 1





    Why use this at all and not class.__mro__?

    – Martijn Pieters
    Nov 25 '18 at 11:59











  • Don't vanadalize your posts. I have rollbacked to previous sane version.

    – Madhur Bhaiya
    Nov 25 '18 at 12:51














  • 2





    If you want to return a set, why don't you just use a set?

    – MisterMiyagi
    Nov 25 '18 at 11:53











  • use 'return set(test_list + [x])'

    – Dinari
    Nov 25 '18 at 11:54






  • 1





    Why use this at all and not class.__mro__?

    – Martijn Pieters
    Nov 25 '18 at 11:59











  • Don't vanadalize your posts. I have rollbacked to previous sane version.

    – Madhur Bhaiya
    Nov 25 '18 at 12:51








2




2





If you want to return a set, why don't you just use a set?

– MisterMiyagi
Nov 25 '18 at 11:53





If you want to return a set, why don't you just use a set?

– MisterMiyagi
Nov 25 '18 at 11:53













use 'return set(test_list + [x])'

– Dinari
Nov 25 '18 at 11:54





use 'return set(test_list + [x])'

– Dinari
Nov 25 '18 at 11:54




1




1





Why use this at all and not class.__mro__?

– Martijn Pieters
Nov 25 '18 at 11:59





Why use this at all and not class.__mro__?

– Martijn Pieters
Nov 25 '18 at 11:59













Don't vanadalize your posts. I have rollbacked to previous sane version.

– Madhur Bhaiya
Nov 25 '18 at 12:51





Don't vanadalize your posts. I have rollbacked to previous sane version.

– Madhur Bhaiya
Nov 25 '18 at 12:51












2 Answers
2






active

oldest

votes


















3














Python has a builtin set type that eliminates duplicates:



def get_bases(obj):
bases = {obj} # new set including only obj
if not(obj.__bases__): # technically redundant - iter is a noop on empty collections
return bases
else:
for x in obj.__bases__:
bases.update(get_bases(x)) # update set - automatically eliminates duplicates
return bases


This code already avoids adding many duplicates in the first place. However, the set still eliminates duplicates in case of multiple inheritance.



class A: ...
class B1(A): ...
class B2(A): ...
class C(B1, B2): ...
print(get_bases(C))
# {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}




Python being Python, there is already something that does this:



>>> C.__mro__
(__main__.C, __main__.B1, __main__.B2, __main__.A, object)


If you just care about the bases, use __mro__. Its order also expresses how lookup is performed with multiple bases.





A slightly different approach for such searches is to use a set to track duplicates, but a list to store elements:



def get_bases(obj, _dupes=None):
_dupes = _dupes if _dupes is not None else set()
bases = [obj] # new list including only obj
_dupes.add(obj)
for x in obj.__bases__:
if x not in _dupes:
bases.extend(get_bases(x, _dupes)) # update set - automatically eliminates duplicates
return bases


This uses a _dupes: set to check whether you already visited a class. Instead of eliminating classes you added twice, it only adds them once in the first place. A set is faster for this check than a list, given many elements. However, you need the list to preserve order.






share|improve this answer

































    2














    Your function is redundant in that it can be replaced with cls.__mro__:



    >>> class Base: pass
    ...
    >>> class Foo(Base): pass
    ...
    >>> class Bar(Base): pass
    ...
    >>> class Baz(Foo, Bar): pass
    ...

    >>> Baz.__mro__
    (<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>)


    Your biggest issue is that your implementation adds classes to the list twice, once in the recursive call, then again in the current call. Only add the current class to the list. Checking for the __bases__ list as empty is redundant too, as the for loop already not do anything if the sequence is empty.



    So this is enough:



    def check_classes(cls):
    result = [cls]
    for base in cls.__bases__:
    result += check_classes(base)
    return result


    But this will still repeat base classes that have been included in the hierarchy more than once:



    >>> check_classes(Baz)
    [<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>]


    Note that Base and object appear twice, due to multiple inheritance. You could use a set to avoid this:



    def check_classes(cls):
    result = set([cls])
    for base in cls.__bases__:
    result.update(check_classes(base))
    return result


    at which point we lose ordering, but that may be sufficient for your needs:



    >>> check_classes(Baz)
    {<class '__main__.Bar'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Baz'>}


    However, then you could just use set(cls.__mro__) and be done with it:



    >>> check_classes(Baz) == set(Baz.__mro__)
    True





    share|improve this answer























      Your Answer






      StackExchange.ifUsing("editor", function () {
      StackExchange.using("externalEditor", function () {
      StackExchange.using("snippets", function () {
      StackExchange.snippets.init();
      });
      });
      }, "code-snippets");

      StackExchange.ready(function() {
      var channelOptions = {
      tags: "".split(" "),
      id: "1"
      };
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function() {
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled) {
      StackExchange.using("snippets", function() {
      createEditor();
      });
      }
      else {
      createEditor();
      }
      });

      function createEditor() {
      StackExchange.prepareEditor({
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader: {
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      },
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      });


      }
      });














      draft saved

      draft discarded


















      StackExchange.ready(
      function () {
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467125%2frecursive-function-involving-class%23new-answer', 'question_page');
      }
      );

      Post as a guest















      Required, but never shown

























      2 Answers
      2






      active

      oldest

      votes








      2 Answers
      2






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      3














      Python has a builtin set type that eliminates duplicates:



      def get_bases(obj):
      bases = {obj} # new set including only obj
      if not(obj.__bases__): # technically redundant - iter is a noop on empty collections
      return bases
      else:
      for x in obj.__bases__:
      bases.update(get_bases(x)) # update set - automatically eliminates duplicates
      return bases


      This code already avoids adding many duplicates in the first place. However, the set still eliminates duplicates in case of multiple inheritance.



      class A: ...
      class B1(A): ...
      class B2(A): ...
      class C(B1, B2): ...
      print(get_bases(C))
      # {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}




      Python being Python, there is already something that does this:



      >>> C.__mro__
      (__main__.C, __main__.B1, __main__.B2, __main__.A, object)


      If you just care about the bases, use __mro__. Its order also expresses how lookup is performed with multiple bases.





      A slightly different approach for such searches is to use a set to track duplicates, but a list to store elements:



      def get_bases(obj, _dupes=None):
      _dupes = _dupes if _dupes is not None else set()
      bases = [obj] # new list including only obj
      _dupes.add(obj)
      for x in obj.__bases__:
      if x not in _dupes:
      bases.extend(get_bases(x, _dupes)) # update set - automatically eliminates duplicates
      return bases


      This uses a _dupes: set to check whether you already visited a class. Instead of eliminating classes you added twice, it only adds them once in the first place. A set is faster for this check than a list, given many elements. However, you need the list to preserve order.






      share|improve this answer






























        3














        Python has a builtin set type that eliminates duplicates:



        def get_bases(obj):
        bases = {obj} # new set including only obj
        if not(obj.__bases__): # technically redundant - iter is a noop on empty collections
        return bases
        else:
        for x in obj.__bases__:
        bases.update(get_bases(x)) # update set - automatically eliminates duplicates
        return bases


        This code already avoids adding many duplicates in the first place. However, the set still eliminates duplicates in case of multiple inheritance.



        class A: ...
        class B1(A): ...
        class B2(A): ...
        class C(B1, B2): ...
        print(get_bases(C))
        # {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}




        Python being Python, there is already something that does this:



        >>> C.__mro__
        (__main__.C, __main__.B1, __main__.B2, __main__.A, object)


        If you just care about the bases, use __mro__. Its order also expresses how lookup is performed with multiple bases.





        A slightly different approach for such searches is to use a set to track duplicates, but a list to store elements:



        def get_bases(obj, _dupes=None):
        _dupes = _dupes if _dupes is not None else set()
        bases = [obj] # new list including only obj
        _dupes.add(obj)
        for x in obj.__bases__:
        if x not in _dupes:
        bases.extend(get_bases(x, _dupes)) # update set - automatically eliminates duplicates
        return bases


        This uses a _dupes: set to check whether you already visited a class. Instead of eliminating classes you added twice, it only adds them once in the first place. A set is faster for this check than a list, given many elements. However, you need the list to preserve order.






        share|improve this answer




























          3












          3








          3







          Python has a builtin set type that eliminates duplicates:



          def get_bases(obj):
          bases = {obj} # new set including only obj
          if not(obj.__bases__): # technically redundant - iter is a noop on empty collections
          return bases
          else:
          for x in obj.__bases__:
          bases.update(get_bases(x)) # update set - automatically eliminates duplicates
          return bases


          This code already avoids adding many duplicates in the first place. However, the set still eliminates duplicates in case of multiple inheritance.



          class A: ...
          class B1(A): ...
          class B2(A): ...
          class C(B1, B2): ...
          print(get_bases(C))
          # {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}




          Python being Python, there is already something that does this:



          >>> C.__mro__
          (__main__.C, __main__.B1, __main__.B2, __main__.A, object)


          If you just care about the bases, use __mro__. Its order also expresses how lookup is performed with multiple bases.





          A slightly different approach for such searches is to use a set to track duplicates, but a list to store elements:



          def get_bases(obj, _dupes=None):
          _dupes = _dupes if _dupes is not None else set()
          bases = [obj] # new list including only obj
          _dupes.add(obj)
          for x in obj.__bases__:
          if x not in _dupes:
          bases.extend(get_bases(x, _dupes)) # update set - automatically eliminates duplicates
          return bases


          This uses a _dupes: set to check whether you already visited a class. Instead of eliminating classes you added twice, it only adds them once in the first place. A set is faster for this check than a list, given many elements. However, you need the list to preserve order.






          share|improve this answer















          Python has a builtin set type that eliminates duplicates:



          def get_bases(obj):
          bases = {obj} # new set including only obj
          if not(obj.__bases__): # technically redundant - iter is a noop on empty collections
          return bases
          else:
          for x in obj.__bases__:
          bases.update(get_bases(x)) # update set - automatically eliminates duplicates
          return bases


          This code already avoids adding many duplicates in the first place. However, the set still eliminates duplicates in case of multiple inheritance.



          class A: ...
          class B1(A): ...
          class B2(A): ...
          class C(B1, B2): ...
          print(get_bases(C))
          # {<class '__main__.C'>, <class '__main__.B1'>, <class 'object'>, <class '__main__.B2'>, <class '__main__.A'>}




          Python being Python, there is already something that does this:



          >>> C.__mro__
          (__main__.C, __main__.B1, __main__.B2, __main__.A, object)


          If you just care about the bases, use __mro__. Its order also expresses how lookup is performed with multiple bases.





          A slightly different approach for such searches is to use a set to track duplicates, but a list to store elements:



          def get_bases(obj, _dupes=None):
          _dupes = _dupes if _dupes is not None else set()
          bases = [obj] # new list including only obj
          _dupes.add(obj)
          for x in obj.__bases__:
          if x not in _dupes:
          bases.extend(get_bases(x, _dupes)) # update set - automatically eliminates duplicates
          return bases


          This uses a _dupes: set to check whether you already visited a class. Instead of eliminating classes you added twice, it only adds them once in the first place. A set is faster for this check than a list, given many elements. However, you need the list to preserve order.







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Nov 25 '18 at 12:29

























          answered Nov 25 '18 at 11:58









          MisterMiyagiMisterMiyagi

          7,9862446




          7,9862446

























              2














              Your function is redundant in that it can be replaced with cls.__mro__:



              >>> class Base: pass
              ...
              >>> class Foo(Base): pass
              ...
              >>> class Bar(Base): pass
              ...
              >>> class Baz(Foo, Bar): pass
              ...

              >>> Baz.__mro__
              (<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>)


              Your biggest issue is that your implementation adds classes to the list twice, once in the recursive call, then again in the current call. Only add the current class to the list. Checking for the __bases__ list as empty is redundant too, as the for loop already not do anything if the sequence is empty.



              So this is enough:



              def check_classes(cls):
              result = [cls]
              for base in cls.__bases__:
              result += check_classes(base)
              return result


              But this will still repeat base classes that have been included in the hierarchy more than once:



              >>> check_classes(Baz)
              [<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>]


              Note that Base and object appear twice, due to multiple inheritance. You could use a set to avoid this:



              def check_classes(cls):
              result = set([cls])
              for base in cls.__bases__:
              result.update(check_classes(base))
              return result


              at which point we lose ordering, but that may be sufficient for your needs:



              >>> check_classes(Baz)
              {<class '__main__.Bar'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Baz'>}


              However, then you could just use set(cls.__mro__) and be done with it:



              >>> check_classes(Baz) == set(Baz.__mro__)
              True





              share|improve this answer




























                2














                Your function is redundant in that it can be replaced with cls.__mro__:



                >>> class Base: pass
                ...
                >>> class Foo(Base): pass
                ...
                >>> class Bar(Base): pass
                ...
                >>> class Baz(Foo, Bar): pass
                ...

                >>> Baz.__mro__
                (<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>)


                Your biggest issue is that your implementation adds classes to the list twice, once in the recursive call, then again in the current call. Only add the current class to the list. Checking for the __bases__ list as empty is redundant too, as the for loop already not do anything if the sequence is empty.



                So this is enough:



                def check_classes(cls):
                result = [cls]
                for base in cls.__bases__:
                result += check_classes(base)
                return result


                But this will still repeat base classes that have been included in the hierarchy more than once:



                >>> check_classes(Baz)
                [<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>]


                Note that Base and object appear twice, due to multiple inheritance. You could use a set to avoid this:



                def check_classes(cls):
                result = set([cls])
                for base in cls.__bases__:
                result.update(check_classes(base))
                return result


                at which point we lose ordering, but that may be sufficient for your needs:



                >>> check_classes(Baz)
                {<class '__main__.Bar'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Baz'>}


                However, then you could just use set(cls.__mro__) and be done with it:



                >>> check_classes(Baz) == set(Baz.__mro__)
                True





                share|improve this answer


























                  2












                  2








                  2







                  Your function is redundant in that it can be replaced with cls.__mro__:



                  >>> class Base: pass
                  ...
                  >>> class Foo(Base): pass
                  ...
                  >>> class Bar(Base): pass
                  ...
                  >>> class Baz(Foo, Bar): pass
                  ...

                  >>> Baz.__mro__
                  (<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>)


                  Your biggest issue is that your implementation adds classes to the list twice, once in the recursive call, then again in the current call. Only add the current class to the list. Checking for the __bases__ list as empty is redundant too, as the for loop already not do anything if the sequence is empty.



                  So this is enough:



                  def check_classes(cls):
                  result = [cls]
                  for base in cls.__bases__:
                  result += check_classes(base)
                  return result


                  But this will still repeat base classes that have been included in the hierarchy more than once:



                  >>> check_classes(Baz)
                  [<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>]


                  Note that Base and object appear twice, due to multiple inheritance. You could use a set to avoid this:



                  def check_classes(cls):
                  result = set([cls])
                  for base in cls.__bases__:
                  result.update(check_classes(base))
                  return result


                  at which point we lose ordering, but that may be sufficient for your needs:



                  >>> check_classes(Baz)
                  {<class '__main__.Bar'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Baz'>}


                  However, then you could just use set(cls.__mro__) and be done with it:



                  >>> check_classes(Baz) == set(Baz.__mro__)
                  True





                  share|improve this answer













                  Your function is redundant in that it can be replaced with cls.__mro__:



                  >>> class Base: pass
                  ...
                  >>> class Foo(Base): pass
                  ...
                  >>> class Bar(Base): pass
                  ...
                  >>> class Baz(Foo, Bar): pass
                  ...

                  >>> Baz.__mro__
                  (<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>)


                  Your biggest issue is that your implementation adds classes to the list twice, once in the recursive call, then again in the current call. Only add the current class to the list. Checking for the __bases__ list as empty is redundant too, as the for loop already not do anything if the sequence is empty.



                  So this is enough:



                  def check_classes(cls):
                  result = [cls]
                  for base in cls.__bases__:
                  result += check_classes(base)
                  return result


                  But this will still repeat base classes that have been included in the hierarchy more than once:



                  >>> check_classes(Baz)
                  [<class '__main__.Baz'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Bar'>, <class '__main__.Base'>, <class 'object'>]


                  Note that Base and object appear twice, due to multiple inheritance. You could use a set to avoid this:



                  def check_classes(cls):
                  result = set([cls])
                  for base in cls.__bases__:
                  result.update(check_classes(base))
                  return result


                  at which point we lose ordering, but that may be sufficient for your needs:



                  >>> check_classes(Baz)
                  {<class '__main__.Bar'>, <class '__main__.Foo'>, <class '__main__.Base'>, <class 'object'>, <class '__main__.Baz'>}


                  However, then you could just use set(cls.__mro__) and be done with it:



                  >>> check_classes(Baz) == set(Baz.__mro__)
                  True






                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 25 '18 at 12:06









                  Martijn PietersMartijn Pieters

                  719k14025112320




                  719k14025112320






























                      draft saved

                      draft discarded




















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid



                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.


                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function () {
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53467125%2frecursive-function-involving-class%23new-answer', 'question_page');
                      }
                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      Wiesbaden

                      Marschland

                      Dieringhausen