简体   繁体   English

Python-为什么当我检查返回的对象不是NoneType时,此方法为什么返回NoneType?

[英]Python - why does this method return NoneType when I've checked that the object I'm returning is not NoneType?

I have code in which all objects descend from a base object, which I don't plan to instantiate directly. 我有代码,其中所有对象都来自基础对象,我不打算直接实例化该对象。 In the __init__() method of my base object I'm trying to perform some magic -- I am trying to decorate, or wrap, every method of the object being initialized. 在我的基础对象的__init__()方法中,我试图执行一些魔术操作–我试图装饰或包装要初始化的对象的每个方法。 But I'm getting a result that puzzles me when I call the resulting methods. 但是当我调用结果方法时,得到的结果使我感到困惑。 Here is example code that isolates the problem: 这是解决问题的示例代码:

class ParentObject(object):
    def __init__(self):
        self._adjust_methods(self.__class__)

    def _adjust_methods(self, cls):
        for attr, val in cls.__dict__.iteritems():
            if callable(val) and not attr.startswith("_"):
                setattr(cls, attr, self._smile_warmly(val))
        bases = cls.__bases__
        for base in bases:
            if base.__name__ != 'object':
                self._adjust_methods(base)

    def _smile_warmly(self, the_method):
        def _wrapped(cls, *args, **kwargs):
            print "\n-smile_warmly - " +cls.__name__
            the_method(self, *args, **kwargs)
        cmethod_wrapped = classmethod(_wrapped)
        return cmethod_wrapped

class SonObject(ParentObject):
    def hello_son(self):
        print "hello son"

    def get_sister(self):
        sis = DaughterObject()
        print type(sis)
        return sis

class DaughterObject(ParentObject):
    def hello_daughter(self):
        print "hello daughter"

    def get_brother(self):
        bro = SonObject()
        print type(bro)
        return bro

if __name__ == '__main__':
    son = SonObject()
    son.hello_son()

    daughter = DaughterObject()
    daughter.hello_daughter()

    sis = son.get_sister()
    print type(sis)
    sis.hello_daughter()

    bro = sis.get_brother()
    print type(bro)
    bro.hello_son()

The program crashes, however -- the line sis = son.get_sister() results in the sis object having a type of NoneType. 程序崩溃,但是-行sis = son.get_sister()导致sis对象的类型为NoneType。 Here is the output: 这是输出:

-smile_warmly - SonObject
hello son

-smile_warmly - DaughterObject
hello daughter

-smile_warmly - SonObject
<class '__main__.DaughterObject'>
<type 'NoneType'>
Traceback (most recent call last):
  File "metaclass_decoration_test.py", line 48, in <module>
    sis.hello_daughter()
AttributeError: 'NoneType' object has no attribute 'hello_daughter'

Why is this happening? 为什么会这样呢?

Try changing: 尝试更改:

    def _wrapped(cls, *args, **kwargs):
        print "\n-smile_warmly - " +cls.__name__
        the_method(self, *args, **kwargs)

to

    def _wrapped(cls, *args, **kwargs):
        print "\n-smile_warmly - " +cls.__name__
        return the_method(self, *args, **kwargs)

Your _wrapped method is calling the method that is being wrapped, but not returning that method's return value. 您的_wrapped方法正在调用被包装的方法,但不返回该方法的返回值。

Well, I don't really want to even touch the craziness that is going on in this code, but your error specifically is because your "decorator" is not returning anything from the wrapped function: 好吧,我什至根本不想触碰这段代码中发生的疯狂行为,但是您的错误特别是因为您的“装饰器”没有从包装函数中返回任何内容:

def _smile_warmly(self, the_method):
    def _wrapped(cls, *args, **kwargs):
        print "\n-smile_warmly - " +cls.__name__
        return the_method(self, *args, **kwargs) # return here
    cmethod_wrapped = classmethod(_wrapped)
    return cmethod_wrapped

The problem is that you are wrapping all methods of your classes, including get_sister . 问题是您包装了所有类的方法,包括get_sister You could do as @Paul McGuire suggests and add the return to the wrapper, but that will mean that the "smile" message is printed when you call son.get_sister , which probably isn't what you want. 您可以按照@Paul McGuire的建议进行操作,然后将return添加到包装器中,但这将意味着在您调用son.get_sister时会打印“微笑”消息,这可能不是您想要的。

What you probably need to do instead is add some logic inside _adjust_methods to decide precisely which methods to wrap. 相反,您可能需要做的是在_adjust_methods添加一些逻辑,以精确地确定要包装的方法。 Instead of just checking for callable and not startswith('_') , you could have some naming convention for ones you do or don't want to wrap with smile behavior. 除了可以检查callablenot startswith('_') ,您还可以为自己喜欢或不想用smile行为包装的对象设置一些命名约定。 However, the more you do this, the less the automatic decoration will benefit you as compared to just manually decorating the methods you want to decorate. 但是,与仅手动装饰要装饰的方法相比,您执行的越多,自动装饰对您的好处就越少。 It's a little hard to understand why you want to use the structure you apparently want to use (all classmethods, wrapping everything, etc.). 很难理解为什么要使用您显然要使用的结构(所有类方法,包装所有内容等)。 Perhaps if you explained what your ultimate goal is here someone could suggest a more straightforward design. 也许,如果您在这里解释了您的最终目标是什么,那么有人可以建议一种更直接的设计。

Moreover, even if you add the return or the extra logic for wrapping, you'll still have the problem I mentioned in your other question: since you do the wrapping in __init__ , it is going to happen every time you instantiate a class, so you will keep adding more and more wrappers. 而且,即使您添加了return或用于包装的额外逻辑,您仍然会有我在另一个问题中提到的问题:由于您在__init__进行包装,因此每次实例化一个类时都会发生这种情况,因此您将继续添加越来越多的包装器。 This is why I suggested there that you should use a class decorator, or, if you must, a metaclass. 这就是为什么我在那里建议您使用类装饰器,或者,如果需要的话,使用元类的原因。 Messing with class attributes (including methods) in __init__ is not a good idea because they'll get messed with over and over, once for each instance you create. __init__处理类属性(包括方法)不是一个好主意,因为对于创建的每个实例,它们都会一遍又一遍地弄乱。

The missing return in @PaulMcGuire's reply is the cause of the bug. @PaulMcGuire的答复中缺少返回值是导致此错误的原因。

On a higher level, it looks like you're trying to do via inheritance what might more "commonly" (this is hardly a common approach) be done via a metaclass. 在更高的层次上,您似乎正在尝试通过继承来完成通过元类完成的“更常见”(这几乎不是通用方法)的事情。 Maybe something like this discussion of metaclasses would point you in a slightly more manageable direction. 也许像这样的元类讨论会为您指出一个更易于管理的方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 为什么即使我返回一个值,我的函数也返回 nonetype? - Why is my function returning nonetype even as I'm returning a value? 尝试删除具有m2m关系的项目时,为什么我无法调用&#39;NoneType&#39;对象? - Why do I get 'NoneType' object is not callable when trying to delete item with m2m relations? 为什么当函数“ None”不返回时,python在NoneType上失败? - Why does python fail on NoneType when “None” doesnt return in function? 为什么我在 python 中收到错误“TypeError: &#39;NoneType&#39; object is not subscriptable”? - Why do I get the error "TypeError: 'NoneType' object is not subscriptable" in python? 为什么当我扩展列表时,它的类型是“NoneType”? - Why when I extend a list does it have 'NoneType' as type? TypeError:“ NoneType”对象不可迭代 当我在python中使用生成器时 - TypeError: 'NoneType' object is not iterable | when I using generator in python 为什么此函数返回NoneType? - Why does this function return NoneType? 为什么 fetchone()[0] 返回“Nonetype” - Why does fetchone()[0] return a 'Nonetype' 当我在Python中裁剪图像时,它返回&#39;NoneType&#39; - When I crop an image in Python, it returns 'NoneType' 为什么 Python 中的 re.search 返回一个 NoneType 对象? - Why is re.search in Python returning a NoneType object?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM