【问题标题】:When is a decorator (class) object destroyed?装饰器(类)对象何时被销毁?
【发布时间】:2016-10-07 15:10:47
【问题描述】:

我正在使用装饰器来打开和关闭 neo4j 数据库会话(并允许我的装饰函数在该会话中运行查询)。起初我使用了一个装饰器功能:

 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

然后我调用这个函数:

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

但是,这会为每个消耗资源的查询打开和关闭会话。因此,我尝试创建一个装饰器类,并存储会话:

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") 

这似乎有效,因为“会话已打开”只出现一次。但会话似乎没有关闭(“会话关闭”从未打印出来)。

所以我的第一个问题如下,我如何在装饰器销毁时调用 self.SESSION.close() ?

我也想知道我是否很好地理解了我的代码在做什么。当我调用RUN 之类的修饰函数时,是否只创建了一个会话对象?如果我有另一个装饰函数MATCH

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

会话对象是否相同?

【问题讨论】:

  • 当它装饰的所有函数消失时,该类可能会消失(在这种情况下,看起来每个装饰的函数都有一个会话)。如果函数处于模块级别,则答案是在解释器关闭之前会话不会关闭(并且可能甚至不会关闭)。

标签: python database-connection decorator python-decorators


【解决方案1】:

如何

这是一个使用函数创建带有参数的装饰器的模板:

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

用法如下:

@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

有了类,就更直接了:

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

回答

要在函数调用之前/之后打开和关闭会话,您必须在包装函数中实现它,如下所示:

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

注意事项:

  • 您可以让异常引发...
  • 您应该重命名装饰器(就像我所做的那样)以避免掩盖名称“会话”。
  • 此装饰器不是上下文管理器。为此,您需要使用__enter____exit__,这是另一个用例...

参考

见:How to make a chain of function decorators?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-04-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多