Recursive function involving class
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
add a comment |
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
2
If you want to return aset
, why don't you just use aset
?
– 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 notclass.__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
add a comment |
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
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
python class recursion set
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 aset
, why don't you just use aset
?
– 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 notclass.__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
add a comment |
2
If you want to return aset
, why don't you just use aset
?
– 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 notclass.__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
add a comment |
2 Answers
2
active
oldest
votes
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.
add a comment |
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
add a comment |
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
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
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.
add a comment |
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.
add a comment |
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.
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.
edited Nov 25 '18 at 12:29
answered Nov 25 '18 at 11:58
MisterMiyagiMisterMiyagi
7,9862446
7,9862446
add a comment |
add a comment |
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
add a comment |
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
add a comment |
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
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
answered Nov 25 '18 at 12:06
Martijn Pieters♦Martijn Pieters
719k14025112320
719k14025112320
add a comment |
add a comment |
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.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
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
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
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
2
If you want to return a
set
, why don't you just use aset
?– 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