如何在Python中编写一次性或匿名类?
我经常会有一些简单的类,我只想要一个实例。举个简单的例子:
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-off
和 anonymous
这些词,但似乎没有人说我想说的内容)。我试过这个,但没成功:
example = class(object):
def methodOne(self, a, b):
return a + b
def methodTwo(self, a, b):
return a * b
我意识到这样做其实没什么大用,只是少了一行代码要打,还有一个东西在我的命名空间里少了,所以我理解如果这功能不存在也没关系。
5 个回答
在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
(@mgilson的回答是最直接的解决方案。我也认为你的原始代码比这里的任何答案都要好)
如果你不需要使用任何特殊的函数(比如 __repr__
),那么可以用一个简单、易读的方式,只需使用一个函数字典(充当方法的角色):
fake_obj = dict(method_one = lambda a,b: a+b, method_two = lambda a,b: a*b)
你可以使用元类,这样相比于@mgilson的回答,你可以用更好看的语法。
class OneOff(type):
def __new__(cls, name, bases, attrs):
klass = type.__new__(cls, name, bases, attrs)
return klass()
class PS1(object):
__metaclass__ = OneOff
...
不过,我和其他人一样觉得这可能不是个好主意。我曾经做过类似的事情,但那是为了一个非常特定的用途,我建议你先考虑其他的解决办法。此外,这看起来很像单例模式,所以也许采用单例模式会更合适。
你可以用一个简单的类装饰器来把这个类替换成它的一个实例:
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
如果你这么做的话,可能想把类名改成小写,因为最后它是用来命名一个实例,而不是类。
这样做虽然还是需要多一行代码,但不需要在命名空间里再多一个名字。
如果你真的想的话,可以写一个元类来自动完成同样的事情。不过,我觉得这样做并不会比手动实例化类省多少力气,而且肯定会让代码变得更复杂,更难理解。
我觉得你可能不常见到这个,因为它真的很难读懂,不过……
sys.ps1 = type('PS1', (object,), {'__repr__': lambda self: datetime.datetime.now().strftime('%H:%M:%S')})()
这样做就可以解决问题……
我用 type
来动态创建一个类(参数包括类名、基类和类字典)。在这个例子中,类字典里只包含一个函数 __repr__
。
希望我们能达成共识,完整的格式要更容易理解和使用 ;-).