2007-06-14 08:03:37 +08:00
|
|
|
# Copyright 2007 Google, Inc. All Rights Reserved.
|
|
|
|
# Licensed to PSF under a Contributor Agreement.
|
|
|
|
|
|
|
|
"""Abstract Base Classes (ABCs) according to PEP 3119."""
|
|
|
|
|
2008-02-05 08:20:01 +08:00
|
|
|
from _weakrefset import WeakSet
|
2007-06-14 08:03:37 +08:00
|
|
|
|
|
|
|
def abstractmethod(funcobj):
|
|
|
|
"""A decorator indicating abstract methods.
|
|
|
|
|
|
|
|
Requires that the metaclass is ABCMeta or derived from it. A
|
|
|
|
class that has a metaclass derived from ABCMeta cannot be
|
|
|
|
instantiated unless all of its abstract methods are overridden.
|
2009-05-05 00:10:10 +08:00
|
|
|
The abstract methods can be called using any of the normal
|
2007-06-14 08:03:37 +08:00
|
|
|
'super' call mechanisms.
|
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
class C(metaclass=ABCMeta):
|
|
|
|
@abstractmethod
|
|
|
|
def my_abstract_method(self, ...):
|
|
|
|
...
|
|
|
|
"""
|
|
|
|
funcobj.__isabstractmethod__ = True
|
|
|
|
return funcobj
|
|
|
|
|
|
|
|
|
2007-08-02 01:32:28 +08:00
|
|
|
class abstractproperty(property):
|
|
|
|
"""A decorator indicating abstract properties.
|
|
|
|
|
|
|
|
Requires that the metaclass is ABCMeta or derived from it. A
|
|
|
|
class that has a metaclass derived from ABCMeta cannot be
|
|
|
|
instantiated unless all of its abstract properties are overridden.
|
2009-05-05 00:10:10 +08:00
|
|
|
The abstract properties can be called using any of the normal
|
2007-08-02 01:52:23 +08:00
|
|
|
'super' call mechanisms.
|
2007-08-02 01:32:28 +08:00
|
|
|
|
|
|
|
Usage:
|
|
|
|
|
|
|
|
class C(metaclass=ABCMeta):
|
|
|
|
@abstractproperty
|
|
|
|
def my_abstract_property(self):
|
|
|
|
...
|
|
|
|
|
|
|
|
This defines a read-only property; you can also define a read-write
|
|
|
|
abstract property using the 'long' form of property declaration:
|
|
|
|
|
|
|
|
class C(metaclass=ABCMeta):
|
|
|
|
def getx(self): ...
|
|
|
|
def setx(self, value): ...
|
|
|
|
x = abstractproperty(getx, setx)
|
|
|
|
"""
|
|
|
|
__isabstractmethod__ = True
|
|
|
|
|
|
|
|
|
2007-06-14 08:03:37 +08:00
|
|
|
class ABCMeta(type):
|
|
|
|
|
|
|
|
"""Metaclass for defining Abstract Base Classes (ABCs).
|
|
|
|
|
|
|
|
Use this metaclass to create an ABC. An ABC can be subclassed
|
|
|
|
directly, and then acts as a mix-in class. You can also register
|
|
|
|
unrelated concrete classes (even built-in classes) and unrelated
|
|
|
|
ABCs as 'virtual subclasses' -- these and their descendants will
|
|
|
|
be considered subclasses of the registering ABC by the built-in
|
|
|
|
issubclass() function, but the registering ABC won't show up in
|
|
|
|
their MRO (Method Resolution Order) nor will method
|
|
|
|
implementations defined by the registering ABC be callable (not
|
|
|
|
even via super()).
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
# A global counter that is incremented each time a class is
|
|
|
|
# registered as a virtual subclass of anything. It forces the
|
|
|
|
# negative cache to be cleared before its next use.
|
2007-08-21 03:29:24 +08:00
|
|
|
_abc_invalidation_counter = 0
|
2007-06-14 08:03:37 +08:00
|
|
|
|
|
|
|
def __new__(mcls, name, bases, namespace):
|
2007-06-14 11:27:55 +08:00
|
|
|
cls = super().__new__(mcls, name, bases, namespace)
|
2007-06-14 08:03:37 +08:00
|
|
|
# Compute set of abstract method names
|
|
|
|
abstracts = {name
|
|
|
|
for name, value in namespace.items()
|
|
|
|
if getattr(value, "__isabstractmethod__", False)}
|
|
|
|
for base in bases:
|
|
|
|
for name in getattr(base, "__abstractmethods__", set()):
|
|
|
|
value = getattr(cls, name, None)
|
|
|
|
if getattr(value, "__isabstractmethod__", False):
|
|
|
|
abstracts.add(name)
|
Merged revisions 61038,61042-61045,61047,61050,61053,61055-61056,61061-61062,61066,61068,61070,61083,61085,61092-61103 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r61098 | jeffrey.yasskin | 2008-02-28 05:45:36 +0100 (Thu, 28 Feb 2008) | 7 lines
Move abc._Abstract into object by adding a new flag Py_TPFLAGS_IS_ABSTRACT,
which forbids constructing types that have it set. The effect is to speed
./python.exe -m timeit -s 'import abc' -s 'class Foo(object): __metaclass__ = abc.ABCMeta' 'Foo()'
up from 2.5us to 0.201us. This fixes issue 1762.
........
r61099 | jeffrey.yasskin | 2008-02-28 06:53:18 +0100 (Thu, 28 Feb 2008) | 3 lines
Speed test_socketserver up from 28.739s to 0.226s, simplify the logic, and make
sure all tests run even if some fail.
........
r61100 | jeffrey.yasskin | 2008-02-28 07:09:19 +0100 (Thu, 28 Feb 2008) | 21 lines
Thread.start() used sleep(0.000001) to make sure it didn't return before the
new thread had started. At least on my MacBook Pro, that wound up sleeping for
a full 10ms (probably 1 jiffy). By using an Event instead, we can be absolutely
certain that the thread has started, and return more quickly (217us).
Before:
$ ./python.exe -m timeit -s 'from threading import Thread' 't = Thread(); t.start(); t.join()'
100 loops, best of 3: 10.3 msec per loop
$ ./python.exe -m timeit -s 'from threading import Thread; t = Thread()' 't.isAlive()'
1000000 loops, best of 3: 0.47 usec per loop
After:
$ ./python.exe -m timeit -s 'from threading import Thread' 't = Thread(); t.start(); t.join()'
1000 loops, best of 3: 217 usec per loop
$ ./python.exe -m timeit -s 'from threading import Thread; t = Thread()' 't.isAlive()'
1000000 loops, best of 3: 0.86 usec per loop
To be fair, the 10ms isn't CPU time, and other threads including the spawned
one get to run during it. There are also some slightly more complicated ways to
get back the .4us in isAlive() if we want.
........
r61101 | raymond.hettinger | 2008-02-28 10:23:48 +0100 (Thu, 28 Feb 2008) | 1 line
Add repeat keyword argument to itertools.product().
........
r61102 | christian.heimes | 2008-02-28 12:18:49 +0100 (Thu, 28 Feb 2008) | 1 line
The empty tuple is usually a singleton with a much higher refcnt than 1
........
2008-02-28 20:27:11 +08:00
|
|
|
cls.__abstractmethods__ = frozenset(abstracts)
|
2007-06-14 08:03:37 +08:00
|
|
|
# Set up inheritance registry
|
2007-10-23 14:26:46 +08:00
|
|
|
cls._abc_registry = WeakSet()
|
|
|
|
cls._abc_cache = WeakSet()
|
|
|
|
cls._abc_negative_cache = WeakSet()
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
|
2007-06-14 08:03:37 +08:00
|
|
|
return cls
|
|
|
|
|
2007-11-30 23:13:13 +08:00
|
|
|
def register(cls, subclass):
|
2007-06-14 08:03:37 +08:00
|
|
|
"""Register a virtual subclass of an ABC."""
|
|
|
|
if not isinstance(cls, type):
|
|
|
|
raise TypeError("Can only register classes")
|
|
|
|
if issubclass(subclass, cls):
|
|
|
|
return # Already a subclass
|
|
|
|
# Subtle: test for cycles *after* testing for "already a subclass";
|
|
|
|
# this means we allow X.register(X) and interpret it as a no-op.
|
|
|
|
if issubclass(cls, subclass):
|
|
|
|
# This would create a cycle, which is bad for the algorithm below
|
|
|
|
raise RuntimeError("Refusing to create an inheritance cycle")
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_registry.add(subclass)
|
|
|
|
ABCMeta._abc_invalidation_counter += 1 # Invalidate negative cache
|
2007-06-14 08:03:37 +08:00
|
|
|
|
|
|
|
def _dump_registry(cls, file=None):
|
|
|
|
"""Debug helper to print the ABC registry."""
|
|
|
|
print("Class: %s.%s" % (cls.__module__, cls.__name__), file=file)
|
2007-08-21 03:29:24 +08:00
|
|
|
print("Inv.counter: %s" % ABCMeta._abc_invalidation_counter, file=file)
|
2007-06-14 08:03:37 +08:00
|
|
|
for name in sorted(cls.__dict__.keys()):
|
2007-08-21 03:29:24 +08:00
|
|
|
if name.startswith("_abc_"):
|
2007-06-14 08:03:37 +08:00
|
|
|
value = getattr(cls, name)
|
|
|
|
print("%s: %r" % (name, value), file=file)
|
|
|
|
|
|
|
|
def __instancecheck__(cls, instance):
|
|
|
|
"""Override for isinstance(instance, cls)."""
|
Merged revisions 60481,60485,60489-60492,60494-60496,60498-60499,60501-60503,60505-60506,60508-60509,60523-60524,60532,60543,60545,60547-60548,60552,60554,60556-60559,60561-60562,60569,60571-60572,60574,60576-60583,60585-60586,60589,60591,60594-60595,60597-60598,60600-60601,60606-60612,60615,60617,60619-60621,60623-60625,60627-60629,60631,60633,60635,60647,60650,60652,60654,60656,60658-60659,60664-60666,60668-60670,60672,60676,60678,60680-60683,60685-60686,60688,60690,60692-60694,60697-60700,60705-60706,60708,60711,60714,60720,60724-60730,60732,60736,60742,60744,60746,60748,60750-60766,60769-60786 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk
........
r60752 | mark.dickinson | 2008-02-12 22:31:59 +0100 (Tue, 12 Feb 2008) | 5 lines
Implementation of Fraction.limit_denominator.
Remove Fraction.to_continued_fraction and
Fraction.from_continued_fraction
........
r60754 | mark.dickinson | 2008-02-12 22:40:53 +0100 (Tue, 12 Feb 2008) | 3 lines
Revert change in r60712: turn alternate constructors back into
classmethods instead of staticmethods.
........
r60755 | mark.dickinson | 2008-02-12 22:46:54 +0100 (Tue, 12 Feb 2008) | 4 lines
Replace R=fractions.Fraction with F=fractions.Fraction in
test_fractions.py. This should have been part of the name
change from Rational to Fraction.
........
r60758 | georg.brandl | 2008-02-13 08:20:22 +0100 (Wed, 13 Feb 2008) | 3 lines
#2063: correct order of utime and stime in os.times()
result on Windows.
........
r60762 | jeffrey.yasskin | 2008-02-13 18:58:04 +0100 (Wed, 13 Feb 2008) | 7 lines
Working on issue #1762: Brought
./python.exe -m timeit -s 'from fractions import Fraction; f = Fraction(3, 2)' 'isinstance(3, Fraction); isinstance(f, Fraction)'
from 12.3 usec/loop to 3.44 usec/loop and
./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3, 2)'
from 48.8 usec to 23.6 usec by avoiding genexps and sets in __instancecheck__
and inlining the common case from __subclasscheck__.
........
r60765 | brett.cannon | 2008-02-13 20:15:44 +0100 (Wed, 13 Feb 2008) | 5 lines
Fix --enable-universalsdk and its comment line so that zsh's flag completion
works.
Thanks to Jeroen Ruigrok van der Werven for the fix.
........
r60771 | kurt.kaiser | 2008-02-14 01:08:55 +0100 (Thu, 14 Feb 2008) | 2 lines
Bring NEWS.txt up to date from check-in msgs.
........
r60772 | raymond.hettinger | 2008-02-14 02:08:02 +0100 (Thu, 14 Feb 2008) | 3 lines
Update notes on Decimal.
........
r60773 | raymond.hettinger | 2008-02-14 03:41:22 +0100 (Thu, 14 Feb 2008) | 1 line
Fix decimal repr which should have used single quotes like other reprs.
........
r60785 | jeffrey.yasskin | 2008-02-14 07:12:24 +0100 (Thu, 14 Feb 2008) | 11 lines
Performance optimizations on Fraction's constructor.
./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3)`
31.7 usec/loop -> 9.2 usec/loop
./python.exe -m timeit -s 'from fractions import Fraction' 'Fraction(3, 2)'`
27.7 usec/loop -> 9.32 usec/loop
./python.exe -m timeit -s 'from fractions import Fraction; f = Fraction(3, 2)' 'Fraction(f)'
31.9 usec/loop -> 14.3 usec/loop
........
r60786 | jeffrey.yasskin | 2008-02-14 08:49:25 +0100 (Thu, 14 Feb 2008) | 5 lines
Change simple instances (in Fraction) of self.numerator and self.denominator to
self._numerator and self._denominator. This speeds abs() up from 12.2us to
10.8us and trunc() from 2.07us to 1.11us. This doesn't change _add and friends
because they're more complicated.
........
2008-02-14 16:27:37 +08:00
|
|
|
# Inline the cache checking
|
|
|
|
subclass = instance.__class__
|
|
|
|
if subclass in cls._abc_cache:
|
|
|
|
return True
|
|
|
|
subtype = type(instance)
|
|
|
|
if subtype is subclass:
|
|
|
|
if (cls._abc_negative_cache_version ==
|
|
|
|
ABCMeta._abc_invalidation_counter and
|
|
|
|
subclass in cls._abc_negative_cache):
|
|
|
|
return False
|
|
|
|
# Fall back to the subclass check.
|
|
|
|
return cls.__subclasscheck__(subclass)
|
|
|
|
return any(cls.__subclasscheck__(c) for c in {subclass, subtype})
|
2007-06-14 08:03:37 +08:00
|
|
|
|
|
|
|
def __subclasscheck__(cls, subclass):
|
|
|
|
"""Override for issubclass(subclass, cls)."""
|
|
|
|
# Check cache
|
2007-08-21 03:29:24 +08:00
|
|
|
if subclass in cls._abc_cache:
|
2007-06-14 08:03:37 +08:00
|
|
|
return True
|
|
|
|
# Check negative cache; may have to invalidate
|
2007-08-21 03:29:24 +08:00
|
|
|
if cls._abc_negative_cache_version < ABCMeta._abc_invalidation_counter:
|
2007-06-14 08:03:37 +08:00
|
|
|
# Invalidate the negative cache
|
2007-10-23 14:26:46 +08:00
|
|
|
cls._abc_negative_cache = WeakSet()
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_negative_cache_version = ABCMeta._abc_invalidation_counter
|
|
|
|
elif subclass in cls._abc_negative_cache:
|
2007-06-14 08:03:37 +08:00
|
|
|
return False
|
|
|
|
# Check the subclass hook
|
|
|
|
ok = cls.__subclasshook__(subclass)
|
|
|
|
if ok is not NotImplemented:
|
|
|
|
assert isinstance(ok, bool)
|
|
|
|
if ok:
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
else:
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_negative_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
return ok
|
|
|
|
# Check if it's a direct subclass
|
2008-01-08 01:19:16 +08:00
|
|
|
if cls in getattr(subclass, '__mro__', ()):
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
return True
|
|
|
|
# Check if it's a subclass of a registered class (recursive)
|
2007-08-21 03:29:24 +08:00
|
|
|
for rcls in cls._abc_registry:
|
2007-06-14 08:03:37 +08:00
|
|
|
if issubclass(subclass, rcls):
|
2008-09-02 18:43:28 +08:00
|
|
|
cls._abc_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
return True
|
|
|
|
# Check if it's a subclass of a subclass (recursive)
|
|
|
|
for scls in cls.__subclasses__():
|
|
|
|
if issubclass(subclass, scls):
|
2008-09-02 18:43:28 +08:00
|
|
|
cls._abc_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
return True
|
|
|
|
# No dice; update negative cache
|
2007-08-21 03:29:24 +08:00
|
|
|
cls._abc_negative_cache.add(subclass)
|
2007-06-14 08:03:37 +08:00
|
|
|
return False
|