【问题标题】:Fudging the line between classes and functions混淆类和函数之间的界限
【发布时间】:2016-02-18 21:23:22
【问题描述】:

我有一系列用于对数据进行分类的函数。每个函数都传递相同的输入。该系统的目标是能够随意添加新的分类功能,而无需进行任何调整。

为此,我使用了从here 提升的classes_in_module 函数。然后,一个 python 文件中的每个分类器将在每个输入上运行。

但是,我发现将分类器实现为类或函数是很笨拙的。类意味着实例化和执行,而函数缺乏清晰的自省来允许我查询名称或使用继承来定义公共值。

这是一个例子。一、类实现:

class AbstractClassifier(object):
    @property
    def name(self):
        return self.__class__.__name__

class ClassifierA(AbstractClassifier):
    def __init__(self, data):
        self.data = data
    def run(self):
        return 1

然后可以以这种方式使用它,假设classifier_list 是包含ClassifierA 等文件的classes_in_module 的输出:

result = []
for classifier in classifier_list:
    c = classifier(data)
    result.append(c.run())

但是,这似乎有点愚蠢。这个类显然是静态的,并不真正需要维护自己的状态,因为它被使用一次并被丢弃。分类器实际上是一个函数,但是我失去了共享name 属性的能力——我将不得不使用丑陋的内省技术sys._getframe().f_code.co_name 并为每个分类器函数复制该代码。并且分类器之间的任何其他共享属性也会丢失。

你怎么看?我应该接受这种对课程的滥用吗?还是有更好的办法?

【问题讨论】:

  • 你的分类器函数真的需要查找自己的名字吗?
  • 也许妥协是使用@staticmethod装饰器?
  • @jwodder 这会让事情变得更方便。不过,您是对的,我可以解决名称问题。但是,抽象基类中还有其他共享属性,我没有在示例中包含。
  • @IanFiddes 函数有一个func_name 属性,还可以包含成员数据(参见下面的示例)

标签: python


【解决方案1】:

函数可以有成员数据。您还可以使用func_name 属性查找函数的名称。

def classifier(data):
    return 1
classifier.name = classifier.func_name

print(classifier.name) #classifier

如果您希望多个函数的行为方式相同,可以使用装饰器。

function_tracker = []

def add_attributes(function):
    function.name = function.func_name
    function.id = len(function_tracker)
    function_tracker.append(function)
    return function

@add_attributes
def classifier(data):
    return 1

print(classifier.name, classifier.id) # 'classifier', 0

这是否可以避免在您的特定情况下上课?

【讨论】:

    【解决方案2】:

    如果您不需要该类的多个实例(而且您似乎不需要)创建该类的一个实例并将run 更改为__call__

    class AbstractClassifier(object):
        @property
        def name(self):
            return self.__class__.__name__
    
    class ClassifierA(AbstractClassifier):
        def __call__(self, data):
            return 1
    ClassifierA = ClassifierA()       # see below for alternatives
    

    然后在你的其他代码中:

    result = []
    for classifier in classifier_list:
        result.append(classifier(data))
    

    除了ClassifierA = ClassifierA()(不是很优雅),还可以这样做:

    classifier_list = [c() for c in (ClassifierA, ClassifierB, ...)]
    

    如果您需要创建更多的类实例,此方法可让您方便地使用您的类;如果您不需要多个实例,则可以使用装饰器来 IAYG(随您进行实例化;):

    def instantiate(cls):
        return cls()
    
    @instantiate
    class ClassifierZ(object):
        def __call__(self, data):
            return some_classification
    

    【讨论】:

    • 最后一行(多余的点)有语法错误。
    • 那一定是ClassifierA()(),对吧?一次实例化,然后实际调用第二对括号。
    • @MarkDickinson:不,这些类在创建列表时已经实例化,或者在创建类之后立即实例化。
    • 啊,对不起;我明白你现在在做什么。不过,ClassifierA = ClassifierA() 非常可怕。 :-)
    • @MarkDickinson:是的,这就是我添加list 评论的原因;或者,可以使用 @instantiate 装饰器;这取决于 OP 可能对这些类做什么。
    【解决方案3】:

    将类实例用作函数:

    class ClassifierA(AbstractClassifier):
        def __init__(self, data):
            self.data = data
        def __call__(self):
            return 1
    
    result = []
    for classifier in classifier_list:
        c = classifier(data)
        result.append(c())
    

    或者只使用函数:

    classifier_list = []
    def my_decorator(func):
        classifier_list.append(func)
        return func
    
    @my_decorator
    def classifier_a(data):
        return 1
    
    result = []
    for classifier in classifier_list:
        c = classifier(data)
        result.append(c)
    

    【讨论】:

      猜你喜欢
      • 2015-03-03
      • 1970-01-01
      • 2010-11-22
      • 2013-07-16
      • 1970-01-01
      • 1970-01-01
      • 2013-08-14
      • 2016-09-22
      • 2015-06-01
      相关资源
      最近更新 更多