如何创建一个不可实例化的类?

时间:2013-04-23 13:44:58

标签: python instantiation objectinstantiation

对于我目前正在工作的项目之一,我正在考虑创建一个无法由客户端实例化的类,并且只通过特定接口提供实例,即客户端无法创建更多实例。它是由一些hackery,如:

>>> try:
...     raise WindowsError
... except:
...     foo = sys.exc_info()
... 
>>> foo
(<type 'exceptions.WindowsError'>, WindowsError(), <traceback object at 0x0000000005503A48>)
>>> type(foo[2])()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'traceback' instances

一旦有了。

我成功地创建了一个无法实例化的类。即。

>>> class Foo():
...     def __init__(self):
...         raise TypeError("cannot create 'Foo' instances")
... 
>>> bar = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in __init__
TypeError: cannot create 'Foo' instances
>>> bar
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'bar' is not defined

但是我怎么能用这个相同的定义创建一个类的实例呢?

当然我可以这样做:

>>> class Foo():
...     def __init__(self, instantiate = False):
...         if not instantiate:
...               raise TypeError("cannot create 'Foo' instances")

但我发现它不够优雅,也不能完全阻止客户端进一步实例化它。不,我不会为它构建一个C ++模块。

关于如何实现这样的事情的任何建议? import abc

回答Martijn的question以及完整性的简短理由:

实际上,您可以将有问题的特定类和相关类的实例视为树中的节点,并确保父级和子级保持连接,依赖于彼此并认识到并且具有唯一的唯一遍及任何python实例的root(由use package保险)。特定节点中的任何状态更改都会导致其他人自行更新,并相应地更新它们所连接的数据库。除此之外,我很想知道如何安排这样的事情(traceback课程在戏弄我)。

1 个答案:

答案 0 :(得分:11)

你所做的是一个坏主意,你不应该这样做。 我确信还有其他更好的解决方案。 如果您确实决定采用自己的方式(不应该),那么您可以在不使用__init__()的情况下创建对象:


python中的对象是使用__new__()方法创建的。方法__init__()仅编辑由__new__()创建的对象。例如,__init__()通常会初始化对象的某些属性。

当声明x = Foo()之类的内容时,会发生什么:

    首先调用
  1. x = object.__new__(Foo)并创建对象。
  2. Foo.__init__(x)被调用为秒,它只是将一些属性等初始化为现有对象。
  3. 这意味着您无需致电Foo()(因此,也请致电__init__())。相反,您可以直接致电__new__()

    class Foo(object):
        def __init__(self):
            raise TypeError("Cannot create 'Foo' instances.")
    
    >>> x = object.__new__(Foo)
    >>> x
    <__main__.Foo object at 0x02B074F0>
    

    我们的x现在是Foo的一个实例,没有任何属性,它可以使用Foo类中定义的任何方法。

    如果需要,您可以创建自己的__init__替换函数来初始化属性:

    def init_foo(foo, name):
        foo.name = name
    
    >>> init_foo(x, "Mike")
    >>> x.name
    'Mike'
    

    这当然也可以是Foo的实例方法:

    class Foo(object):
        def __init__(self):
            raise TypeError("Cannot create 'Foo' instances.")
    
        def init(self, name):
            self.name = name
    
    >>> x = object.__new__(Foo)
    >>> x.init("Mike")
    >>> x.name
    'Mike'
    

    更进一步,您甚至可以使用classmethod仅使用一次调用来创建对象:

    class Foo(object):
        def __init__(self):
            raise TypeError("Cannot create 'Foo' instances.")
    
        @classmethod
        def new(cls, name):
            obj = object.__new__(cls)
            obj.name = name
            return obj
    
    >>> x = Foo.new("Mike")
    >>> x.name
    'Mike'