Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   Re: Wow: list of immediate subclasses? (http://www.velocityreviews.com/forums/t320415-re-wow-list-of-immediate-subclasses.html)

Carl Banks 08-01-2003 05:49 AM

Re: Wow: list of immediate subclasses?
 
Roman Suzi wrote:
>
> I am very surprised that modern classes (inherited from object)
> in Python 2.3 show their ancestry, eg:
>
>>>> object.__subclasses__()

> [<type 'type'>, <type 'int'>, <type 'basestring'>, <type 'list'>, <type
> 'NoneType'>, <type 'NotImplementedType'>, <type 'module'>, <type
> 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type
> 'posix.statvfs_result'>, <type 'dict'>, <type 'function'>, <type 'dictproxy'>,
> <type 'member_descriptor'>, <type 'getset_descriptor'>, <type 'tuple'>, <type
> 'wrapper_descriptor'>, <type 'builtin_function_or_method'>, <type
> 'method_descriptor'>, <type 'file'>]
>
> This seems cool introspection tool but raises questions:
>
> 1- I wonder if it has security consequences (knowing what other
> classes are in there, probably in some other modules). As it adds
> a hole starting from base class "object". Earlier it was possible
> to "chroot" to some custom builtin namespace and provide
> restricted execution.
>
> 2- how do I get rid of a class completely?
>
> This doesn't work:
>
>>>> object.__subclasses__()

> [<type 'type'>, <type 'int'>, <type 'basestring'>, <type 'list'>, <type
> 'NoneType'>, <type 'NotImplementedType'>, <type 'module'>, <type
> 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type
> 'posix.statvfs_result'>, <type 'dict'>, <type 'function'>]
>>>> class A(object): pass

> ...
>>>> object.__subclasses__()

> [<type 'type'>, <type 'int'>, <type 'basestring'>, <type 'list'>, <type
> 'NoneType'>, <type 'NotImplementedType'>, <type 'module'>, <type
> 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type
> 'posix.statvfs_result'>, <type 'dict'>, <type 'function'>, <class
> '__main__.A'>]
>>>> del A
>>>> object.__subclasses__()

> [<type 'type'>, <type 'int'>, <type 'basestring'>, <type 'list'>, <type
> 'NoneType'>, <type 'NotImplementedType'>, <type 'module'>, <type
> 'zipimport.zipimporter'>, <type 'posix.stat_result'>, <type
> 'posix.statvfs_result'>, <type 'dict'>, <type 'function'>, <class
> '__main__.A'>]
>>>>

>
> Sincerely yours, Roman Suzi



__subclasses__ is a list of weak references, so the class can be
collected even though it's listed in __subclasses__. For whatever
reason, class A isn't deleted by reference counts, but cyclic garbage
collection gets it.



Python 2.2.3c1 (#12, May 27 2003, 21:32:04)
[GCC 2.95.4 20011002 (Debian prerelease)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class A(object): pass

....
>>> object.__subclasses__()

[<type 'type'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedT
ype'>, <type 'module'>, <type 'posix.stat_result'>, <type 'posix.statvfs
_result'>, <type 'dict'>, <type 'function'>, <type 'str'>, <type 'file'>
, <class '__main__.A'>]
>>> del A
>>> object.__subclasses__()

[<type 'type'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedT
ype'>, <type 'module'>, <type 'posix.stat_result'>, <type 'posix.statvfs
_result'>, <type 'dict'>, <type 'function'>, <type 'str'>, <type 'file'>
, <class '__main__.A'>]
>>> 1

1
>>> 1

1
>>> 1

1
>>> import gc
>>> gc.collect()

6
>>> object.__subclasses__()

[<type 'type'>, <type 'list'>, <type 'NoneType'>, <type 'NotImplementedT
ype'>, <type 'module'>, <type 'posix.stat_result'>, <type 'posix.statvfs
_result'>, <type 'dict'>, <type 'function'>, <type 'str'>, <type 'file'>
]



--
CARL BANKS

Michael Hudson 08-01-2003 11:14 AM

Re: Wow: list of immediate subclasses?
 
"Andrew Dalke" <adalke@mindspring.com> writes:

> Carl Banks, responding to Roman Suzi:
> > __subclasses__ is a list of weak references, so the class can be
> > collected even though it's listed in __subclasses__. For whatever
> > reason, class A isn't deleted by reference counts, but cyclic garbage
> > collection gets it.

>
> But I want to know that reason. Why are there any cycles? After
> all, don't weak-references help break cycles? And in my code
> before, why do I need to do the gc a few times to force the cycle
> to be broken?
>
> >>> float.__subclasses__()

> []
> >>> class Spam(float): pass

> ...
> >>> float.__subclasses__()

> [<class '__main__.Spam'>]
> >>> del Spam
> >>> _ = None # just in case ...


This doesn't do what you think it does. The reference to Spam is in
__builtin__._; this only assigns to __main__._.

I don't know where the cycle is, off-hand. I suspect I did once...

[...]
> It's a bit too mysterious for my liking.


I can manage not to care :-)

Cheers,
mwh

--
It's actually a corruption of "starling". They used to be carried.
Since they weighed a full pound (hence the name), they had to be
carried by two starlings in tandem, with a line between them.
-- Alan J Rosenthal explains "Pounds Sterling" on asr

Michael Hudson 08-01-2003 11:29 AM

Re: Wow: list of immediate subclasses?
 
Michael Hudson <mwh@python.net> writes:

> "Andrew Dalke" <adalke@mindspring.com> writes:
>
> > Carl Banks, responding to Roman Suzi:
> > > __subclasses__ is a list of weak references, so the class can be
> > > collected even though it's listed in __subclasses__. For whatever
> > > reason, class A isn't deleted by reference counts, but cyclic garbage
> > > collection gets it.

> >
> > But I want to know that reason. Why are there any cycles?

[...]
>
> I don't know where the cycle is, off-hand. I suspect I did once...


Found it (them):

>>> class A(object): pass

....
>>> A.__dict__['__weakref__'].__objclass__ is A

True

praise-be-to-neils-ly y'rs
mwh

--
I never disputed the Perl hacking skill of the Slashdot creators.
My objections are to the editors' taste, the site's ugly visual
design, and the Slashdot community's raging stupidity.
-- http://www.cs.washington.edu/homes/k...shdot.html#faq

Carl Banks 08-01-2003 09:06 PM

Re: Wow: list of immediate subclasses?
 
Andrew Dalke wrote:
> Carl Banks, responding to Roman Suzi:
>> __subclasses__ is a list of weak references, so the class can be
>> collected even though it's listed in __subclasses__. For whatever
>> reason, class A isn't deleted by reference counts, but cyclic garbage
>> collection gets it.

>
> But I want to know that reason. Why are there any cycles? After
> all, don't weak-references help break cycles?


Take a look at "__mro__" method of types. __mro__ is a tuple
containing real references, and the first item is always the type
object, follwed by all it's bases. That makes at least one cycle.
There's probably more since gc collects 6 objects.


> And in my code
> before, why do I need to do the gc a few times to force the cycle
> to be broken?


Because, __subclasses__ is a list of weak references internally, it
gets converted to a regular list when called, and this list is stored
in _. Thus, if you call gc.collect right after evaluating
float.__subclasses__, there remains an active reference.



>>>> float.__subclasses__()

> []
>>>> class Spam(float): pass

> ...
>>>> float.__subclasses__()

> [<class '__main__.Spam'>]
>>>> del Spam
>>>> _ = None # just in case ...
>>>> float.__subclasses__()

> [<class '__main__.Spam'>]
>>>> gc.collect()

> 0
>>>> float.__subclasses__()

> [<class '__main__.Spam'>]
>>>> gc.collect()

> 0
>>>> float.__subclasses__()

> [<class '__main__.Spam'>]
>>>> gc.collect()

> 0
>>>> gc.collect()

> 6
>>>> gc.collect()

> 0
>>>> float.__subclasses__()

> []
>>>>

>
> It's a bit too mysterious for my liking.


I think it's a very minor problem. There doesn't appear to be a
memory leak, and what's the point of making the effort to manually
break cycles when cycle garbage collection exists?



--
CARL BANKS

Andrew Dalke 08-01-2003 11:00 PM

Re: Wow: list of immediate subclasses?
 
Michael Hudson:
> >>> A.__dict__['__weakref__'].__objclass__ is A


Ahhh...
Andrew
dalke@dalkescientific.com



Michael Hudson 08-05-2003 12:48 PM

Re: Wow: list of immediate subclasses?
 
"Andrew Dalke" <adalke@mindspring.com> writes:

> Michael Hudson:
> > >>> A.__dict__['__weakref__'].__objclass__ is A

>
> Ahhh...


And *then* I find how I should have found <wink> the cycle:

>>> class A(object): pass

....
>>> pprint.pprint([r for r in gc.get_referrers(A) if r is not __main__.__dict__])

[<attribute '__dict__' of 'A' objects>,
<attribute '__weakref__' of 'A' objects>,
(<class '__main__.A'>, <type 'object'>)]

Forgot about the obvious A.__mro__[0] is A cycle!

Cheers,
mwh

--
A difference which makes no difference is no difference at all.
-- William James (I think. Reference anyone?)


All times are GMT. The time now is 11:00 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.