Python ABCs: registering vs. subclassing

2024/11/15 13:47:47

(I am using python 2.7) The python documentation indicates that you can pass a mapping to the dict builtin and it will copy that mapping into the new dict:

http://docs.python.org/library/stdtypes.html#mapping-types-dict

I have a class that implements the Mapping ABC, but it fails:

import collections
class Mapping(object):def __init__(self, dict={}): self.dict=dictdef __iter__(self): return iter(self.dict)def __iter__(self): return iter(self.dict)def __len__(self): return len(self.dict)def __contains__(self, value): return value in self.dictdef __getitem__(self, name): return self.dict[name]m=Mapping({5:5})
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence
collections.Mapping.register(Mapping)
dict(m)
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
# TypeError: cannot convert dictionary update sequence element #0 to a sequence

However, if my class subclasses collections.Mapping then it works fine:

import collections
class Mapping(collections.Mapping):def __init__(self, dict={}): self.dict=dictdef __iter__(self): return iter(self.dict)def __iter__(self): return iter(self.dict)def __len__(self): return len(self.dict)def __contains__(self, value): return value in self.dictdef __getitem__(self, name): return self.dict[name]m=Mapping({5:5})
dict(m)
# {5: 5}

I thought the whole point of the ABCs was to allow registration to work the same as subclassing (for isinstance and issubclass anyway). So what's up here?

Answer

Registration does not give you the "missing methods" implemented on top of those you define: in fact, registration is non-invasive with respect to the type you're registering -- nothing gets added to it, nothing gets removed, nothing gets altered. It only affects isinstance and issubclass checks: nothing more, nothing less.

Subclassing an ABC can and does give you plenty of methods implemented "for free" by the ABC on top of those you're having to define yourself.

The semantics of an operation that's totally non-invasive like registering, compared to those of an operation that's intended to enrich a class, like subclassing, obviously cannot be identical; so your understanding of "the whole point of the ABCs" is imperfect -- ABCs have two points, one obtained by subclassing ("invasive"), one by registering (non-invasive).

Note that you can always multiply-inherit if you already have a class like your original Mapping: class GoogMapping(Mapping, collections.Mapping): ... will give you the same results as inheriting Mapping directly from collections.Mapping -- a new type with all the auxiliary methods added by collections.Mapping.

https://en.xdnf.cn/q/72438.html

Related Q&A

python - ensure script is activated only once

Im writing a Python 2.7 script. In summary, this script is being run every night on Linux and activates several processes.Id like to ensure this script is not run multiple times in parallel (basically …

How to set up auto-deploy to AppEngine when pushing to Git Repository

Ive heard that other platforms support auto-deployment of their code to production when they push changes to their Git repository.Can I set up something similar to this for AppEngine? How?Im using Py…

#include zbar.h 1 error generated when running pip install zbar

Im trying to run pip install zbar and for some reason I cant seem to find an answer to solve this dependency issue. Any help would be extremely appreciated. See traceback below:Downloading/unpacking zb…

Django model field default based on another model field

I use Django Admin to build a management site. There are two tables, one is ModelA with data in it, another is ModelB with nothing in it. If one model field b_b in ModelB is None, it can be displayed o…

How do I improve remove duplicate algorithm?

My interview question was that I need to return the length of an array that removed duplicates but we can leave at most 2 duplicates. For example, [1, 1, 1, 2, 2, 3] the new array would be [1, 1, 2, 2,…

Looking for values in nested tuple

Say I have:t = ((dog, Dog),(cat, Cat),(fish, Fish), )And I need to check if a value is in the first bit of the nested tuple (ie. the lowercase bits). How can I do this? The capitalised values do not m…

Multiple lines user input in command-line Python application

Is there any easy way to handle multiple lines user input in command-line Python application?I was looking for an answer without any result, because I dont want to:read data from a file (I know, its t…

Performance difference between filling existing numpy array and creating a new one

In iterative algorithms, it is common to use large numpy arrays many times. Frequently the arrays need to be manually "reset" on each iteration. Is there a performance difference between fill…

Set space between boxplots in Python Graphs generated nested box plots with Seaborn?

I am trying to set a space between the boxplots (between the green and orange boxes) created with Python Seaborn modules sns.boxplot(). Please see attached the graph, that the green and orange subplot …

Geocoding using Geopy and Python

I am trying to Geocode a CSV file that contains the name of the location and a parsed out address which includes Address number, Street name, city, zip, country. I want to use GEOPY and ArcGIS Geocodes…