2008-10-02 9 views
1

L'une des choses sur python vraiment sympa est la simplicité avec laquelle vous pouvez nommer les variables qui ont le même nom que l'accesseur:Dériver une classe avec des membres privés

self.__value = 1 

def value(): 
    return self.__value 

est-il un moyen simple de fournir un accès aux membres privés d'une classe que je souhaite sous-classer? Souvent, je souhaite simplement travailler avec les objets de données brutes à l'intérieur d'une classe sans avoir à utiliser des accesseurs et des mutateurs tout le temps. Je sais que cela semble aller à l'encontre de l'idée générale du privé et du public, mais généralement, la classe que j'essaie de sous-classer est l'une des miennes et je suis très heureux d'exposer les membres à une sous-classe, mais pas à un instance de cette classe. Existe-t-il un moyen propre de fournir cette distinction?

Répondre

5

Pas commodément, sans casser davantage l'encapsulation. L'attribut de double trait de soulignement est altéré par le nom en ajoutant '_ClassName' à la classe dans laquelle il est accédé. Donc, si vous avez une classe 'ContainerThing' qui a un attribut '__value', l'attribut est actuellement stocké sous la forme '_ContainerThing__value '. Changer le nom de classe (ou refactoring où l'attribut est assigné) signifierait casser toutes les sous-classes qui essayent d'accéder à cet attribut.

C'est exactement pourquoi le double-underscore name-mangling (qui n'est pas vraiment "private", juste "incommode") est une mauvaise idée à utiliser. Utilisez simplement un trait de soulignement simple. Tout le monde saura ne pas toucher à votre attribut 'private' et vous pourrez toujours y accéder dans des sous-classes et dans d'autres situations où il est très utile. Le dénigrement des attributs de double trait de soulignement est utile uniquement pour éviter les conflits de noms pour les attributs qui sont vraiment spécifiques à une classe particulière, ce qui est extrêmement rare. Il n'offre aucune «sécurité» supplémentaire puisque même les attributs mutilés par le nom sont trivialement accessibles. Pour l'enregistrement, '__value' et 'value' (et '_value') ne portent pas le même nom. Les traits de soulignement font partie du nom.

2

Je ne sais pas d'où citer, mais la déclaration suivante en ce qui concerne la protection d'accès est le canon Pythonic: "Nous sommes tous des adultes consentants ici". Comme l'a dit Thomas Wouters, un seul trait de soulignement principal est la manière idiomatique de marquer un attribut comme faisant partie de l'état interne de l'objet. Deux caractères de soulignement fournissent juste un changement de nom pour empêcher un accès facile à l'attribut. Après cela, vous devriez juste vous attendre à ce que le client de votre bibliothèque n'aille pas se tirer dans le pied en se mêlant des attributs «privés».

3

"Je sais que cela va à l'encontre de l'idée générale de privé et public" Pas vraiment "contre", juste différent de C++ et Java.

Privé - comme implémenté en C++ et Java n'est pas un concept très utile. Cela aide, parfois, à isoler les détails d'implémentation. Mais c'est trop utilisé.

Les noms Python commençant par deux __ sont spéciaux et vous ne devriez pas, comme d'habitude, définir des attributs avec des noms comme celui-ci. Les noms avec __ sont spéciaux et font partie de la mise en œuvre. Et exposé pour votre usage. Les noms commençant par _ sont "privé". Parfois, ils sont cachés, un peu. La plupart du temps, la règle des «adultes consentants» s'applique - ne les utilisez pas bêtement, ils sont sujets à changement sans préavis.

Nous mettons "privé" entre guillemets parce que c'est juste un accord entre vous et vos utilisateurs. Vous avez marqué les choses avec _. Vos utilisateurs (et vous-même) devraient honorer cela.

Souvent, nous avons des noms de fonctions de méthodes avec un _ en tête pour indiquer que nous les considérons comme étant «privés» et susceptibles d'être modifiés sans préavis.

Les getters et setters sans fin dont Java a besoin ne sont pas aussi souvent utilisés en Python. L'introspection de Python est plus flexible, vous avez accès au dictionnaire interne des valeurs d'attribut d'un objet, et vous avez la première classe functions comme getattr() et setattr().

De plus, vous avez la fonction property() qui est souvent utilisée pour lier les getters et les setters à un seul nom qui se comporte comme un simple attribut, mais qui est en fait un appel de fonction de méthode bien défini.