类属性的python全局装饰器

Der*_*ist 2 python properties decorator python-3.x

下面是一段抽象的代码,它简化了我遇到的问题。在此示例中,我有一个具有登录和注销属性的程序。登录与版本无关,注销与版本相关。

class A(class):
    def __init__(self):
        self.version = "1.0"

        self.login = "logged in"
        self.login_message = "hello logger"
        self.logout = {"1.0": "logged out",
                       "2.0": "logged out 2.0"}
        self.logout_message = {"1.0": "goodbye logger",
                               "2.0": "goodbye logger 2.0"}

    def perform(self, executor):
        executor.do(self.login)
        executor.do(self.logout)
Run Code Online (Sandbox Code Playgroud)

executor是一个执行实际操作的外部接口,它应该接收一个字符串。该do功能无法更改。版本可以并且会在运行时改变,所以我正在寻找某种全局装饰器/属性,当访问装饰属性时,它会调用一个函数。目标是在每个版本发送到executor.do.

答案显然是改变perform功能executer.do(self.logout[self.version]),但self.loginself.logout不宜不同的方式访问。有些继承self.logout只是一个字符串,并且perform是共享的。

我在想这样的事情:

self.version = "1.0"

self.login = "logged in"        
self.login_message = "hello logger"
@by_version
self.logout = {"1.0": "logged out",
               "2.0": "logged out 2.0"}
@by_version
self.logout_message = {"1.0": "goodbye logger",
                       "2.0": "goodbye logger 2.0"}

def by_version(self, attribute):
    return attribute[self.version]
Run Code Online (Sandbox Code Playgroud)

那显然行不通。这甚至可能吗?

Mik*_*ler 6

手动解决方案

看起来像property装饰器的用例:

class A(object):
    def __init__(self):
        self.version = "1.0"

        self.login = "logged in"
        self.login_message = "hello logger"

    @property    
    def logout(self):
        return {"1.0": "logged out", "2.0": "logged out 2.0"}[self.version]

    @property    
    def logout_message(self):
        return {"1.0": "goodbye logger", "2.0": "goodbye logger 2.0"}[self.version]
Run Code Online (Sandbox Code Playgroud)

现在:

>>> a = A()
>>> a.login
'logged in'
>>> a.logout
'logged out'
>>> a.version = '2.0'
>>> a.logout
'logged out 2.0'     
Run Code Online (Sandbox Code Playgroud)

自动化解决方案 1

如果你有很多这样的属性,你可以自动化一点:

class A(object):
    def __init__(self):
        self.version = '1.0'
        self.login = 'logged in'
        self.login_message = 'hello logger'
        property_attrs = {'logout': {'1.0': 'logged out', 
                                     '2.0': 'logged out 2.0'},
                          'logout_message': {'1.0': 'goodbye logger',
                                             '2.0': 'goodbye logger 2.0'}}
        for name, value in property_attrs.items():
            setattr(self.__class__, name, property(lambda x: value[x.version]))
Run Code Online (Sandbox Code Playgroud)

现在:

>>> a = A()
>>> a.login_message
'hello logger'
>>> a.logout
'goodbye logger'
>>> a.version = '2.0'
>>> a.logout
'goodbye logger 2.0'
Run Code Online (Sandbox Code Playgroud)

自动化解决方案 2

每次创建新实例时,“自动化解决方案 1”都会重新定义属性A。此解决方案避免了这种情况,但涉及更多。它使用类装饰器。

property_attrs = {'logout': {'1.0': 'logged out', '2.0': 'logged out 2.0'},
                  'logout_message': {'1.0': 'goodbye logger', '2.0': 'goodbye logger 2.0'}}

def add_properties(property_attrs):
    def decorate(cls):
        for name, value in property_attrs.items():
            setattr(cls, name, property(lambda self: value[self.version]))
        return cls
    return decorate

@add_properties(property_attrs)
class A(object):
    def __init__(self):
        self.version = '1.0'
        self.login = 'logged in'
        self.login_message = 'hello logger'
Run Code Online (Sandbox Code Playgroud)

现在:

>>> a = A()
>>> a.logout
'goodbye logger'
>>> a.version = '2.0'
>>> a.logout
'goodbye logger 2.0'
Run Code Online (Sandbox Code Playgroud)