在 Programming Python 中,Mark Lutz 提到了术语 mixin。我来自 C/C++/C# 背景,之前没有听说过这个词。什么是混音?
在 this example 的行之间阅读(我已经链接到它,因为它很长),我假设这是使用多重继承来扩展类而不是适当的子类化的情况。这是正确的吗?
为什么我要这样做而不是将新功能放入子类中?就此而言,为什么混合/多重继承方法比使用组合更好?
混合继承与多重继承有什么区别?这只是语义问题吗?
Curiously Recurring Template Pattern
) 将多个基类功能添加到您的类中。这类似于混合提供的内容。调试很有趣。
mixin 是一种特殊的多重继承。使用mixin主要有两种情况:
你想为一个类提供很多可选特性。你想在很多不同的类中使用一个特定的特性。
对于第一个示例,请考虑 werkzeug's request and response system。我可以通过说来制作一个普通的旧请求对象:
from werkzeug import BaseRequest
class Request(BaseRequest):
pass
如果我想添加接受标头支持,我会这样做
from werkzeug import BaseRequest, AcceptMixin
class Request(AcceptMixin, BaseRequest):
pass
如果我想创建一个支持接受标头、etags、身份验证和用户代理支持的请求对象,我可以这样做:
from werkzeug import BaseRequest, AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin
class Request(AcceptMixin, ETagRequestMixin, UserAgentMixin, AuthenticationMixin, BaseRequest):
pass
区别是微妙的,但在上面的例子中,mixin 类并不是独立存在的。在更传统的多重继承中,AuthenticationMixin
(例如)可能更像 Authenticator
。也就是说,该类可能被设计为独立存在。
首先,您应该注意 mixin 仅存在于多继承语言中。你不能在 Java 或 C# 中做一个 mixin。
基本上,mixin 是一种独立的基本类型,它为子类提供有限的功能和多态共振。如果您正在考虑使用 C#,请考虑一个您不必实际实现的接口,因为它已经实现了;您只需从它继承并受益于它的功能。
Mixin 的范围通常很窄,并不打算扩展。
[编辑——至于为什么:]
既然你问了,我想我应该说明原因。最大的好处是您不必一遍又一遍地自己做。在 C# 中,mixin 可能受益的最大地方可能是 Disposal pattern。每当您实现 IDisposable 时,您几乎总是希望遵循相同的模式,但您最终会编写和重写相同的基本代码,但会有细微的变化。如果有一个可扩展的 Disposal mixin,你可以节省很多额外的输入。
[编辑2——回答你的其他问题]
混合继承与多重继承有什么区别?这只是语义问题吗?
是的。 mixin 和标准多重继承之间的区别只是语义问题。具有多重继承的类可能会利用 mixin 作为多重继承的一部分。
mixin 的重点是创建一个可以通过继承“混入”任何其他类型的类型,而不影响继承的类型,同时仍然为该类型提供一些有益的功能。
同样,考虑一个已经实现的接口。
我个人不使用 mixins,因为我主要使用不支持它们的语言进行开发,所以我很难想出一个像样的例子来提供“啊哈!”给你的时刻。但我会再试一次。我将使用一个人为设计的示例——大多数语言已经以某种方式提供了该功能——但希望这将解释应该如何创建和使用 mixin。开始:
假设您有一个类型,您希望能够序列化到 XML 和从 XML 序列化。您希望该类型提供一个“ToXML”方法,该方法返回一个包含具有该类型数据值的 XML 片段的字符串,以及一个允许该类型从字符串中的 XML 片段重建其数据值的“FromXML”。同样,这是一个人为的示例,因此您可能使用文件流,或者您语言的运行时库中的 XML Writer 类……随便。关键是您希望将对象序列化为 XML 并从 XML 中获取新对象。
此示例中的另一个重点是您希望以通用方式执行此操作。您不想为每个要序列化的类型实现“ToXML”和“FromXML”方法,您需要一些通用的方法来确保您的类型能够执行此操作并且它可以正常工作。你想要代码重用。
如果您的语言支持它,您可以创建 XmlSerializable mixin 来为您完成工作。这种类型将实现 ToXML 和 FromXML 方法。它将使用一些对示例不重要的机制,能够从混合的任何类型中收集所有必要的数据,以构建由 ToXML 返回的 XML 片段,并且当 FromXML 是时,它同样能够恢复该数据叫。
而且..就是这样。要使用它,您需要将任何需要序列化为 XML 的类型从 XmlSerializable 继承。每当您需要序列化或反序列化该类型时,您只需调用 ToXML 或 FromXML。事实上,由于 XmlSerializable 是一个成熟的类型和多态性,您可以想象构建一个对原始类型一无所知的文档序列化程序,只接受一个 XmlSerializable 类型的数组。
现在想象一下将此场景用于其他事情,例如创建一个 mixin 以确保将它混合到每个类中记录每个方法调用,或者创建一个为混合它的类型提供事务性的 mixin。这个列表可以继续下去。
如果您只是将 mixin 视为一种小型基础类型,旨在为类型添加少量功能而不会影响该类型,那么您就是黄金。
希望。 :)
该答案旨在通过以下示例解释 mixins:
自包含:简短,无需了解任何库即可理解示例。
在 Python 中,而不是在其他语言中。可以理解,有来自其他语言(例如 Ruby)的示例,因为该术语在这些语言中更为常见,但这是一个 Python 线程。
它还应考虑有争议的问题:
是否需要多重继承来表征mixin?
定义
我还没有看到来自“权威”来源的引文清楚地说明什么是 Python 中的 mixin。
我已经看到了 2 种可能的 mixin 定义(如果它们被认为与其他类似概念不同,例如抽象基类),人们并不完全同意哪个是正确的。
不同语言之间的共识可能会有所不同。
定义1:没有多重继承
mixin 是一个类,该类的某些方法使用了该类中未定义的方法。
因此,该类不打算实例化,而是用作基类。否则,实例将具有无法在不引发异常的情况下调用的方法。
一些来源添加的一个约束是该类可能不包含数据,只有方法,但我不明白为什么这是必要的。然而在实践中,许多有用的 mixin 没有任何数据,并且没有数据的基类更易于使用。
一个经典示例是仅从 <=
和 ==
实现所有比较运算符:
class ComparableMixin(object):
"""This class has methods which use `<=` and `==`,
but this class does NOT implement those methods."""
def __ne__(self, other):
return not (self == other)
def __lt__(self, other):
return self <= other and (self != other)
def __gt__(self, other):
return not self <= other
def __ge__(self, other):
return self == other or self > other
class Integer(ComparableMixin):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
# It is possible to instantiate a mixin:
o = ComparableMixin()
# but one of its methods raise an exception:
#o != o
这个特定示例可以通过 functools.total_ordering()
装饰器实现,但这里的游戏是重新发明轮子:
import functools
@functools.total_ordering
class Integer(object):
def __init__(self, i):
self.i = i
def __le__(self, other):
return self.i <= other.i
def __eq__(self, other):
return self.i == other.i
assert Integer(0) < Integer(1)
assert Integer(0) != Integer(1)
assert Integer(1) > Integer(0)
assert Integer(1) >= Integer(1)
定义2:多重继承
mixin 是一种设计模式,其中基类的某些方法使用它未定义的方法,并且该方法旨在由另一个基类实现,而不是由定义 1 中的派生类实现。
术语 mixin 类指的是打算在该设计模式中使用的基类(TODO 那些使用该方法的,还是那些实现它的?)
判断一个给定的类是否是mixin并不容易:该方法可能只是在派生类上实现,在这种情况下我们回到定义1。你必须考虑作者的意图。
这种模式很有趣,因为可以将功能与不同的基类选择重新组合:
class HasMethod1(object):
def method(self):
return 1
class HasMethod2(object):
def method(self):
return 2
class UsesMethod10(object):
def usesMethod(self):
return self.method() + 10
class UsesMethod20(object):
def usesMethod(self):
return self.method() + 20
class C1_10(HasMethod1, UsesMethod10): pass
class C1_20(HasMethod1, UsesMethod20): pass
class C2_10(HasMethod2, UsesMethod10): pass
class C2_20(HasMethod2, UsesMethod20): pass
assert C1_10().usesMethod() == 11
assert C1_20().usesMethod() == 21
assert C2_10().usesMethod() == 12
assert C2_20().usesMethod() == 22
# Nothing prevents implementing the method
# on the base class like in Definition 1:
class C3_10(UsesMethod10):
def method(self):
return 3
assert C3_10().usesMethod() == 13
权威的 Python 事件
在 official documentatiton for collections.abc,文档明确使用了术语 Mixin 方法。
它指出,如果一个类:
实现 __next__
从单个类 Iterator 继承
然后该类免费获得一个 __iter__
mixin 方法。
因此至少在文档的这一点上,mixin 不需要多重继承,并且与定义 1 一致。
当然,文档在不同点上可能是矛盾的,其他重要的 Python 库可能在其文档中使用其他定义。
该页面还使用了术语 Set mixin
,它清楚地表明像 Set
和 Iterator
这样的类可以称为 Mixin 类。
在其他语言中
Ruby:显然不需要 mixin 的多重继承,正如主要参考书籍如 Programming Ruby 和 The Ruby programming Language 中提到的
C++:设置=0的虚方法是纯虚方法。定义 1 与抽象类(具有纯虚方法的类)的定义一致。该类无法实例化。定义 2 可以使用虚拟继承:来自两个派生类的多重继承
Set
和 Iterator
这样的类可以称为 Mixin 类。”那么它是否与您的 mixin 类定义 1 相矛盾,后者要求 mixin 类使用它们未定义的方法,因为 Iterator
违反了该要求(参见它的 implementation)?
我认为它们是使用多重继承的一种规范方式——因为最终,mixin 只是另一个 python 类,它(可能)遵循关于称为 mixin 的类的约定。
我对管理你称之为 Mixin 的东西的约定的理解是,一个 Mixin:
添加方法但不添加实例变量(类常量可以)
仅继承自对象(在 Python 中)
这样,它限制了多重继承的潜在复杂性,并通过限制您必须查看的位置(与完全多重继承相比)来相当容易地跟踪程序的流程。它们类似于 ruby modules。
如果我想添加实例变量(具有比单继承所允许的更大的灵活性),那么我倾向于进行组合。
话虽如此,我已经看到名为 XYZMixin 的类确实具有实例变量。
混合继承与多重继承有什么区别?这只是语义问题吗?
mixin 是一种有限的多重继承形式。在某些语言中,向类添加 mixin 的机制(在语法方面)与继承的机制略有不同。
特别是在 Python 的上下文中,mixin 是一个父类,它为子类提供功能,但并不打算实例化它本身。
可能导致您说“这只是多重继承,而不是真正的 mixin”的原因是,如果实际上可以实例化和使用可能被混淆为 mixin 的类,那么它确实是一种语义上的、非常真实的差异。
多重继承的例子
此示例 from the documentation 是一个 OrderedCounter:
class OrderedCounter(Counter, OrderedDict): '记住第一次遇到的顺序元素的计数器' def __repr__(self): return '%s(%r)' % (self.__class__.__name__, OrderedDict(self)) def __reduce__( self): 返回 self.__class__, (OrderedDict(self),)
它从 collections
模块继承 Counter
和 OrderedDict
。
Counter
和 OrderedDict
都旨在单独实例化和使用。但是,通过对它们进行子类化,我们可以有一个有序的计数器并重用每个对象中的代码。
这是一种重用代码的强大方法,但也可能存在问题。如果事实证明其中一个对象存在错误,那么不小心修复它可能会在子类中产生错误。
Mixin 示例
Mixin 通常被推广为一种获得代码重用的方法,而不会出现协作多重继承(如 OrderedCounter)可能存在的潜在耦合问题。当您使用 mixin 时,您使用的功能与数据没有紧密耦合。
与上面的示例不同,mixin 并不打算单独使用。它提供了新的或不同的功能。
例如,标准库有几个 mixins in the socketserver
library。
可以使用这些混合类创建每种类型服务器的分叉和线程版本。例如,ThreadingUDPServer 的创建如下: class ThreadingUDPServer(ThreadingMixIn, UDPServer): pass 混合类首先出现,因为它覆盖了 UDPServer 中定义的方法。设置各种属性也会改变底层服务器机制的行为。
在这种情况下,mixin 方法会覆盖 UDPServer
对象定义中的方法以允许并发。
被覆盖的方法似乎是 process_request
,它还提供了另一种方法 process_request_thread
。这是来自 source code:
class ThreadingMixIn: """混合类来处理新线程中的每个请求。""" # 决定线程将如何在主进程终止时采取行动 daemon_threads = False def process_request_thread(self, request, client_address): "" "和 BaseServer 中一样,但作为线程。另外,这里进行异常处理。""" try: self.finish_request(request, client_address) except Exception: self.handle_error(request, client_address) finally: self.shutdown_request(request ) def process_request(self, request, client_address): """启动一个新线程来处理请求。""" t = threading.Thread(target = self.process_request_thread, args = (request, client_address)) t.daemon = self.daemon_threads t.start()
一个人为的例子
这是一个主要用于演示目的的 mixin - 大多数对象的发展将超出此 repr 的用途:
class SimpleInitReprMixin(object):
"""mixin, don't instantiate - useful for classes instantiable
by keyword arguments to their __init__ method.
"""
__slots__ = () # allow subclasses to use __slots__ to prevent __dict__
def __repr__(self):
kwarg_strings = []
d = getattr(self, '__dict__', None)
if d is not None:
for k, v in d.items():
kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
slots = getattr(self, '__slots__', None)
if slots is not None:
for k in slots:
v = getattr(self, k, None)
kwarg_strings.append('{k}={v}'.format(k=k, v=repr(v)))
return '{name}({kwargs})'.format(
name=type(self).__name__,
kwargs=', '.join(kwarg_strings)
)
用法是:
class Foo(SimpleInitReprMixin): # add other mixins and/or extend another class here
__slots__ = 'foo',
def __init__(self, foo=None):
self.foo = foo
super(Foo, self).__init__()
和用法:
>>> f1 = Foo('bar')
>>> f2 = Foo()
>>> f1
Foo(foo='bar')
>>> f2
Foo(foo=None)
Mixins 是编程中的一个概念,其中类提供了功能,但并不打算用于实例化。 Mixins 的主要目的是提供独立的功能,最好是 mixins 本身不与其他 mixins 继承并避免状态。在 Ruby 等语言中,有一些直接的语言支持,但对于 Python,则没有。但是,您可以使用多类继承来执行 Python 中提供的功能。
我观看了此视频 http://www.youtube.com/watch?v=v_uKI2NOLEM 以了解 mixin 的基础知识。对于初学者来说,了解 mixin 的基础知识、它们的工作原理以及在实现它们时可能遇到的问题是非常有用的。
维基百科仍然是最好的:http://en.wikipedia.org/wiki/Mixin
我认为之前的回答很好地定义了 MixIn 是什么。然而,为了更好地理解它们,从代码/实现的角度比较 MixIn 与抽象类和接口可能会很有用:
1.抽象类
需要包含一个或多个抽象方法的类
抽象类可以包含状态(实例变量)和非抽象方法
2.接口
接口仅包含抽象方法(没有非抽象方法和内部状态)
3. 混音
MixIns(如接口)不包含内部状态(实例变量)
MixIn 包含一个或多个非抽象方法(与接口不同,它们可以包含非抽象方法)
在例如 Python 中,这些只是约定,因为以上所有内容都定义为 class
es。然而,抽象类、接口和MixIns的共同特点是它们不应该单独存在,即不应该被实例化。
我认为这里有一些很好的解释,但我想提供另一种观点。
在 Scala 中,您可以像这里描述的那样执行 mixins,但非常有趣的是,mixin 实际上是“融合”在一起以创建一种新的类来继承。本质上,您不会从多个类/mixin 继承,而是生成一种新的类,其中包含要继承的 mixin 的所有属性。这是有道理的,因为 Scala 基于当前不支持多重继承的 JVM(从 Java 8 开始)。顺便说一下,这种 mixin 类类型是 Scala 中称为 Trait 的特殊类型。
在定义类的方式中暗示了这一点:类 NewClass 用 SecondMixin 和 ThirdMixin 扩展 FirstMixin ...
我不确定 CPython 解释器是否也这样做(mixin 类组合),但我不会感到惊讶。此外,来自 C++ 背景,我不会将 ABC 或“接口”称为与 mixin 等价的东西——这是一个相似的概念,但在使用和实现上有所不同。
我建议不要在新的 Python 代码中混入,如果你能找到任何其他方法(比如组合而不是继承,或者只是猴子修补方法到你自己的类中),那就不多了努力。
在旧式类中,您可以使用混入作为从另一个类中获取一些方法的一种方式。但在新式世界中,一切,甚至是混入,都继承自 object
。这意味着任何使用多重继承自然会引入 MRO issues。
有一些方法可以让多继承 MRO 在 Python 中工作,最值得注意的是 super() 函数,但这意味着您必须使用 super() 来完成整个类层次结构,而且理解控制流要困难得多。
也许几个例子会有所帮助。
如果您正在构建一个类并且希望它像字典一样工作,您可以定义所有各种必要的 __ __
方法。但这有点痛苦。作为替代方案,您可以只定义一些,并从 UserDict.DictMixin
继承(除了任何其他继承之外)(在 py3k 中移至 collections.DictMixin
)。这将具有自动定义所有其余字典 api 的效果。
第二个示例:GUI 工具包 wxPython 允许您制作具有多列的列表控件(例如,Windows 资源管理器中的文件显示)。默认情况下,这些列表是相当基本的。您可以添加其他功能,例如通过单击列标题、从 ListCtrl 继承并添加适当的 mixin 来按特定列对列表进行排序的能力。
这不是 Python 示例,但在 the D programing language 中,术语 mixin
用于指代使用方式大致相同的构造;在课堂上添加一堆东西。
在 D 中(顺便说一句,它不做 MI),这是通过将模板(认为语法感知和安全的宏,你将接近)插入范围来完成的。这允许将类、结构、函数、模块或其他任何内容中的单行代码扩展为任意数量的声明。
OP 提到他/她从未听说过 C++ 中的 mixin,可能是因为它们在 C++ 中被称为 Curiously Recurring Template Pattern (CRTP)。此外,@Ciro Santilli 提到 mixin 是通过 C++ 中的抽象基类实现的。虽然可以使用抽象基类来实现 mixin,但这是一种矫枉过正的做法,因为可以在编译时使用模板来实现运行时的虚函数功能,而无需在运行时进行虚拟表查找的开销。
详细描述了 CRTP 模式 here
我已经使用下面的模板类将@Ciro Santilli 的答案中的 python 示例转换为 C++:
#include <iostream>
#include <assert.h>
template <class T>
class ComparableMixin {
public:
bool operator !=(ComparableMixin &other) {
return ~(*static_cast<T*>(this) == static_cast<T&>(other));
}
bool operator <(ComparableMixin &other) {
return ((*(this) != other) && (*static_cast<T*>(this) <= static_cast<T&>(other)));
}
bool operator >(ComparableMixin &other) {
return ~(*static_cast<T*>(this) <= static_cast<T&>(other));
}
bool operator >=(ComparableMixin &other) {
return ((*static_cast<T*>(this) == static_cast<T&>(other)) || (*(this) > other));
}
protected:
ComparableMixin() {}
};
class Integer: public ComparableMixin<Integer> {
public:
Integer(int i) {
this->i = i;
}
int i;
bool operator <=(Integer &other) {
return (this->i <= other.i);
}
bool operator ==(Integer &other) {
return (this->i == other.i);
}
};
int main() {
Integer i(0) ;
Integer j(1) ;
//ComparableMixin<Integer> c; // this will cause compilation error because constructor is protected.
assert (i < j );
assert (i != j);
assert (j > i);
assert (j >= i);
return 0;
}
编辑:在 ComparableMixin 中添加了受保护的构造函数,以便它只能被继承而不能被实例化。更新了示例以显示在创建 ComparableMixin 对象时受保护的构造函数将如何导致编译错误。
mixin 提供了一种在类中添加功能的方法,即您可以通过将模块包含在所需的类中来与模块中定义的方法进行交互。尽管 ruby 不支持多重继承,但提供了 mixin 作为实现这一目标的替代方案。
这是一个示例,解释了如何使用 mixin 实现多重继承。
module A # you create a module
def a1 # lets have a method 'a1' in it
end
def a2 # Another method 'a2'
end
end
module B # let's say we have another module
def b1 # A method 'b1'
end
def b2 #another method b2
end
end
class Sample # we create a class 'Sample'
include A # including module 'A' in the class 'Sample' (mixin)
include B # including module B as well
def S1 #class 'Sample' contains a method 's1'
end
end
samp = Sample.new # creating an instance object 'samp'
# we can access methods from module A and B in our class(power of mixin)
samp.a1 # accessing method 'a1' from module A
samp.a2 # accessing method 'a2' from module A
samp.b1 # accessing method 'b1' from module B
samp.b2 # accessing method 'a2' from module B
samp.s1 # accessing method 's1' inside the class Sample
我只是使用 python mixin 来实现 python milters 的单元测试。通常情况下,milter 会与 MTA 对话,从而使单元测试变得困难。测试 mixin 会覆盖与 MTA 对话的方法,并创建一个由测试用例驱动的模拟环境。
因此,您采用未经修改的 milter 应用程序,例如 spfmilter 和 mixin TestBase,如下所示:
class TestMilter(TestBase,spfmilter.spfMilter):
def __init__(self):
TestBase.__init__(self)
spfmilter.config = spfmilter.Config()
spfmilter.config.access_file = 'test/access.db'
spfmilter.spfMilter.__init__(self)
然后,在 milter 应用程序的测试用例中使用 TestMilter:
def testPass(self):
milter = TestMilter()
rc = milter.connect('mail.example.com',ip='192.0.2.1')
self.assertEqual(rc,Milter.CONTINUE)
rc = milter.feedMsg('test1',sender='good@example.com')
self.assertEqual(rc,Milter.CONTINUE)
milter.close()
http://pymilter.cvs.sourceforge.net/viewvc/pymilter/pymilter/Milter/test.py?revision=1.6&view=markup
也许 ruby 的一个例子可以帮助:
您可以包含 mixin Comparable
并定义一个函数 "<=>(other)"
,mixin 提供所有这些函数:
<(other)
>(other)
==(other)
<=(other)
>=(other)
between?(other)
它通过调用 <=>(other)
并返回正确的结果来做到这一点。
如果两个对象相等,"instance <=> other"
返回 0,如果 instance
大于 other
,则返回小于 0,如果 other
更大,则返回大于 0。
__lt__
定义为基础而不是 __cmp__
,但后者实际上已被弃用并且不鼓励使用。对我来说,使用该 mixin 而不是相当复杂的 decorators(functools 的一部分)似乎更简单——尽管 this one 可能能够对 which 提供的比较做出更动态的反应......
我读到你有 ac# 背景。因此,一个好的起点可能是 .NET 的 mixin 实现。
您可能想查看 http://remix.codeplex.com/ 上的 codeplex 项目
观看 lang.net Symposium 链接以获得概览。 codeplex 页面上的文档还有更多内容。
问候斯特凡
这个概念来自 Steve’s Ice Cream,这是一家由 Steve Herrell 于 1973 年在马萨诸塞州萨默维尔创立的冰淇淋店,mix-ins(糖果、蛋糕等)被混合到基本冰淇淋中口味(香草、巧克力等)。
受 Steve's Ice Cream 的启发,Lisp 对象系统 Flavors 的设计者首次将这一概念包含在编程语言中,其中包含用于增强称为 mix-ins 的其他类的小型帮助程序类和大型称为 flavors 的独立类。
所以主要思想是混入是一个可重用的扩展('reusable' 相对于'exclusive';'extension' 相对于'base')。
该概念与单继承或多继承以及抽象或具体类的概念正交。混合类可以用于单继承或多继承,可以是抽象类或具体类。混入类的接口不完整,抽象类的实现不完整,具体类的实现完整。
混合类名称通常以“-MixIn”、“-able”或“-ible”作为后缀以强调它们的性质,例如在 Python 标准库中的 socketserver
的 ThreadingMixIn
和 ForkingMixIn
类模块,以及 collections.abc
模块的 Hashable
、Iterable
、Callable
、Awaitable
、AsyncIterable
和 Reversible
类。
以下是扩展 Python 内置 list
和 dict
类并具有日志记录功能的混合类示例:
import logging
class LoggingMixIn:
def __setitem__(self, key, value):
logging.info('Setting %r to %r', key, value)
super().__setitem__(key, value)
def __delitem__(self, key):
logging.info('Deleting %r', key)
super().__delitem__(key)
class LoggingList(LoggingMixIn, list):
pass
class LoggingDict(LoggingMixIn, dict):
pass
>>> logging.basicConfig(level=logging.INFO)
>>> l = LoggingList([False])
>>> d = LoggingDict({'a': False})
>>> l[0] = True
INFO:root:Setting 0 to True
>>> d['a'] = True
INFO:root:Setting 'a' to True
>>> del l[0]
INFO:root:Deleting 0
>>> del d['a']
INFO:root:Deleting 'a'