当我试图从一个带有元类的类继承时,我在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
然后,在通知程序.py公司名称:
^{pr2}$但是,当我尝试导入CommentNotifier时,它返回Notifier。在外壳中:
^{3}$事实上,这(至少我是这么想的)实际上和我一周前遇到的问题一样。起初我认为这与Django的工作方式有关,但现在我怀疑这更像是一个Python的元类和继承问题。
这是已知的问题还是我只是做错了什么?希望你能帮助我。
编辑:我忘了提到我把这个“错误”归因于元类,因为如果我不给通知程序一个元类,它就会按预期工作。在
好吧,我想我知道了。正在导入正确的类。只是名字不对。如果在类上设置属性,应该可以看到这一点。如果您将
someJunk = "Notifier"
放在通知程序定义中,someJunk = "CommentNotifier"
放在CommentNotifier定义中,那么当您导入CommentNotifier时,它将具有正确的值。在问题是在创建
attrs
时,排除了所有双下划线属性,包括__module__
。当您调用超类__new__
时,您将传入您的attrs
,它没有__module__
项,因此Python会为您创建一个。因为这个文件并没有正确地在元类中执行,而不是在元类中执行。在我没有看到您观察到的类的实际名称的行为,只有模块的行为。也就是说,对我来说,导入的类名为
metafile.CommentNotifier
,其中metafile
是包含元类的文件。它应该命名为submeta.CommentNotifier
,其中submeta
是包含CommentNotifierClass的文件。我不知道您为什么也看到__name__
,但是如果模块/名称分配的一些细微处理在不同的Python版本中有所不同,我也不会感到惊讶。在__notify__
和__notification__
不是Python魔术方法。似乎您排除了双下划线方法,因为您使用双下划线来表示某些东西是出于您自己的目的。你不应该这么做。如果必须,请为自己的方法使用其他前缀(如_Notifier
或其他),然后排除这些方法,并保留双下划线的方法。排除双下划线方法可能会导致其他问题。特别是,如果您决定在使用这个元类的类上定义一个真正的魔术方法(例如__str__
),它将导致失败。在(澄清一下:如果需要,可以使用带有双下划线的开头的方法作为私有属性,尽管这可能不是一个好主意。但是,如果您这样做,您需要确保只对这些属性进行特殊处理,而不是那些以和结尾的属性,这是Python内部的魔术方法。您不应该创建以双下划线开头和结尾的自己的名称,例如
__notify__
。)相关问题 更多 >
编程相关推荐