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

42
demandé sur Anders 2011-11-21 16:48:08

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!

24
répondu mac 2015-02-12 18:15:09

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 exemple Tkinter.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é.

8
répondu gimel 2011-11-21 13:19:14

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

7
répondu Adam 2018-04-13 03:50:27

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.

5
répondu Jesse W at Z 2014-09-25 17:06:40

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
3
répondu Zaur Nasibov 2011-11-21 12:57:18
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.

1
répondu BaiJiFeiLong 2017-06-21 09:59:32