2010-07-07 3 views
1

Je ne comprends pas comment poser cette question. Si je le faisais, je serais probablement beaucoup plus proche d'une solution. J'ai besoin d'un aperçu de l'héritage.Un exemple d'héritage en Python

Je veux faire un sous-type personnalisé de float. Mais je veux que l'instance de ce sous-type réévalue sa valeur avant d'exécuter l'une des méthodes de flottement normales (__add__, __mul__, etc.). Dans cet exemple, il devrait multiplier sa valeur par le facteur global:

class FactorFloat(float): 
    # I don't think I want to do this: 
    ## def __new__(self, value): 
    ##  return float.__new__(self, value) 
    def __init__(self, value): 
     float.__init__(self, value) 
    # Something important is missing.. 
    # I want to do something with global FACTOR 
    # when any float method is called. 

f = FactorFloat(3.) 
FACTOR = 10. 
print f # 30.0 
print f-1 # 29.0 
FACTOR = 2. 
print f # 6.0 
print f-1 # 5.0 

C'est juste un exemple aseptisé que je pense obtient mon point de. Je posterai un problème "réel" plus complexe si nécessaire.

Répondre

5
class FactorFloat(float): 
    def _factor_scale(f): 
     def wrapper(self, *args, **kwargs): 
      scaled = float.__mul__(self, FACTOR) 
      result = f(scaled, *args, **kwargs) 
      # if you want to return FactorFloats when possible: 
      if isinstance(result, float): 
       result = type(self)(result/FACTOR) 
      return result 
     return wrapper 

    def __repr__(self): 
     return '%s(%s)' % (type(self).__name__, float.__repr__(self)) 

    __str__ = _factor_scale(float.__str__) 
    __mul__ = _factor_scale(float.__mul__) 
    __div__ = _factor_scale(float.__div__) 
    __add__ = _factor_scale(float.__add__) 
    __sub__ = _factor_scale(float.__sub__) 


f = FactorFloat(3.) 
FACTOR = 10. 
print f # 30.0 
print f-1 # 29.0 
FACTOR = 2. 
print f # 6.0 
print f-1 # 5.0 
print repr(f) 

pour:

30.0 
29.0 
6.0 
5.0 
FactorFloat(3.0) 

EDIT:

En réponse à la question dans le commentaire; rendre les choses légèrement plus générales et automatisées, en utilisant un décorateur de classe. Je ne bouclerais pas sur dir(baseclass), mais plutôt énumérerais explicitement les méthodes que je souhaitais envelopper. Dans l'exemple ci-dessous, je les liste dans la variable de classe _scale_methods.

def wrap_scale_methods(cls): 
    Base = cls.__base__ 
    def factor_scale(f): 
     def wrapper(self, *args, **kwargs): 
      scaled = Base.__mul__(self, FACTOR) 
      result = f(scaled, *args, **kwargs) 
      if isinstance(result, Base): 
       result = type(self)(result/FACTOR) 
      return result 
     return wrapper 
    for methodname in cls._scale_methods: 
     setattr(cls, methodname, factor_scale(getattr(Base, methodname))) 
    return cls 

@wrap_scale_methods 
class FactorComplex(complex): 
    _scale_methods = '__str__ __mul__ __div__ __add__ __sub__'.split() 
    def __repr__(self): 
     return '%s(%s)' % (type(self).__name__, complex.__repr__(self)[1:-1]) 
+0

Merci. Juste curieux, existe-t-il un moyen de faire une boucle sur dir (float) au lieu de définir '__mul__',' __div__', etc. individuellement? Je demande parce que je pourrais essayer ceci sur un tableau numpy au lieu d'un flotteur. – Paul

+0

Voir la modification à ma réponse. –

1

Qu'est-ce que vous êtes désireux de faire est en réalité très difficile. Je ne connais aucun logiciel python qui sous-classe un type tel que float ou int et fait ensuite des mathématiques avec lui. Je pense qu'il y a peut-être une meilleure façon d'accomplir ce que vous essayez d'atteindre sans utiliser une sous-classe de float. Vous devriez étudier des alternatives.

1

Voici quelques méthodes pour obtenir votre testcases passant

def __str__(self): 
    return str(FACTOR*self) 
def __sub__(self, other): 
    return self*FACTOR-other 

Évidemment, vous devez également mettre en œuvre __add__, __mul__, etc ...

Cela dit - ce qui est votre cas d'utilisation? Cela semble être une chose étrange de vouloir faire

+0

Mon cas d'utilisation est une interpolation multi-axes utilisant des valeurs de recherche globales. Je veux définir, par exemple, la densité de l'air comme une simple variable flottante qui dépend de la pression globale et de la température. Cependant, j'aimerais également utiliser de manière interchangeable des flotteurs réels pour des densités qui sont indépendantes de la température et/ou de la pression (par exemple de l'acier). J'espérais éviter d'implémenter __add__, __mul__, etc., mais cela semble inévitable. ..et probablement plus facile que d'afficher cette question .. – Paul