2013-05-31 1 views
0

J'ai une classe de base Base et deux sous-classes Foo et Bar. Dans Base je définis une fonction avec un argument optionnel. Cet argument est donné ou récupéré au moment de l'exécution (pas au moment de la définition). L'argument est toujours récupéré de la même manière, ce qui conduit à des sous-classes ayant une ligne de code standard (bien sûr, c'est une ligne, mais c'est juste un exemple). Normalement, cela ressemblerait à ceci:Valeur par défaut de l'argument de la méthode surchargée (empêchant le passe-partout)

class Base(object): 
    def greet(self, name=None): 
     pass 

class Foo(Base): 
    def greet(self, name=None): 
     name = name or get_name_at_runtime() 
     print('Hello {name} this is Foo.'.format(name=name)) 

class Bar(Base): 
    def greet(self, name=None): 
     name = name or get_name_at_runtime() 
     print('Hello {name} this is Bar.'.format(name=name)) 

Maintenant, je suis venu avec un hack qui permet de résoudre ce problème, mais je ne trouve pas que ce soit une solution solide. La solution implique la définition d'une méthode privée qui enveloppe la méthode substituée et lui fournit la valeur correcte. Les deux méthodes sont commutées dans le __init__ afin d'appeler/redéfinissant la méthode se sent « normal »:

class Base(object): 
    def __init__(self): 
     self.greet, self.__greet = self.__greet, self.greet 

    def greet(self, name): 
     pass 

    def __greet(self, name=None): 
     self.__greet(name or get_name_at_runtime()) 

class Foo(Base): 
    def greet(self, name): 
     print('Hello {name} this is Foo.'.format(name=name)) 

class Bar(Base): 
    def greet(self, name): 
     print('Hello {name} this is Bar.'.format(name=name)) 

La « solution » je suis venu avec pose le problème que ce n'est pas clair que le nom est facultatif, car il semble que ce doesn n'a pas de valeur par défaut.

Dans certains cas, Base est une classe de base abstraite et, dans certains cas, elle ne l'est pas, donc je suis à la recherche d'une solution qui supporte les deux.

+0

Pourquoi pas le métacl asses solution? –

Répondre

0

Que diriez-vous d'utiliser un décorateur? C'est le genre de chose pour laquelle ils sont destinés. Quelque chose comme:

def get_at_runtime(func): 
    def wrapped(*args, **kwargs): 
     if kwargs.get('name', None) is None: 
      kwargs['name'] = get_name_at_runtime() 
     func(*args, **kwargs) 

et envelopper vos méthodes:

@get_at_runtime 
def greet(self, name=None): 
    print('Hello {name} this is Foo.'.format(name=name)) 
+0

De cette façon, vous auriez toujours le décorateur sur 'Bar.great()' et 'Foo.great()'. Maintenant, le décorateur est le passe-partout, cela ne fait que déplacer le problème imo. – siebz0r

0

Salut Vous pouvez utiliser métaclasses

class DefaultNameType(type): 
    def __new__(cls, name, bases, attrs): 
     if 'greet' in attrs: 
      attrs['_greet'] = attrs.pop('greet') 
      def greet(self, name=None): 
       name = name or self.get_name_at_runtime() 
       return self._greet(name) 
      attrs['greet'] = greet 
     print attrs 
     return super(DefaultNameType, cls).__new__(cls, name, bases, attrs) 

class Base(object): 
    __metaclass__ = DefaultNameType 

    def get_name_at_runtime(self): 
     return 'foo' 

    def greet(self, name): 
     pass 

class Foo(Base): 
    def greet(self, name): 
     print('Hello {name} this is Foo.'.format(name=name)) 

class Bar(Base): 
    def greet(self, name): 
     print('Hello {name} this is Bar.'.format(name=name))  

    def get_name_at_runtime(self): 
     return 'foo1' 

Dans ce cas, toute classe dérivée de Base sera modifié de sorte que greet méthode sera être renommé en _greet et la méthode de greet sera créée qui exécutera _greet

Questions connexes