web-dev-qa-db-fra.com

Méthodes privées dans Python

Je voudrais avoir une fonction dans ma classe, que je vais utiliser uniquement à l'intérieur des méthodes de cette classe. Je ne l'appellerai pas en dehors des implémentations de ces méthodes. En C++, j'utiliserais une méthode déclarée dans la section privée de la classe. Quelle est la meilleure façon d'implémenter une telle fonction en python? Je pense utiliser un décorateur statique pour ce cas. Puis-je utiliser une fonction sans décorateurs et self Word

15
freude

Python n'a pas le concept de méthodes ou d'attributs privés, tout dépend de la façon dont vous implémentez votre classe. Mais vous pouvez utiliser des variables pseudo-privées (changement de nom), toute variable précédée de __ (deux traits de soulignement) devient une variable pseudo-privée.

De la docs :

Puisqu'il existe un cas d'utilisation valide pour les membres de classe privée (à savoir pour éviter les conflits de noms avec des noms définis par des sous-classes), il existe un support limité pour un tel mécanisme, appelé gestion de noms. Tout identifiant du formulaire __spam (au moins deux traits de soulignement de début, au plus un trait de soulignement de fin) est textuellement remplacé par _classname__spam, où nom_classe est le nom de classe actuel avec le ou les traits de soulignement en tête supprimés. Cette manipulation est effectuée sans tenir compte de la position syntaxique de l'identifiant, tant qu'elle se produit dans la définition d'une classe.

class A:
    def __private(self):
       pass

Alors __private devient désormais _A__private

exemple de méthode statique:

>>> class A:
...     @staticmethod         #not required in py3.x
...     def __private():
...         print 'hello'
...         
>>> A._A__private()
hello
25
Ashwini Chaudhary

Python n'a pas le concept de "privé" comme le font de nombreux autres langages. Il est construit sur le principe de l'adulte consentant qui dit que les utilisateurs de votre code l'utiliseront de manière responsable. Par convention, les attributs commençant par un simple ou double soulignement de tête seront traités comme faisant partie de l'implémentation interne, mais ils ne sont pas réellement cachés aux utilisateurs. Un double soulignement entraînera cependant une altération du nom d'attribut.

De plus, je noterais pour vous que self n'est spécial que par convention, et non par aucune caractéristique du langage. Pour les méthodes d'instance, lorsqu'elles sont appelées en tant que membres d'une instance, elles sont implicitement passées à l'instance comme premier argument, mais dans l'implémentation de la méthode elle-même, cet argument peut techniquement être nommé n'importe quelle chose arbitraire que vous voulez. self est juste la convention pour faciliter la compréhension du code. Par conséquent, le fait de ne pas inclure self dans la signature d'une méthode n'a aucun effet fonctionnel réel autre que de provoquer l'attribution de l'argument d'instance implicite au nom de variable suivant dans la signature. Ceci est bien sûr différent pour les méthodes de classe, qui reçoivent l'instance de l'objet classe lui-même comme premier argument implicite, et les méthodes statiques, qui ne reçoivent aucun argument implicite du tout.

6
Silas Ray

Beaucoup de bonnes choses ici avec de l'obscurcissement en utilisant des soulignements de premier plan. Personnellement, je profite grandement de la décision de conception du langage de rendre tout public car cela réduit le temps nécessaire pour comprendre et utiliser de nouveaux modules.

Cependant, si vous êtes déterminé à implémenter des méthodes/attributs privés et que vous êtes disposé à ne pas être pythonique, vous pouvez faire quelque chose comme:

from pprint import pprint


# CamelCase because it 'acts' like a class
def SneakyCounter():

    class SneakyCounterInternal(object):

        def __init__(self):
            self.counter = 0

        def add_two(self):
            self.increment()
            self.increment()

        def increment(self):
            self.counter += 1

        def reset(self):
            print 'count prior to reset: {}'.format(self.counter)
            self.counter = 0

    sneaky_counter = SneakyCounterInternal()

    class SneakyCounterExternal(object):

        def add_two(self):
            sneaky_counter.add_two()

        def reset(self):
            sneaky_counter.reset()

    return SneakyCounterExternal()


# counter attribute is not accessible from out here
sneaky_counter = SneakyCounter()

sneaky_counter.add_two()
sneaky_counter.add_two()
sneaky_counter.reset()

# `increment` and `counter` not exposed (AFAIK)
pprint(dir(sneaky_counter))

Difficile d'imaginer un cas où vous voudriez faire cela, mais c'est possible.

4
circld

Python ne fait tout simplement pas de privé. Si vous le souhaitez, vous pouvez suivre la convention et faire précéder le nom d'un simple soulignement, mais c'est aux autres codeurs de respecter cela de manière gentleman †

† ou gentiment

2
John La Rooy

vous ne le faites tout simplement pas:

  • La méthode Pythonic consiste à ne pas documenter ces méthodes/membres à l'aide de docstrings, uniquement avec des commentaires de code "réels". Et la convention consiste à leur ajouter un simple ou un double soulignement;

  • Ensuite, vous pouvez utiliser des doubles traits de soulignement devant votre membre, afin qu'ils soient rendus locaux à la classe (c'est principalement un changement de nom, c'est-à-dire que le vrai nom du membre en dehors de la classe devient: instance.__classname_membername). Il est utile d'éviter les conflits lors de l'utilisation de l'héritage ou de créer un "espace privé" entre les enfants d'une classe.

  • AFAICT, il est possible de "cacher" des variables en utilisant des métaclasses, mais cela viole toute la philosophie de python, donc je n'entrerai pas dans les détails à ce sujet

1
zmo