Constructeur privé en Python
comment créer un constructeur privé qui ne devrait être appelé que par la fonction statique de la classe et non d'où?
6 réponses
comment créer un constructeur privé?
En substance, c'est impossible à la fois parce que python n'utilise pas les constructeurs comme vous pouvez le penser si vous venez d'autres langues OOP et parce que python n'utilise pas appliquer la vie privée, il y a une syntaxe spécifique à penser qu'une telle méthode/propriété devrait être considéré comme privé. Permettez-moi de préciser...
premier: Le plus proche d'un constructeur que vous pouvez trouver en python est l' __new__
méthode mais ceci est très rarement utilisé (vous utilisez normalement __init__
modifier la juste objet créé (en fait, il a déjà self
comme premier paramètre).
peu importe, python est basé sur l'hypothèse que tout le monde est un adultes consentants, donc privé/public n'est pas appliqué comme certains autres langues.
tel que mentionné par d'autres répondants, les méthodes qui sont censées être "privé" sont normalement précédées par un ou deux traits de soulignement: _private
ou __private
. La différence entre les deux est que le dernier brouillera le nom de la méthode, de sorte que vous serez incapable de l'appeler de l'extérieur de l'instanciation de l'objet, alors que le premier ne le fait pas.
alors par exemple si votre classe A
définit les deux _private(self)
et __private(self)
:
>>> a = A()
>>> a._private() # will work
>>> a.__private() # will raise an exception
vous voulez normalement utiliser le simple underscore, comme-spécialement pour les tests unitaires - ayant double les soulignements peuvent rendre les choses très délicates....
HTH!
Citant le Guide du style Python (PEP 8):
En outre, les formulaires à l'aide avant ou après les soulignements sont reconnus (ils peuvent généralement être combinés avec n'importe quel cas convention):
from M import * " n'importe pas les objets dont le nom commence par un underscore.
single_trailing_underscore_
: utilisé par convention pour éviter les conflits avec d' Mot-clé Python, par exempleTkinter.Toplevel(master, class_='ClassName')
__double_leading_underscore
: en nommant un attribut de classe, invoque le nom mangling (à l'intérieur de la classe FooBar,__boo
devient_FooBar__boo
; voir ci-dessous).
__double_leading_and_trailing_underscore__
: objets "magiques" ou attributs qui vivent dans des espaces de noms contrôlés par l'utilisateur. E. g.__init__
,__import__
ou__file__
. N'inventez jamais de tels noms; utilisez-les seulement comme il est indiqué.
_
et __
les préfixes n'offrent pas de solution pour restreindre l'instanciation d'un objet à une "usine" spécifique, cependant Python est une boîte à outils puissante et le comportement désiré peut être atteint de plus d'une manière (comme @Jesse W at Z l'a démontré).
Voici une solution possible qui maintient la classe publiquement visible (permettant isinstance
etc.) mais assure que la construction n'est possible que par des méthodes de classe:
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
construire un objet avec le create
classe-méthode:
>>> OnlyCreatable.create("I'm a test")
<__main__.OnlyCreatable object at 0x1023a6f60>
en essayant de construire un objet sans utiliser le create
classe-méthode de création échoue en raison de l'affirmation:
>>> 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
Si vous tentez de créer un objet en imitant l' create
classe-méthode
la création échoue à cause de la modification du compilateur de 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'
La seule façon de construire OnlyCreatable
en dehors d'une classe-la méthode consiste à connaître la valeur de OnlyCreatable.__create_key
. Puisque la valeur de cet attribut de classe est générée à d'exécution et le nom est préfixé avec __ marquant comme inaccessible qu'elle est "impossible" pour obtenir cette valeur et/ou de construction de l'objet.
Comme personne ne l'a mentionné encore-vous pouvez avoir un contrôle considérable sur ce noms sont visibles dans quelles étendues -- et il y a beaucoup de lunettes disponibles. Voici deuxtrois d'autres moyens de limiter la construction d'une classe à une méthode de fabrique:
#Define the class within the factory method
def factory():
class Foo:
pass
return Foo()
OR
#Assign the class as an attribute of the factory method
def factory():
return factory.Foo()
class Foo:
pass
factory.Foo = Foo
del Foo
(Note: Ceci permet toujours de faire référence à la classe de l'extérieur (pour isinstance
vérifie, par exemple), mais il est assez évident que vous n'êtes pas censé l'instancier directement.)
OR
#Assign the class to a local variable of an outer function
class Foo:
pass
def factory_maker():
inner_Foo=Foo
def factory():
return inner_Foo()
return factory
factory = factory_maker()
del Foo
del factory_maker
ce qui le rend impossible (au moins, sans utiliser au moins une propriété magique (double underscore)) pour accéder au Foo
class, mais permet quand même à plusieurs fonctions de l'utiliser (en les définissant avant de supprimer le nom Foo global.
tout d'abord, le terme "constructeur" ne s'applique pas à Python, parce que, bien que __init__()
méthode joue un rôle de l'un, c'est juste une méthode qui est appelée lorsqu'un objet a déjà été créé et nécessite l'initialisation.
Chaque méthode d'une classe en Python est public. Généralement les programmeurs marque "privé" méthodes _
ou __
dans le nom d'une méthode, par exemple:
# inheriting from object is relevant for Python 2.x only
class MyClass(object):
# kinda "constructor"
def __init__(self):
pass
# here is a "private" method
def _some_method(self):
pass
# ... and a public one
def another_method(self):
pass
class MongoConn(object):
@classmethod
def instance(cls):
if not hasattr(cls, '_instance'):
cls._instance = cls()
return cls._instance
def __init__(self):
assert not hasattr(self.__class__, '_instance'), 'Do not call constructor directly!'
si vous voulez une seule instance.