5

For one of the project I am currently working I was thinking of creating a class that could not be instantiate by a client and only be supplied an instance of through a particular interface i.e. the client would not be able create further instance out of it by some hackery such as:

>>> 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

once he has one.

I was successfully able to create a class that couldn't be instantiated. i.e.

>>> 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

But how could I use this every same definition to create an instance of the class?

Of course I could do something like this:

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

but I don't find it elegant enough nor does it completely prevent the client from further instantiating it. And no I aint going down the road of building a C++ module for it.

Any suggestions on how to achieve such a thing? import abc?

A brief rational to answer Martijn's question and for completeness:

Actual you could consider the instance of the particular, and related, classes, in question, as nodes in a tree and that both the parent and the children to remain connected, dependent on and cognizant of each other and have a single unique root throughout any instance of python(insured by the use package). Any state changes in a particular node would cause others to update themselves and the database to which they are connect, accordingly. Apart from that I was being curious to know how such a thing could be put in place (the traceback class was teasing me).

4

1 回答 1

13

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


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

当声明类似x = Foo()发生的事情时:

  1. x = object.__new__(Foo)首先被调用并创建对象。
  2. Foo.__init__(x)第二个被调用,它只是将一些属性等初始化为已经存在的对象。

这意味着您不需要调用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's 实例方法:

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'

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

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'
于 2013-04-23T13:54:58.597 回答