Python 元类的奇怪继承

Python 元类的奇怪继承,python,inheritance,metaclass,Python,Inheritance,Metaclass,当我试图从一个带有元类的类继承时,在Python中遇到了一些非常奇怪的问题。我有这个: class NotifierMetaclass(type): def __new__(cls, name, bases, dct): attrs = ((name, value) for name, value in dct.items() if not name.startswith('__')) def wrap_met

当我试图从一个带有元类的类继承时,在Python中遇到了一些非常奇怪的问题。我有这个:

class NotifierMetaclass(type):

    def __new__(cls, name, bases, dct):

        attrs = ((name, value) for name, value in dct.items()
                    if not name.startswith('__'))

        def wrap_method(meth):
            return instance_wrapper()(meth) # instance_wrapper is a decorator of my own

        def is_callable(value):
            return hasattr(value, '__call__')

        decorated_meth = dict(
            (name, value) if not is_callable(value)
            else (name, wrap_method(value))
            for name, value in attrs
        )

        return super(NotifierMetaclass, cls).__new__(
            cls, name, bases, decorated_meth
        )


class Notifier(object):

    def __init__(self, instance):
        self._i = instance

    __metaclass__ = NotifierMetaclass
然后,在notifiers.py中:

from helpers import Notifier

class CommentNotifier(Notifier):

    def __notification__(self, notification):
        return '%s has commented on your board' % self.sender

    def __notify__(self):
        receivers = self.retrieve_users()
        notif_type = self.__notificationtype__()
        for user in receivers:
            Notification.objects.create(
                object_id=self.id,
                receiver=user,
                sender_id=self.sender_id,
                type=notif_type
            )
然而,当我尝试导入CommentNotifier时,它返回Notifier。在外壳中:

$ python
Python 2.7.3 (default, Apr 20 2012, 22:44:07) 
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from logic.notifiers import CommentNotifier
>>> CommentNotifier
<class 'helpers.CommentNotifier'>
$python
Python 2.7.3(默认值,2012年4月20日,22:44:07)
[GCC 4.6.3]关于linux2
有关详细信息,请键入“帮助”、“版权”、“信用证”或“许可证”。
(InteractiveConsole)
>>>从logic.notifiers导入CommentNotifier
>>>评论通知程序
事实上,这(至少我是这么认为的)实际上和我一周前遇到的一些问题是一样的。起初我认为这与Django的工作方式有关,但现在我怀疑这更像是一个Python元类和继承的“问题” 这是一个已知的问题,还是我只是做错了?希望你能帮助我。

编辑:我忘了提到我把这个“错误”归因于元类,因为如果我不给通知程序一个元类,它就会按预期工作。

好的,我想我已经解决了。正在导入正确的类。只是名字不对。如果在类上设置属性,您应该能够看到这一点。如果将
someJunk=“Notifier”
放入通知程序定义中,并将
someJunk=“CommentNotifier”
放入CommentNotifier定义中,则导入CommentNotifier时,它将具有正确的值

问题在于,在创建
属性时,排除了所有双下划线属性,包括
\uuuu模块\uuu
。当您调用超类
\uuuuuu new\uuuuuuu
时,您会传入
attrs
,它没有
\uuuuu模块\uuuuuuuuuuu
条目,因此Python会为您创建一个条目。但是,由于此代码是在包含元类的文件中执行的,因此模块被错误地设置为元类的文件,而不是实际类的文件

我没有看到您观察到的类的实际名称的行为,只看到了模块的行为。也就是说,对于我来说,导入的类名为
metafile.CommentNotifier
,其中
metafile
是包含元类的文件。它应该命名为
submeta.CommentNotifier
,其中
submeta
是包含CommentNotifierClass的文件。我不知道为什么您也会在
\uuuuu name\uuuuu
中看到它,但如果在不同的Python版本中对模块/名称分配的一些细微处理有所不同,我也不会感到惊讶

\uuuuuuuuuuuu通知
\uuuuuu通知
不是Python神奇的方法。看起来您排除了双下划线方法,因为您使用双下划线来表示您自己的目的。你不应该这样做。如果必须,请为您自己的方法使用一些其他前缀(如
\u Notifier
或其他内容),然后排除这些方法并保留双下划线的方法。排除双下划线方法可能会导致其他问题。特别是,如果您决定在使用此元类的类上定义真正的魔术方法(例如,
\uuu str\uu
),则会导致失败


(澄清一下:如果您愿意,可以使用以双下划线开头的方法作为私有属性,尽管这可能不是一个好主意。但是,如果您这样做,您需要确保只对这些属性进行特殊处理,而不是以双下划线开头和结尾的属性,这是Python内部的魔法hods.你不应该做的是创建以双下划线开头和结尾的自己的名字,比如
\uuuuu notify\uuuuuu

你的例子对我来说是正确的。你是否没有在“东西”中遗漏重要的东西部分?请提供一个实际展示您所指行为的示例。只需编辑真实案例的代码i get
(仅使用两个文件,
helpers.py
notifiers.py
),和
,如果我把它放在一个包中。试着将它进一步压缩,并在不同的地方粘贴一些打印语句,以排除您没有导入您认为是的版本的可能性。我也得到了@DSM看到的行为。我相信您的问题不是导入了错误的类,而是它给了它wrong名称(或至少是错误的
\uuuuuuu模块\uuuuuu
)。提到了同样的问题,但没有答案。似乎
\uuuu module\uuuuu
被错误地设置为元类的模块,而不是类的模块。我仍在试图解决它…+1,但我发现类名差异真的令人费解。我也在使用2.7.3。不是+1而是+1000,你真的给了我一个Pyth在第一课上。首先,我想为“helpers.Notifier”产生的所有混乱道歉。事实上,它是“helpers.CommentNotifier”解释器说了什么,但我不知怎么修改了文本却没有注意到。很抱歉。其次,你的猜测完全正确,如果我省略了对
“\uuuuuuu”
的检查,它实际上正确设置了
\uuuuuu模块\uuuuuu
属性并保留了
\uuuuuu foo\uuuuuuuu
方法。最后,但并非最不重要的是,它是方法nami的事实ng.我从来没有对
\uuuufoo\uuuu
的命名感到完全满意,但它确实有效。我应该重新考虑一下。