如何在Python中编写一次性或匿名类?

5 投票
5 回答
2553 浏览
提问于 2025-04-18 14:19

我经常会有一些简单的类,我只想要一个实例。举个简单的例子:

import datetime
import sys

class PS1(object):
    def __repr__(self):
        now = datetime.datetime.now()
        return str(now.strftime("%H:%M:%S"))

sys.ps1 = PS1()

有没有办法可以把定义和实例化合并成一步,达到同样的效果呢?

再举个例子,这个也简单得容易理解。

class Example(object):
    def methodOne(self, a, b):
        return a + b

    def methodTwo(self, a, b):
        return a * b

example = Example()

我在网上搜索了一下,没找到相关的信息(很多人提到 one-offanonymous 这些词,但似乎没有人说我想说的内容)。我试过这个,但没成功:

example = class(object):
    def methodOne(self, a, b):
        return a + b

    def methodTwo(self, a, b):
        return a * b

我意识到这样做其实没什么大用,只是少了一行代码要打,还有一个东西在我的命名空间里少了,所以我理解如果这功能不存在也没关系。

5 个回答

0

在Python中,有两种方法可以实现这个功能。第一种是创建一个单例对象,这可以通过装饰器来完成;第二种是让类本身成为使用的对象,利用类方法和类变量。

第一种选择(单例)看起来是这样的:

def apply_class(*args, **kwargs):
    def myclass(c):
        c(*args,**kwargs)
    return myclass

@apply_class(5)
class mysingleton(object):
    def __init__(self, x):
        print x

第二种选择(类方法/变量)看起来是这样的:

class mysingleton:
    myvariable = 5
    @classmethod
    def mymethod(cls):
        print cls.myvariable
0

(@mgilson的回答是最直接的解决方案。我也认为你的原始代码比这里的任何答案都要好)

如果你不需要使用任何特殊的函数(比如 __repr__),那么可以用一个简单、易读的方式,只需使用一个函数字典(充当方法的角色):

fake_obj = dict(method_one = lambda a,b: a+b, method_two = lambda a,b: a*b)
0

你可以使用元类,这样相比于@mgilson的回答,你可以用更好看的语法。

class OneOff(type):
    def __new__(cls, name, bases, attrs):
        klass = type.__new__(cls, name, bases, attrs)
        return klass()

class PS1(object):
    __metaclass__ = OneOff

    ...

不过,我和其他人一样觉得这可能不是个好主意。我曾经做过类似的事情,但那是为了一个非常特定的用途,我建议你先考虑其他的解决办法。此外,这看起来很像单例模式,所以也许采用单例模式会更合适。

2

你可以用一个简单的类装饰器来把这个类替换成它的一个实例:

def instantiator(cls):
    return cls()

然后这样使用它:

@instantiator
class PS1(object):
    def __repr__(self):
        now = datetime.datetime.now()
        return str(now.strftime("%H:%M:%S"))

接下来:

>>> PS1
11:53:37

如果你这么做的话,可能想把类名改成小写,因为最后它是用来命名一个实例,而不是类。

这样做虽然还是需要多一行代码,但不需要在命名空间里再多一个名字。

如果你真的想的话,可以写一个元类来自动完成同样的事情。不过,我觉得这样做并不会比手动实例化类省多少力气,而且肯定会让代码变得更复杂,更难理解。

7

我觉得你可能不常见到这个,因为它真的很难读懂,不过……

sys.ps1 = type('PS1', (object,), {'__repr__': lambda self: datetime.datetime.now().strftime('%H:%M:%S')})()

这样做就可以解决问题……

我用 type 来动态创建一个类(参数包括类名、基类和类字典)。在这个例子中,类字典里只包含一个函数 __repr__

希望我们能达成共识,完整的格式要更容易理解和使用 ;-).

撰写回答