简体   繁体   English

装饰器(类)对象何时被销毁?

[英]When is a decorator (class) object destroyed?

I am using a decorator to open and close a neo4j database session (and allow my decorated functions to run queries within that session). 我正在使用装饰器打开和关闭neo4j数据库会话(并允许经过装饰的函数在该会话中运行查询)。 At first I used a decorator function : 首先,我使用了一个装饰器函数:

 from neo4j.v1 import GraphDatabase, basic_auth
 def session(func,url="bolt://localhost:7474", user="neo4j",pwd="neo4j", *args, **kwargs):
     def operate(*args, **kwargs):
         driver = GraphDatabase.driver(url, auth=basic_auth(user,pwd))
         session=driver.session()
         kwargs["session"]=session 
         result=func(*args, **kwargs)
         session.close()
         return result
     return operate

and for example I then call this function: 例如,然后我调用此函数:

@session
def RUN(command,session):
    result=session.run(command)
    return(result)

However, this opens and closes the session for every query which is resource consuming. 但是,这会打开和关闭每个消耗资源的查询的会话。 Thus, I tried to create a decorator class, and store the session: 因此,我试图创建一个装饰器类,并存储会话:

class session(object):
    def __init__(self, func, url="bolt://localhost", user="neo4j", pwd="neo4j"):
        try:
            driver = GraphDatabase.driver(url, auth=basic_auth(user, pwd))
            print("session opened")
        except:
            print("Exception during authentification")
            self.__exit__()
        else:
            session=driver.session()
            self.func=func
            self.SESSION=session

    def __call__(self, *args, **kwargs):
        kwargs["session"]=self.SESSION 
        result=self.func(*args, **kwargs)
        return result
    def __del__(self):
        print("del")
        try:
            self.SESSION.close()
            print("session closed")
        except:
            print("could not close session") 

This seems to work, as the "session opened" appears only once. 这似乎可行,因为“打开的会话”仅出现一次。 But the session does not seem to close ("session close" is never printed). 但是会话似乎没有关闭(从未打印“会话关闭”)。

So my first question is the following, how can I call the self.SESSION.close() at the destruction of the decorator ? 因此,我的第一个问题是,如何在装饰器破坏时调用self.SESSION.close()?

I'm also wondering if I understood well what my code is doing. 我也想知道我是否了解我的代码在做什么。 When I call a decorated function such as RUN , is only one session object created? 当我调用经过修饰的函数(例如RUN ,是否仅创建了一个会话对象? And what if I were to have an other decorated function MATCH 而如果我要拥有另一个装饰功能MATCH ,该怎么办?

@session
def MATCH(*args,**kwargs):
    pass

would the session object be the same ? 会话对象会相同吗?

How to 如何

Here is a template to create a decorator with parameters using a function: 这是一个使用函数创建带有参数的装饰器的模板:

def decorator_maker(param1, param2):
    print("The parameters of my decorator are: {0} and {1}".format(param1, param2))

    def my_decorator(function_to_decorate):
        def wrapper(arg1, arg2):
            print("before call")
            result = function_to_decorate(arg1, arg2)
            print("after call")
            return result

        return wrapper

    return my_decorator

The usage is as follow: 用法如下:

@decorator_maker("hello", "How are you?")
def my_function(arg1, arg2):
    print("The parameters of my function are: {0} and {1}".format(arg1, arg2))
    return arg1 + "-" + arg2

With a class, it is more straightforward: 对于一个类,它更简单:

class decorator_maker(object):
    def __init__(self, param1, param2):
        print("The parameters of my decorator are: {0} and {1}".format(param1, param2))
        self.param1 = param1
        self.param2 = param2

    def __call__(self, function_to_decorate):
        def wrapper(arg1, arg2):
            print("before call")
            result = function_to_decorate(arg1, arg2)
            print("after call")
            return result

        return wrapper

Answer 回答

To open and close your session before/after the function call, you have to implement it in the wrapped function, like this: 要在函数调用之前/之后打开和关闭会话,您必须在包装的函数中实现它,如下所示:

class with_session(object):
    def __init__(self, url="bolt://localhost", user="neo4j", pwd="neo4j"):
        self.url = url
        self.user = user
        self.pwd = pwd

    def __call__(self, f):
        def wrapper(*args, **kwargs):
            driver = GraphDatabase.driver(self.url, auth=basic_auth(self.user, self.pwd))
            kwargs["session"] = session = driver.session()
            try:
                return f(*args, **kwargs)
            finally:
                session.close()

        return wrapper

Notes: 笔记:

  • You can let the exception raises... 您可以让异常引发...
  • You should rename the decorator (like I did) to avoid shadowing the name "session". 您应该重命名装饰器(就像我一样),以免遮盖“会话”名称。
  • This decorator is not aa context manager. 此装饰器不是上下文管理器。 For that you need to use __enter__ and __exit__ , this is another use case... 为此,您需要使用__enter____exit__ ,这是另一个用例...

Reference 参考

See: How to make a chain of function decorators? 请参阅: 如何制作功能装饰器链?

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM