Skip to content

Commit c71ae1a

Browse files
bpo-36743: __get__ is sometimes called without the owner argument (GH-12992) (GH-15589)
(cherry picked from commit 0dac68f) Co-authored-by: Raymond Hettinger <rhettinger@users.noreply.github.com>
1 parent 0d45d50 commit c71ae1a

File tree

5 files changed

+24
-13
lines changed

5 files changed

+24
-13
lines changed

Doc/reference/datamodel.rst

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,21 +1618,32 @@ refers to the attribute whose name is the key of the property in the owner
16181618
class' :attr:`~object.__dict__`.
16191619

16201620

1621-
.. method:: object.__get__(self, instance, owner)
1621+
.. method:: object.__get__(self, instance, owner=None)
16221622

1623-
Called to get the attribute of the owner class (class attribute access) or of an
1624-
instance of that class (instance attribute access). *owner* is always the owner
1625-
class, while *instance* is the instance that the attribute was accessed through,
1626-
or ``None`` when the attribute is accessed through the *owner*. This method
1627-
should return the (computed) attribute value or raise an :exc:`AttributeError`
1628-
exception.
1623+
Called to get the attribute of the owner class (class attribute access) or
1624+
of an instance of that class (instance attribute access). The optional
1625+
*owner* argument is the owner class, while *instance* is the instance that
1626+
the attribute was accessed through, or ``None`` when the attribute is
1627+
accessed through the *owner*.
16291628

1629+
This method should return the computed attribute value or raise an
1630+
:exc:`AttributeError` exception.
1631+
1632+
:PEP:`252` specifies that :meth:`__get__` is callable with one or two
1633+
arguments. Python's own built-in descriptors support this specification;
1634+
however, it is likely that some third-party tools have descriptors
1635+
that require both arguments. Python's own :meth:`__getattribute__`
1636+
implementation always passes in both arguments whether they are required
1637+
or not.
16301638

16311639
.. method:: object.__set__(self, instance, value)
16321640

16331641
Called to set the attribute on an instance *instance* of the owner class to a
16341642
new value, *value*.
16351643

1644+
Note, adding :meth:`__set__` or :meth:`__delete__` changes the kind of
1645+
descriptor to a "data descriptor". See :ref:`descriptor-invocation` for
1646+
more details.
16361647

16371648
.. method:: object.__delete__(self, instance)
16381649

Lib/_pyio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def _open_code_with_warning(path):
281281
class DocDescriptor:
282282
"""Helper for builtins.open.__doc__
283283
"""
284-
def __get__(self, obj, typ):
284+
def __get__(self, obj, typ=None):
285285
return (
286286
"open(file, mode='r', buffering=-1, encoding=None, "
287287
"errors=None, newline=None, closefd=True)\n\n" +

Lib/functools.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ def _method(cls_or_self, /, *args, **keywords):
400400
_method._partialmethod = self
401401
return _method
402402

403-
def __get__(self, obj, cls):
403+
def __get__(self, obj, cls=None):
404404
get = getattr(self.func, "__get__", None)
405405
result = None
406406
if get is not None:
@@ -905,7 +905,7 @@ def register(self, cls, method=None):
905905
"""
906906
return self.dispatcher.register(cls, func=method)
907907

908-
def __get__(self, obj, cls):
908+
def __get__(self, obj, cls=None):
909909
def _method(*args, **kwargs):
910910
method = self.dispatcher.dispatch(args[0].__class__)
911911
return method.__get__(obj, cls)(*args, **kwargs)
@@ -943,7 +943,7 @@ def __set_name__(self, owner, name):
943943
f"({self.attrname!r} and {name!r})."
944944
)
945945

946-
def __get__(self, instance, owner):
946+
def __get__(self, instance, owner=None):
947947
if instance is None:
948948
return self
949949
if self.attrname is None:

Lib/unittest/mock.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2806,7 +2806,7 @@ class PropertyMock(Mock):
28062806
def _get_child_mock(self, /, **kwargs):
28072807
return MagicMock(**kwargs)
28082808

2809-
def __get__(self, obj, obj_type):
2809+
def __get__(self, obj, obj_type=None):
28102810
return self()
28112811
def __set__(self, obj, val):
28122812
self(val)

Tools/demo/eiffel.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ def __init__(self, func, pre, post):
7878
self.__name__ = func.__name__
7979
self.__doc__ = func.__doc__
8080

81-
def __get__(self, obj, cls):
81+
def __get__(self, obj, cls=None):
8282
return EiffelMethodWrapper(obj, self)
8383

8484
def callmethod(self, inst, args, kwargs):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy