Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #37682 > unrolled thread
| Started by | lars van gemerden <lars@rational-it.com> |
|---|---|
| First post | 2013-01-25 09:40 -0800 |
| Last post | 2013-01-25 12:08 -0800 |
| Articles | 9 — 3 participants |
Back to article view | Back to comp.lang.python
finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 09:40 -0800
Re: finding abc's Ian Kelly <ian.g.kelly@gmail.com> - 2013-01-25 12:04 -0700
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 12:05 -0800
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 12:05 -0800
Re: finding abc's Peter Otten <__peter__@web.de> - 2013-01-25 20:08 +0100
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 12:08 -0800
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 16:48 -0800
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 16:48 -0800
Re: finding abc's lars van gemerden <lars@rational-it.com> - 2013-01-25 12:08 -0800
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 09:40 -0800 |
| Subject | finding abc's |
| Message-ID | <766ec7eb-ab43-4c17-8073-3a0e6a8b89ea@googlegroups.com> |
Hi all,
i was writing a function to determine the common base class of a number classes:
def common_base(classes):
if not len(classes):
return None
common = set(classes.pop().mro())
for cls in classes:
common.intersection_update(cls.mro())
while len(common) > 1:
cls1 = common.pop()
cls2 = common.pop()
if issubclass(cls1, cls2):
common.add(cls1)
elif issubclass(cls2, cls1):
common.add(cls2)
return common.pop()
and ran common_base(int, float), hoping to get numbers.Number.
this did not work because abstract base classes are not always in the mro() of classes.
My question is: is there a way to obtain the abc's of a class or otherwise a way to make the function above take abc's into account (maybe via a predefined function)?
Cheers, Lars
[toc] | [next] | [standalone]
| From | Ian Kelly <ian.g.kelly@gmail.com> |
|---|---|
| Date | 2013-01-25 12:04 -0700 |
| Message-ID | <mailman.1051.1359140711.2939.python-list@python.org> |
| In reply to | #37682 |
On Fri, Jan 25, 2013 at 10:40 AM, lars van gemerden <lars@rational-it.com> wrote: > Hi all, > > i was writing a function to determine the common base class of a number classes: > [...] > > and ran common_base(int, float), hoping to get numbers.Number. > > this did not work because abstract base classes are not always in the mro() of classes. > > My question is: is there a way to obtain the abc's of a class or otherwise a way to make the function above take abc's into account (maybe via a predefined function)? If the abstract base class's module has not been imported, it may not even be loaded into memory, even though it is technically considered a superclass. Consider this: Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit (Intel)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>> def common_base(classes): ... common = set() ... for cls in object.__subclasses__(): ... if all(issubclass(c, cls) for c in classes): ... common.add(cls) ... return common ... >>> common_base([int, float]) set([<class '_abcoll.Hashable'>]) >>> import numbers >>> common_base([int, float]) set([<class 'numbers.Number'>, <class '_abcoll.Hashable'>]) If you're okay with that, then the approach above might work. > while len(common) > 1: > cls1 = common.pop() > cls2 = common.pop() > if issubclass(cls1, cls2): > common.add(cls1) > elif issubclass(cls2, cls1): > common.add(cls2) There is a flaw with your set reduction code here. If neither class is a subclass of the other, then both will be removed. There may not actually be a single closest common base class, however. What would you expect the function to return in the following situation? class A(object): pass class B(object): pass class C(A, B): pass class D(A, B): pass print common_base([C, D])
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 12:05 -0800 |
| Message-ID | <9ac2bf34-1945-4819-9bd5-c0a42179fd00@googlegroups.com> |
| In reply to | #37687 |
On Friday, January 25, 2013 8:04:32 PM UTC+1, Ian wrote: > On Fri, Jan 25, 2013 at 10:40 AM, lars van gemerden > > <lars@rational-it.com> wrote: > > > Hi all, > > > > > > i was writing a function to determine the common base class of a number classes: > > > > > [...] > > > > > > and ran common_base(int, float), hoping to get numbers.Number. > > > > > > this did not work because abstract base classes are not always in the mro() of classes. > > > > > > My question is: is there a way to obtain the abc's of a class or otherwise a way to make the function above take abc's into account (maybe via a predefined function)? > > > > > > If the abstract base class's module has not been imported, it may not > > even be loaded into memory, even though it is technically considered a > > superclass. Consider this: > > > > > > Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit > > (Intel)] on win32 > > Type "help", "copyright", "credits" or "license" for more information. > > >>> def common_base(classes): > > ... common = set() > > ... for cls in object.__subclasses__(): > > ... if all(issubclass(c, cls) for c in classes): > > ... common.add(cls) > > ... return common > > ... > > >>> common_base([int, float]) > > set([<class '_abcoll.Hashable'>]) > > >>> import numbers > > >>> common_base([int, float]) > > set([<class 'numbers.Number'>, <class '_abcoll.Hashable'>]) > > > > > > If you're okay with that, then the approach above might work. > > > > > > > while len(common) > 1: > > > cls1 = common.pop() > > > cls2 = common.pop() > > > if issubclass(cls1, cls2): > > > common.add(cls1) > > > elif issubclass(cls2, cls1): > > > common.add(cls2) > > > > There is a flaw with your set reduction code here. If neither class > > is a subclass of the other, then both will be removed. There may not > > actually be a single closest common base class, however. What would > > you expect the function to return in the following situation? > > > > class A(object): pass > > class B(object): pass > > class C(A, B): pass > > class D(A, B): pass > > > > print common_base([C, D]) thanks, good catch, and very concise answer. I'll give up on trying to get abc's and improve my algorithm.
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 12:05 -0800 |
| Message-ID | <mailman.1054.1359144344.2939.python-list@python.org> |
| In reply to | #37687 |
On Friday, January 25, 2013 8:04:32 PM UTC+1, Ian wrote: > On Fri, Jan 25, 2013 at 10:40 AM, lars van gemerden > > <lars@rational-it.com> wrote: > > > Hi all, > > > > > > i was writing a function to determine the common base class of a number classes: > > > > > [...] > > > > > > and ran common_base(int, float), hoping to get numbers.Number. > > > > > > this did not work because abstract base classes are not always in the mro() of classes. > > > > > > My question is: is there a way to obtain the abc's of a class or otherwise a way to make the function above take abc's into account (maybe via a predefined function)? > > > > > > If the abstract base class's module has not been imported, it may not > > even be loaded into memory, even though it is technically considered a > > superclass. Consider this: > > > > > > Python 2.7.1 (r271:86832, Nov 27 2010, 18:30:46) [MSC v.1500 32 bit > > (Intel)] on win32 > > Type "help", "copyright", "credits" or "license" for more information. > > >>> def common_base(classes): > > ... common = set() > > ... for cls in object.__subclasses__(): > > ... if all(issubclass(c, cls) for c in classes): > > ... common.add(cls) > > ... return common > > ... > > >>> common_base([int, float]) > > set([<class '_abcoll.Hashable'>]) > > >>> import numbers > > >>> common_base([int, float]) > > set([<class 'numbers.Number'>, <class '_abcoll.Hashable'>]) > > > > > > If you're okay with that, then the approach above might work. > > > > > > > while len(common) > 1: > > > cls1 = common.pop() > > > cls2 = common.pop() > > > if issubclass(cls1, cls2): > > > common.add(cls1) > > > elif issubclass(cls2, cls1): > > > common.add(cls2) > > > > There is a flaw with your set reduction code here. If neither class > > is a subclass of the other, then both will be removed. There may not > > actually be a single closest common base class, however. What would > > you expect the function to return in the following situation? > > > > class A(object): pass > > class B(object): pass > > class C(A, B): pass > > class D(A, B): pass > > > > print common_base([C, D]) thanks, good catch, and very concise answer. I'll give up on trying to get abc's and improve my algorithm.
[toc] | [prev] | [next] | [standalone]
| From | Peter Otten <__peter__@web.de> |
|---|---|
| Date | 2013-01-25 20:08 +0100 |
| Message-ID | <mailman.1052.1359140888.2939.python-list@python.org> |
| In reply to | #37682 |
lars van gemerden wrote:
> Hi all,
>
> i was writing a function to determine the common base class of a number
> classes:
>
> def common_base(classes):
> if not len(classes):
> return None
> common = set(classes.pop().mro())
> for cls in classes:
> common.intersection_update(cls.mro())
> while len(common) > 1:
> cls1 = common.pop()
> cls2 = common.pop()
> if issubclass(cls1, cls2):
> common.add(cls1)
> elif issubclass(cls2, cls1):
> common.add(cls2)
> return common.pop()
>
> and ran common_base(int, float), hoping to get numbers.Number.
>
> this did not work because abstract base classes are not always in the
> mro() of classes.
>
> My question is: is there a way to obtain the abc's of a class or otherwise
> a way to make the function above take abc's into account (maybe via a
> predefined function)?
The abstract base classes may run arbitrary code to determine the subclass
relationship:
>>> from abc import ABCMeta
>>> import random
>>> class Maybe(metaclass=ABCMeta):
... @classmethod
... def __subclasshook__(cls, C):
... print("processing", C)
... return random.choice((False, True))
...
>>> isinstance(1.1, Maybe)
processing <class 'float'>
True
>>> isinstance(1.1, Maybe)
True
>>> isinstance(1, Maybe)
processing <class 'int'>
False
>>> issubclass(float, Maybe)
True
You'd have to check every pair of classes explicitly and might still miss
(for example) numbers.Number as the module may not have been imported.
I think you are out of luck.
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 12:08 -0800 |
| Message-ID | <0d837f4c-c4a7-4df6-978c-b62a10ef9d70@googlegroups.com> |
| In reply to | #37688 |
On Friday, January 25, 2013 8:08:18 PM UTC+1, Peter Otten wrote:
> lars van gemerden wrote:
>
>
>
> > Hi all,
>
> >
>
> > i was writing a function to determine the common base class of a number
>
> > classes:
>
> >
>
> > def common_base(classes):
>
> > if not len(classes):
>
> > return None
>
> > common = set(classes.pop().mro())
>
> > for cls in classes:
>
> > common.intersection_update(cls.mro())
>
> > while len(common) > 1:
>
> > cls1 = common.pop()
>
> > cls2 = common.pop()
>
> > if issubclass(cls1, cls2):
>
> > common.add(cls1)
>
> > elif issubclass(cls2, cls1):
>
> > common.add(cls2)
>
> > return common.pop()
>
> >
>
> > and ran common_base(int, float), hoping to get numbers.Number.
>
> >
>
> > this did not work because abstract base classes are not always in the
>
> > mro() of classes.
>
> >
>
> > My question is: is there a way to obtain the abc's of a class or otherwise
>
> > a way to make the function above take abc's into account (maybe via a
>
> > predefined function)?
>
>
>
> The abstract base classes may run arbitrary code to determine the subclass
>
> relationship:
>
>
>
> >>> from abc import ABCMeta
>
> >>> import random
>
> >>> class Maybe(metaclass=ABCMeta):
>
> ... @classmethod
>
> ... def __subclasshook__(cls, C):
>
> ... print("processing", C)
>
> ... return random.choice((False, True))
>
> ...
>
> >>> isinstance(1.1, Maybe)
>
> processing <class 'float'>
>
> True
>
> >>> isinstance(1.1, Maybe)
>
> True
>
> >>> isinstance(1, Maybe)
>
> processing <class 'int'>
>
> False
>
> >>> issubclass(float, Maybe)
>
> True
>
>
>
> You'd have to check every pair of classes explicitly and might still miss
>
> (for example) numbers.Number as the module may not have been imported.
>
>
>
> I think you are out of luck.
Thank you, interesting example. Added confirmation that trying to get the abc's is a bad idea.
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 16:48 -0800 |
| Message-ID | <c84c1e15-591b-4faa-bb8b-708c7e006bf1@googlegroups.com> |
| In reply to | #37692 |
for future reference, i decided to go with 2 functions:
def common_bases(classes):
if not len(classes):
return None
common = set(classes.pop().mro())
for cls in classes:
common.intersection_update(cls.mro()) #all subclasses in common
return [cls for cls in common if not any(sub in common for sub in cls.__subclasses__())] #the classes of which no subclasses are present
def unique_common_base(classes):
while len(classes) > 1:
classes = common_bases(classes)
return classes.pop()
if i tested and understood correctly, they only take classes in the mro() into account (which might include abc's), the first gives all common base classes, the second recursively reduces further to one single class (the latter might not make to much sense, but in my program it is a safe bet for rare cases).
Thanks again for the help,
Cheers, Lars
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 16:48 -0800 |
| Message-ID | <mailman.1066.1359161309.2939.python-list@python.org> |
| In reply to | #37692 |
for future reference, i decided to go with 2 functions:
def common_bases(classes):
if not len(classes):
return None
common = set(classes.pop().mro())
for cls in classes:
common.intersection_update(cls.mro()) #all subclasses in common
return [cls for cls in common if not any(sub in common for sub in cls.__subclasses__())] #the classes of which no subclasses are present
def unique_common_base(classes):
while len(classes) > 1:
classes = common_bases(classes)
return classes.pop()
if i tested and understood correctly, they only take classes in the mro() into account (which might include abc's), the first gives all common base classes, the second recursively reduces further to one single class (the latter might not make to much sense, but in my program it is a safe bet for rare cases).
Thanks again for the help,
Cheers, Lars
[toc] | [prev] | [next] | [standalone]
| From | lars van gemerden <lars@rational-it.com> |
|---|---|
| Date | 2013-01-25 12:08 -0800 |
| Message-ID | <mailman.1055.1359144501.2939.python-list@python.org> |
| In reply to | #37688 |
On Friday, January 25, 2013 8:08:18 PM UTC+1, Peter Otten wrote:
> lars van gemerden wrote:
>
>
>
> > Hi all,
>
> >
>
> > i was writing a function to determine the common base class of a number
>
> > classes:
>
> >
>
> > def common_base(classes):
>
> > if not len(classes):
>
> > return None
>
> > common = set(classes.pop().mro())
>
> > for cls in classes:
>
> > common.intersection_update(cls.mro())
>
> > while len(common) > 1:
>
> > cls1 = common.pop()
>
> > cls2 = common.pop()
>
> > if issubclass(cls1, cls2):
>
> > common.add(cls1)
>
> > elif issubclass(cls2, cls1):
>
> > common.add(cls2)
>
> > return common.pop()
>
> >
>
> > and ran common_base(int, float), hoping to get numbers.Number.
>
> >
>
> > this did not work because abstract base classes are not always in the
>
> > mro() of classes.
>
> >
>
> > My question is: is there a way to obtain the abc's of a class or otherwise
>
> > a way to make the function above take abc's into account (maybe via a
>
> > predefined function)?
>
>
>
> The abstract base classes may run arbitrary code to determine the subclass
>
> relationship:
>
>
>
> >>> from abc import ABCMeta
>
> >>> import random
>
> >>> class Maybe(metaclass=ABCMeta):
>
> ... @classmethod
>
> ... def __subclasshook__(cls, C):
>
> ... print("processing", C)
>
> ... return random.choice((False, True))
>
> ...
>
> >>> isinstance(1.1, Maybe)
>
> processing <class 'float'>
>
> True
>
> >>> isinstance(1.1, Maybe)
>
> True
>
> >>> isinstance(1, Maybe)
>
> processing <class 'int'>
>
> False
>
> >>> issubclass(float, Maybe)
>
> True
>
>
>
> You'd have to check every pair of classes explicitly and might still miss
>
> (for example) numbers.Number as the module may not have been imported.
>
>
>
> I think you are out of luck.
Thank you, interesting example. Added confirmation that trying to get the abc's is a bad idea.
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.python
csiph-web