-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
abstract class instantiable when subclassing built-in types #50246
Comments
when declaring a abstract base class with an abstract property or method >>> import abc
>>> class A(object):
... __metaclass__ = abc.ABCMeta
... @abc.abstractproperty
... def abstract(self): return True
...
>>> a = A()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Can't instantiate abstract class A with abstract methods abstract
>>>
>>> class A2(dict):
... __metaclass__ = abc.ABCMeta
... @abc.abstractproperty
... def abstract(self): return True
...
>>> a2 = A2()
>>> although, when using the dict definition from __builtin__.pi directly, platform: |
Also happens with other builtin types such as tuple. It's probably |
I presume you claim the dict example to be a bug in relation to "A class There is the same difference with @abstractproperty class C(metaclass=abc.ABCMeta):
@abc.abstractmethod
def f(self): return True
class C2(dict,metaclass=abc.ABCMeta):
@abc.abstractmethod
def f(self): return True
c2=C2()
print(c2.f())
c=C()
# prints
True
...
TypeError: Can't instantiate abstract class C with abstract methods f |
I think, that the reason is that, object.__new__ checks, if the class is instantiable (object_new in Objects/typeobject.c ). dict.__new__ (and tuple.__new__, and I guess the __new__ method of other built-in types) doesn't call object.__new__, but user defined types typically either doesn't have a __new__, or call object.__new__ from it (directly or with super). |
This patch fixes the problem by moving the check from object_new to PyType_GenericAlloc. The check is very cheap, so this should not be an issue. |
Anyone has any thoughts on this? |
IIRC, classes weren't supposed to be able inherit from two classes that had different metaclasses (since differing metaclasses don't necessarily play well with one another). |
They are, when there's a most specific metaclass -- the one which is a subclass of all others (described here http://www.python.org/download/releases/2.2.3/descrintro/#metaclasses, implemented here http://hg.python.org/cpython/file/ab162f925761/Objects/typeobject.c#l1956). Since ABCMeta is a subclass of type this holds. Also, in the original example there's no multiple inheritance at all. |
I think subclassing builtin types and making it abstract is rare. And when there is a need, we can mimic this in application level (this may also apply to types having custom __new__): In [2]: class CustomDict(dict, metaclass=abc.ABCMeta): Adding the abstract class checking in tp_alloc or builtin types' tp_new maybe degrade performance. Is it necessary to add this support? |
Honestly let's just forget about this. |
Wait, really? My report came out of a real bug that I had in my system and shipped to my users; it wasn't academic or contrived at all. |
Where did you report that? I don't see your name on this bug -- it has a patch that's been unapplied for 5 years, so I doubt it's very important. |
Oh sorry. I received the emails in a strange order. I guess it can stay open. |
My apologies, I added Nathaniel to nosy here when I closed the duplicate, but forgot to add a link to the closed issue: bpo-28537. |
Closed bpo-31127 as a duplicate of this one. |
Closed bpo-35958 as a duplicate of this issue (and updated the title, since clearly the problem is not specific to dict). Patch probably needs to be rebased/rewritten against latest trunk (given it dates from Mercurial days). |
The reason for this bug is that the creation of the subclass avoids the invocation of the 'object_new' method (e.g. for built-in types or when some links: A simple code for enforcing class MyABC(ABC):
def __new__(cls, *args, **kwargs):
if len(cls.__abstractmethods__) > 0:
raise TypeError("Can't instantiate abstract class MyABC with abstract methods test")
return super().__new__(cls, *args, **kwargs)
ABC = MyABC |
I got as far as a repro, but this morning my Pooh brain doesn't follow the root cause. I'll come back to it.
|
You're right that it is because I'm skeptical of Python-level code whose I'm also skeptical of putting anything in One of the duplicates reported the same problem when inheriting from My gut feeling still says that the exception you get for instantiating an abstract class is intended to be helpful, but not a feature you can depend on, but that's at least in part because I don't know how to solve this yet without slowing down e.g. dict creation, which is pretty time sensitive. |
I'm tempted to close this as won't fix, unless there is further discussion. (A PR would also be helpful to focus the discussion; I'm not considering old patch files from bpo.) |
Maybe someday someone will come up with a relatively good solution. At least this is indeed a bug. |
Thanks, it is indeed a bug, but we won't fix it (yet). |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: