2008-10-23 5 views

Répondre

18

Il n'y a pas vraiment vrai « privé » attributs ou méthodes en Python . Une chose que vous pouvez faire est de remplacer simplement la méthode que vous ne voulez pas dans la sous-classe, et soulever une exception:

>>> class Foo(object): 
...  def foo(self): 
...   print 'FOO!' 
...   
>>> class Bar(Foo): 
...  def foo(self): 
...   raise AttributeError("'Bar' object has no attribute 'foo'") 
...  
>>> b = Bar() 
>>> b.foo() 
Traceback (most recent call last): 
    File "<interactive input>", line 1, in <module> 
    File "<interactive input>", line 3, in foo 
AttributeError: 'Bar' object has no attribute 'foo' 
+0

> Il n'y a pas vraiment de véritables attributs ou méthodes "privés" en Python. C'est pourquoi je n'ai pas demandé comment les rendre privés, mais comment les 'enlever' de l'interface. J'espère que la version éditée est plus précise –

+2

Je suis d'accord que NotImplementedError est probablement le meilleur à utiliser, mais si vous vouliez vraiment ne pas avoir la méthode héritée du tout, relancez AttributeError à la place (ce que vous obtiendriez si le parent méthode n'existait pas). –

+1

Bon point concernant AttributeError. Je vais mettre à jour mon exemple. – kurosch

5
class X(object): 
    def some_function(self): 
     do_some_stuff() 

class Y(object): 
    some_function = None 

Cela peut conduire à une mauvaise et difficile à trouver des exceptions étant jetés, donc vous pouvez essayer ceci:

class X(object): 
    def some_function(self): 
     do_some_stuff() 

class Y(object): 
    def some_function(self): 
     raise NotImplementedError("function some_function not implemented") 
17

méthode de Kurosch de résoudre le problème est pas tout à fait correct, parce que vous pouvez toujours utiliser b.foo sans obtenir un AttributeError. Si vous n'appelez pas la fonction, aucune erreur ne se produit. Voici deux façons que je peux penser à faire:

import doctest 

class Foo(object): 
    """ 
    >>> Foo().foo() 
    foo 
    """ 
    def foo(self): print 'foo' 
    def fu(self): print 'fu' 

class Bar(object): 
    """ 
    >>> b = Bar() 
    >>> b.foo() 
    Traceback (most recent call last): 
    ... 
    AttributeError 
    >>> hasattr(b, 'foo') 
    False 
    >>> hasattr(b, 'fu') 
    True 
    """ 
    def __init__(self): self._wrapped = Foo() 

    def __getattr__(self, attr_name): 
     if attr_name == 'foo': raise AttributeError 
     return getattr(self._wrapped, attr_name) 

class Baz(Foo): 
    """ 
    >>> b = Baz() 
    >>> b.foo() # doctest: +ELLIPSIS 
    Traceback (most recent call last): 
    ... 
    AttributeError... 
    >>> hasattr(b, 'foo') 
    False 
    >>> hasattr(b, 'fu') 
    True 
    """ 
    foo = property() 

if __name__ == '__main__': 
    doctest.testmod() 

Bar utilise le motif « envelopper » pour restreindre l'accès à l'objet enveloppé. Martelli has a good talk traitant de cela. Baz utilise the property built-in pour implémenter le protocole descripteur pour l'attribut à remplacer.

+2

Eh bien, bien sûr, dans ma réponse, c'est toujours "visible", mais vous ne pouvez pas "l'utiliser" en soi car cela déclenchera l'exception. Un point valable, cependant. – kurosch

+2

+1, quelle astuce pour utiliser une propriété "vide" pour "supprimer" la méthode foo! : D – MestreLion

+0

Cela va casser la classe pour l'utilisation des opérateurs définis sur le parent, car il n'y a pas de sous-classe. De plus, '__getattr__' est lent – JBernardo

0

C'est la façon la plus propre que je connaisse de le faire. Remplacez les méthodes et demandez à chacune des méthodes surchargées d'appeler votre méthode disabledmethods(). Comme ceci:

class Deck(list): 
... 
@staticmethod 
    def disabledmethods(): 
     raise Exception('Function Disabled') 
    def pop(self): Deck.disabledmethods() 
    def sort(self): Deck.disabledmethods() 
    def reverse(self): Deck.disabledmethods() 
    def __setitem__(self, loc, val): Deck.disabledmethods() 
9

Une variante de la réponse de Kurosch:

class Foo(object): 
    def foo(self): 
     print 'FOO!' 

class Bar(Foo): 
    @property 
    def foo(self): 
     raise AttributeError("'Bar' object has no attribute 'foo'") 

b = Bar() 
b.foo 

Cela soulève une AttributeError sur la propriété au lieu du moment où la méthode est appelée.

Je l'aurais suggéré dans un commentaire mais malheureusement je n'en ai pas encore la réputation.

+0

Est-ce que cela augmentera AttributeError si vous appelez 'getattr (b," Foo ")'? Malheureusement, je n'ai pas d'interpréteur Python pour le tester. –

+0

si vous voulez dire 'getattr (b, 'foo')' alors oui ce sera –

+0

Oui, c'est ce que je voulais dire. Bien que 'getattr (b, 'Foo')' vous donnera également une erreur d'attribut, donc pas de soucis là-bas! –