The _
and __
prefixes don't offer a solution to restricting instantiation of an object to a specific 'factory', however Python is a powerful toolbox and the desired behaviour can be achieved in more than one way (as @Jesse W at Z has demonstrated).
Here is a possible solution that keeps the class publicly visible (allowing isinstance
etc.) but ensures construction is only possible by class-methods:
class OnlyCreatable(object):
__create_key = object()
@classmethod
def create(cls, value):
return OnlyCreatable(cls.__create_key, value)
def __init__(self, create_key, value):
assert(create_key == OnlyCreatable.__create_key),
"OnlyCreatable objects must be created using OnlyCreatable.create"
self.value = value
Constructing an object with the create
class-method:
>>> OnlyCreatable.create("I'm a test")
<__main__.OnlyCreatable object at 0x1023a6f60>
When attempting to construct an object without using the create
class-method creation fails due to the assertion:
>>> OnlyCreatable(0, "I'm a test")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in __init__
AssertionError: OnlyCreatable objects can only be created using OnlyCreatable.create
If attempting to create an object by mimicking the create
class-method
creation fails due to compiler mangling of OnlyCreatable.__createKey
.
>>> OnlyCreatable(OnlyCreatable.__createKey, "I'm a test")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'OnlyCreatable' has no attribute '__createKey'
The only way to construct OnlyCreatable
outside of a class-method is to know the value of OnlyCreatable.__create_key
. Since this class-attribute's value is generated at runtime and it's name is prefixed with __ marking it as inaccessible it is effectively 'impossible' to obtain this value and/or construct the object.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…