【问题标题】:From a list, dynamically create methods with name-awareness从列表中,动态创建具有名称感知的方法
【发布时间】:2018-03-02 21:49:08
【问题描述】:

我正在尝试编写一个简单的控制台颜色实用程序,它采用一个充满 ANSI 代码的类并在我的控制台实用程序上生成一些辅助方法,这样我就可以使用console.add('text', 'blue') 而不是 console.blue('text')。

我知道我可以静态定义所有这些(例如def blue(self, s):),但是如果我想添加 100 个左右的助手(不是我愿意,但是 如果.. .)

这是简单的 ANSI 映射:

class _AnsiColors:
    def __init__(self):
        self.green = 35
        self.red = 1
        self.blue = 32
        self.yellow = 214
        self.amber = 208
        self.olive = 106
        self.orange = 166
        self.purple = 18
        self.pink = 197
        self.gray = 243
        self.dark_gray = 238
        self.light_gray = 248
        self.black = 0
        self.white = 255
        self.debug = 24

ansi = _AnsiColors()

还有控制台实用程序(将方法代理到pyfancy 并使用colors):

import copy 

from colors import color    
from pyfancy import *

from ansi import ansi

class console(object):
    def __init__(self, s):
        self._s = pyfancy(s)

    def add(self, s, c='white'):
        if hasattr(ansi, self.add.__name__):
            c = self.add.__name__
        self._s.add(color(s, fg=getattr(ansi, c)))
        return self

    def bold(self, s):
        self._s.bold(s)
        return self

    def raw(self, s):
        self._s.raw(s)  
        return self

    def dim(self, s):
        self._s.dim(s)      
        return self

    def print(self):
        self._s.output()

# Inject ansi color convenience methods
for c in vars(ansi):
    setattr(console, c, copy.deepcopy(console.add))
    getattr(console, c).__name__ = c

然后我可以这样使用它:

console('raw').bold(' bold').raw(' raw').blue(' blue').red(' red').print()

您可以看到帮助方法 blue 和 red 至少执行,所以我复制 add() 有效,但是这里发生的事情(尽管我认为我可以用 copy.deepcopy 解决它)是当我尝试设置每个方法副本的__name__ 属性时,它设置了对add 的引用,而我最终得到的所有彩色输出都是相同的颜色(ansi.debug)。

有没有办法在不静态定义每个助手的情况下做我想做的事情?


没有颜色的MCVE/pyfancy:

import copy 

from ansi import ansi

class console(object):
    def __init__(self, s):
        self._s = s

    def add(self, s, c='white'):
        if hasattr(ansi, self.add.__name__):
            c = self.add.__name__
        self._s += '%s(%s)' % (s, c)
        return self

    def print(self):
        print(self._s)

# Inject ansi color convenience methods
for c in vars(ansi):
    setattr(console, c, copy.deepcopy(console.add))
    getattr(console, c).__name__ = c

console('white').blue(' blue').red(' red').print()

# white blue(debug) red(debug)

【问题讨论】:

标签: python python-3.x introspection


【解决方案1】:

我会用闭包解决它:

class console(object):
    def __init__(self, s):
        self._s = s
        for color in vars(ansi):
            self._colorizer(color)

    def _colorizer(self, c):        
        def add(s):
            self._s += '%s(%s)' % (s, c)
            return self

        self.__setattr__(c, add)

    def print(self):
        print(self._s)

console('white').blue(' blue').red(' red').print()
# white blue(blue) red(red)

【讨论】:

  • 绝妙的答案!谢谢。 Fwiw,我认为您可以完全跳过 _add 函数并直接在 vars(ansi) 循环中调用它。对于我的用例,因为我在全局范围内使用color,所以我必须重命名一些循环变量和函数名称,以免破坏内容。
  • 是的,我误解了 add 函数的作用并进行了相应的编辑;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 2019-12-18
相关资源
最近更新 更多