Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bfebb7b

Browse files
committed
improve abstract property support (closes #11610)
Thanks to Darren Dale for patch.
1 parent a8ff01c commit bfebb7b

12 files changed

Lines changed: 396 additions & 36 deletions

File tree

Doc/library/abc.rst

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -127,32 +127,71 @@ This module provides the following class:
127127
available as a method of ``Foo``, so it is provided separately.
128128

129129

130-
It also provides the following decorators:
130+
The :mod:`abc` module also provides the following decorators:
131131

132132
.. decorator:: abstractmethod(function)
133133

134134
A decorator indicating abstract methods.
135135

136-
Using this decorator requires that the class's metaclass is :class:`ABCMeta` or
137-
is derived from it.
138-
A class that has a metaclass derived from :class:`ABCMeta`
139-
cannot be instantiated unless all of its abstract methods and
140-
properties are overridden.
141-
The abstract methods can be called using any of the normal 'super' call
142-
mechanisms.
136+
Using this decorator requires that the class's metaclass is :class:`ABCMeta`
137+
or is derived from it. A class that has a metaclass derived from
138+
:class:`ABCMeta` cannot be instantiated unless all of its abstract methods
139+
and properties are overridden. The abstract methods can be called using any
140+
of the normal 'super' call mechanisms. :func:`abstractmethod` may be used
141+
to declare abstract methods for properties and descriptors.
143142

144143
Dynamically adding abstract methods to a class, or attempting to modify the
145144
abstraction status of a method or class once it is created, are not
146145
supported. The :func:`abstractmethod` only affects subclasses derived using
147146
regular inheritance; "virtual subclasses" registered with the ABC's
148147
:meth:`register` method are not affected.
149148

150-
Usage::
149+
When :func:`abstractmethod` is applied in combination with other method
150+
descriptors, it should be applied as the innermost decorator, as shown in
151+
the following usage examples::
151152

152153
class C(metaclass=ABCMeta):
153154
@abstractmethod
154155
def my_abstract_method(self, ...):
155156
...
157+
@classmethod
158+
@abstractmethod
159+
def my_abstract_classmethod(cls, ...):
160+
...
161+
@staticmethod
162+
@abstractmethod
163+
def my_abstract_staticmethod(...):
164+
...
165+
166+
@property
167+
@abstractmethod
168+
def my_abstract_property(self):
169+
...
170+
@my_abstract_property.setter
171+
@abstractmethod
172+
def my_abstract_property(self, val):
173+
...
174+
175+
@abstractmethod
176+
def _get_x(self):
177+
...
178+
@abstractmethod
179+
def _set_x(self, val):
180+
...
181+
x = property(_get_x, _set_x)
182+
183+
In order to correctly interoperate with the abstract base class machinery,
184+
the descriptor must identify itself as abstract using
185+
:attr:`__isabstractmethod__`. In general, this attribute should be ``True``
186+
if any of the methods used to compose the descriptor are abstract. For
187+
example, Python's built-in property does the equivalent of::
188+
189+
class Descriptor:
190+
...
191+
@property
192+
def __isabstractmethod__(self):
193+
return any(getattr(f, '__isabstractmethod__', False) for
194+
f in (self._fget, self._fset, self._fdel))
156195

157196
.. note::
158197

@@ -177,6 +216,8 @@ It also provides the following decorators:
177216
...
178217

179218
.. versionadded:: 3.2
219+
.. deprecated:: 3.3
220+
Use :class:`classmethod` with :func:`abstractmethod` instead
180221

181222

182223
.. decorator:: abstractstaticmethod(function)
@@ -192,18 +233,19 @@ It also provides the following decorators:
192233
...
193234

194235
.. versionadded:: 3.2
236+
.. deprecated:: 3.3
237+
Use :class:`staticmethod` with :func:`abstractmethod` instead
195238

196239

197240
.. decorator:: abstractproperty(fget=None, fset=None, fdel=None, doc=None)
198241

199242
A subclass of the built-in :func:`property`, indicating an abstract property.
200243

201-
Using this function requires that the class's metaclass is :class:`ABCMeta` or
202-
is derived from it.
203-
A class that has a metaclass derived from :class:`ABCMeta` cannot be
204-
instantiated unless all of its abstract methods and properties are overridden.
205-
The abstract properties can be called using any of the normal
206-
'super' call mechanisms.
244+
Using this function requires that the class's metaclass is :class:`ABCMeta`
245+
or is derived from it. A class that has a metaclass derived from
246+
:class:`ABCMeta` cannot be instantiated unless all of its abstract methods
247+
and properties are overridden. The abstract properties can be called using
248+
any of the normal 'super' call mechanisms.
207249

208250
Usage::
209251

@@ -220,6 +262,9 @@ It also provides the following decorators:
220262
def setx(self, value): ...
221263
x = abstractproperty(getx, setx)
222264

265+
.. deprecated:: 3.3
266+
Use :class:`property` with :func:`abstractmethod` instead
267+
223268

224269
.. rubric:: Footnotes
225270

Doc/whatsnew/3.3.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,23 @@ curses
352352

353353
(Contributed by Iñigo Serna in :issue:`6755`)
354354

355+
abc
356+
---
357+
358+
Improved support for abstract base classes containing descriptors composed with
359+
abstract methods. The recommended approach to declaring abstract descriptors is
360+
now to provide :attr:`__isabstractmethod__` as a dynamically updated
361+
property. The built-in descriptors have been updated accordingly.
362+
363+
* :class:`abc.abstractproperty` has been deprecated, use :class:`property`
364+
with :func:`abc.abstractmethod` instead.
365+
* :class:`abc.abstractclassmethod` has been deprecated, use
366+
:class:`classmethod` with :func:`abc.abstractmethod` instead.
367+
* :class:`abc.abstractstaticmethod` has been deprecated, use
368+
:class:`property` with :func:`abc.abstractmethod` instead.
369+
370+
(Contributed by Darren Dale in :issue:`11610`)
371+
355372
faulthandler
356373
------------
357374

Include/object.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,7 @@ PyAPI_FUNC(int) PyObject_HasAttrString(PyObject *, const char *);
473473
PyAPI_FUNC(PyObject *) PyObject_GetAttr(PyObject *, PyObject *);
474474
PyAPI_FUNC(int) PyObject_SetAttr(PyObject *, PyObject *, PyObject *);
475475
PyAPI_FUNC(int) PyObject_HasAttr(PyObject *, PyObject *);
476+
PyAPI_FUNC(int) _PyObject_IsAbstract(PyObject *);
476477
PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *);
477478
PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *);
478479
PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *);

Lib/abc.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ def my_abstract_method(self, ...):
2626

2727

2828
class abstractclassmethod(classmethod):
29-
"""A decorator indicating abstract classmethods.
29+
"""
30+
A decorator indicating abstract classmethods.
3031
3132
Similar to abstractmethod.
3233
@@ -36,6 +37,9 @@ class C(metaclass=ABCMeta):
3637
@abstractclassmethod
3738
def my_abstract_classmethod(cls, ...):
3839
...
40+
41+
'abstractclassmethod' is deprecated. Use 'classmethod' with
42+
'abstractmethod' instead.
3943
"""
4044

4145
__isabstractmethod__ = True
@@ -46,7 +50,8 @@ def __init__(self, callable):
4650

4751

4852
class abstractstaticmethod(staticmethod):
49-
"""A decorator indicating abstract staticmethods.
53+
"""
54+
A decorator indicating abstract staticmethods.
5055
5156
Similar to abstractmethod.
5257
@@ -56,6 +61,9 @@ class C(metaclass=ABCMeta):
5661
@abstractstaticmethod
5762
def my_abstract_staticmethod(...):
5863
...
64+
65+
'abstractstaticmethod' is deprecated. Use 'staticmethod' with
66+
'abstractmethod' instead.
5967
"""
6068

6169
__isabstractmethod__ = True
@@ -66,7 +74,8 @@ def __init__(self, callable):
6674

6775

6876
class abstractproperty(property):
69-
"""A decorator indicating abstract properties.
77+
"""
78+
A decorator indicating abstract properties.
7079
7180
Requires that the metaclass is ABCMeta or derived from it. A
7281
class that has a metaclass derived from ABCMeta cannot be
@@ -88,7 +97,11 @@ class C(metaclass=ABCMeta):
8897
def getx(self): ...
8998
def setx(self, value): ...
9099
x = abstractproperty(getx, setx)
100+
101+
'abstractproperty' is deprecated. Use 'property' with 'abstractmethod'
102+
instead.
91103
"""
104+
92105
__isabstractmethod__ = True
93106

94107

Lib/numbers.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
66
TODO: Fill out more detailed documentation on the operators."""
77

8-
from abc import ABCMeta, abstractmethod, abstractproperty
8+
from abc import ABCMeta, abstractmethod
99

1010
__all__ = ["Number", "Complex", "Real", "Rational", "Integral"]
1111

@@ -50,15 +50,17 @@ def __bool__(self):
5050
"""True if self != 0. Called for bool(self)."""
5151
return self != 0
5252

53-
@abstractproperty
53+
@property
54+
@abstractmethod
5455
def real(self):
5556
"""Retrieve the real component of this number.
5657
5758
This should subclass Real.
5859
"""
5960
raise NotImplementedError
6061

61-
@abstractproperty
62+
@property
63+
@abstractmethod
6264
def imag(self):
6365
"""Retrieve the imaginary component of this number.
6466
@@ -272,11 +274,13 @@ class Rational(Real):
272274

273275
__slots__ = ()
274276

275-
@abstractproperty
277+
@property
278+
@abstractmethod
276279
def numerator(self):
277280
raise NotImplementedError
278281

279-
@abstractproperty
282+
@property
283+
@abstractmethod
280284
def denominator(self):
281285
raise NotImplementedError
282286

0 commit comments

Comments
 (0)