Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
c3afba10
Commit
c3afba10
authored
Nov 17, 2012
by
Antoine Pitrou
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Issue #14631: Add a new :class:`weakref.WeakMethod` to simulate weak references to bound methods.
parent
25bbe5e0
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
227 additions
and
1 deletion
+227
-1
Doc/library/weakref.rst
Doc/library/weakref.rst
+29
-0
Lib/test/test_weakref.py
Lib/test/test_weakref.py
+140
-0
Lib/weakref.py
Lib/weakref.py
+55
-1
Misc/NEWS
Misc/NEWS
+3
-0
No files found.
Doc/library/weakref.rst
View file @
c3afba10
...
...
@@ -192,6 +192,35 @@ These method have the same issues as the and :meth:`keyrefs` method of
discarded when no strong reference to it exists any more.
.. class:: WeakMethod(method)
A custom :class:`ref` subclass which simulates a weak reference to a bound
method (i.e., a method defined on a class and looked up on an instance).
Since a bound method is ephemeral, a standard weak reference cannot keep
hold of it. :class:`WeakMethod` has special code to recreate the bound
method until either the object or the original function dies::
>>> class C:
... def method(self):
... print("method called!")
...
>>> c = C()
>>> r = weakref.ref(c.method)
>>> r()
>>> r = weakref.WeakMethod(c.method)
>>> r()
<bound method C.method of <__main__.C object at 0x7fc859830220>>
>>> r()()
method called!
>>> del c
>>> gc.collect()
0
>>> r()
>>>
.. versionadded:: 3.4
.. data:: ReferenceType
The type object for weak references objects.
...
...
Lib/test/test_weakref.py
View file @
c3afba10
...
...
@@ -47,6 +47,11 @@ class Object:
return
NotImplemented
def
__hash__
(
self
):
return
hash
(
self
.
arg
)
def
some_method
(
self
):
return
4
def
other_method
(
self
):
return
5
class
RefCycle
:
def
__init__
(
self
):
...
...
@@ -880,6 +885,140 @@ class SubclassableWeakrefTestCase(TestBase):
self
.
assertEqual
(
self
.
cbcalled
,
0
)
class
WeakMethodTestCase
(
unittest
.
TestCase
):
def
_subclass
(
self
):
"""Return a Object subclass overriding `some_method`."""
class
C
(
Object
):
def
some_method
(
self
):
return
6
return
C
def
test_alive
(
self
):
o
=
Object
(
1
)
r
=
weakref
.
WeakMethod
(
o
.
some_method
)
self
.
assertIsInstance
(
r
,
weakref
.
ReferenceType
)
self
.
assertIsInstance
(
r
(),
type
(
o
.
some_method
))
self
.
assertIs
(
r
().
__self__
,
o
)
self
.
assertIs
(
r
().
__func__
,
o
.
some_method
.
__func__
)
self
.
assertEqual
(
r
()(),
4
)
def
test_object_dead
(
self
):
o
=
Object
(
1
)
r
=
weakref
.
WeakMethod
(
o
.
some_method
)
del
o
gc
.
collect
()
self
.
assertIs
(
r
(),
None
)
def
test_method_dead
(
self
):
C
=
self
.
_subclass
()
o
=
C
(
1
)
r
=
weakref
.
WeakMethod
(
o
.
some_method
)
del
C
.
some_method
gc
.
collect
()
self
.
assertIs
(
r
(),
None
)
def
test_callback_when_object_dead
(
self
):
# Test callback behaviour when object dies first.
C
=
self
.
_subclass
()
calls
=
[]
def
cb
(
arg
):
calls
.
append
(
arg
)
o
=
C
(
1
)
r
=
weakref
.
WeakMethod
(
o
.
some_method
,
cb
)
del
o
gc
.
collect
()
self
.
assertEqual
(
calls
,
[
r
])
# Callback is only called once.
C
.
some_method
=
Object
.
some_method
gc
.
collect
()
self
.
assertEqual
(
calls
,
[
r
])
def
test_callback_when_method_dead
(
self
):
# Test callback behaviour when method dies first.
C
=
self
.
_subclass
()
calls
=
[]
def
cb
(
arg
):
calls
.
append
(
arg
)
o
=
C
(
1
)
r
=
weakref
.
WeakMethod
(
o
.
some_method
,
cb
)
del
C
.
some_method
gc
.
collect
()
self
.
assertEqual
(
calls
,
[
r
])
# Callback is only called once.
del
o
gc
.
collect
()
self
.
assertEqual
(
calls
,
[
r
])
@
support
.
cpython_only
def
test_no_cycles
(
self
):
# A WeakMethod doesn't create any reference cycle to itself.
o
=
Object
(
1
)
def
cb
(
_
):
pass
r
=
weakref
.
WeakMethod
(
o
.
some_method
,
cb
)
wr
=
weakref
.
ref
(
r
)
del
r
self
.
assertIs
(
wr
(),
None
)
def
test_equality
(
self
):
def
_eq
(
a
,
b
):
self
.
assertTrue
(
a
==
b
)
self
.
assertFalse
(
a
!=
b
)
def
_ne
(
a
,
b
):
self
.
assertTrue
(
a
!=
b
)
self
.
assertFalse
(
a
==
b
)
x
=
Object
(
1
)
y
=
Object
(
1
)
a
=
weakref
.
WeakMethod
(
x
.
some_method
)
b
=
weakref
.
WeakMethod
(
y
.
some_method
)
c
=
weakref
.
WeakMethod
(
x
.
other_method
)
d
=
weakref
.
WeakMethod
(
y
.
other_method
)
# Objects equal, same method
_eq
(
a
,
b
)
_eq
(
c
,
d
)
# Objects equal, different method
_ne
(
a
,
c
)
_ne
(
a
,
d
)
_ne
(
b
,
c
)
_ne
(
b
,
d
)
# Objects unequal, same or different method
z
=
Object
(
2
)
e
=
weakref
.
WeakMethod
(
z
.
some_method
)
f
=
weakref
.
WeakMethod
(
z
.
other_method
)
_ne
(
a
,
e
)
_ne
(
a
,
f
)
_ne
(
b
,
e
)
_ne
(
b
,
f
)
del
x
,
y
,
z
gc
.
collect
()
# Dead WeakMethods compare by identity
refs
=
a
,
b
,
c
,
d
,
e
,
f
for
q
in
refs
:
for
r
in
refs
:
self
.
assertEqual
(
q
==
r
,
q
is
r
)
self
.
assertEqual
(
q
!=
r
,
q
is
not
r
)
def
test_hashing
(
self
):
# Alive WeakMethods are hashable if the underlying object is
# hashable.
x
=
Object
(
1
)
y
=
Object
(
1
)
a
=
weakref
.
WeakMethod
(
x
.
some_method
)
b
=
weakref
.
WeakMethod
(
y
.
some_method
)
c
=
weakref
.
WeakMethod
(
y
.
other_method
)
# Since WeakMethod objects are equal, the hashes should be equal.
self
.
assertEqual
(
hash
(
a
),
hash
(
b
))
ha
=
hash
(
a
)
# Dead WeakMethods retain their old hash value
del
x
,
y
gc
.
collect
()
self
.
assertEqual
(
hash
(
a
),
ha
)
self
.
assertEqual
(
hash
(
b
),
ha
)
# If it wasn't hashed when alive, a dead WeakMethod cannot be hashed.
self
.
assertRaises
(
TypeError
,
hash
,
c
)
class
MappingTestCase
(
TestBase
):
COUNT
=
10
...
...
@@ -1455,6 +1594,7 @@ __test__ = {'libreftest' : libreftest}
def
test_main
():
support
.
run_unittest
(
ReferencesTestCase
,
WeakMethodTestCase
,
MappingTestCase
,
WeakValueDictionaryTestCase
,
WeakKeyDictionaryTestCase
,
...
...
Lib/weakref.py
View file @
c3afba10
...
...
@@ -27,7 +27,61 @@ ProxyTypes = (ProxyType, CallableProxyType)
__all__
=
[
"ref"
,
"proxy"
,
"getweakrefcount"
,
"getweakrefs"
,
"WeakKeyDictionary"
,
"ReferenceType"
,
"ProxyType"
,
"CallableProxyType"
,
"ProxyTypes"
,
"WeakValueDictionary"
,
"WeakSet"
]
"WeakSet"
,
"WeakMethod"
]
class
WeakMethod
(
ref
):
"""
A custom `weakref.ref` subclass which simulates a weak reference to
a bound method, working around the lifetime problem of bound methods.
"""
__slots__
=
"_func_ref"
,
"_meth_type"
,
"_alive"
,
"__weakref__"
def
__new__
(
cls
,
meth
,
callback
=
None
):
try
:
obj
=
meth
.
__self__
func
=
meth
.
__func__
except
AttributeError
:
raise
TypeError
(
"argument should be a bound method, not {}"
.
format
(
type
(
meth
)))
from
None
def
_cb
(
arg
):
# The self-weakref trick is needed to avoid creating a reference
# cycle.
self
=
self_wr
()
if
self
.
_alive
:
self
.
_alive
=
False
if
callback
is
not
None
:
callback
(
self
)
self
=
ref
.
__new__
(
cls
,
obj
,
_cb
)
self
.
_func_ref
=
ref
(
func
,
_cb
)
self
.
_meth_type
=
type
(
meth
)
self
.
_alive
=
True
self_wr
=
ref
(
self
)
return
self
def
__call__
(
self
):
obj
=
super
().
__call__
()
func
=
self
.
_func_ref
()
if
obj
is
None
or
func
is
None
:
return
None
return
self
.
_meth_type
(
func
,
obj
)
def
__eq__
(
self
,
other
):
if
isinstance
(
other
,
WeakMethod
):
if
not
self
.
_alive
or
not
other
.
_alive
:
return
self
is
other
return
ref
.
__eq__
(
self
,
other
)
and
self
.
_func_ref
==
other
.
_func_ref
return
False
def
__ne__
(
self
,
other
):
if
isinstance
(
other
,
WeakMethod
):
if
not
self
.
_alive
or
not
other
.
_alive
:
return
self
is
not
other
return
ref
.
__ne__
(
self
,
other
)
or
self
.
_func_ref
!=
other
.
_func_ref
return
True
__hash__
=
ref
.
__hash__
class
WeakValueDictionary
(
collections
.
MutableMapping
):
...
...
Misc/NEWS
View file @
c3afba10
...
...
@@ -127,6 +127,9 @@ Core and Builtins
Library
-------
- Issue #14631: Add a new :class:`weakref.WeakMethod` to simulate weak
references to bound methods.
- Issue #16469: Fix exceptions from float -> Fraction and Decimal -> Fraction
conversions for special values to be consistent with those for float -> int
and Decimal -> int. Patch by Alexey Kachayev.
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment