Avec ma compréhension limitée de @property, @setter et @getter, j'ai proposé le code suivant.

class BitCounts:
    sign_bit = 0
    exponent_bits = 0
    mantissa_bits = 0
    _total_bits = 0

    @property
    def total_bits(self):
        return self._total_bits

    @total_bits.setter
    def total_bits(self):
        self._total_bits = self.sign_bit + self.exponent_bits + self.mantissa_bits


class Single(BitCounts):
    sign_bit = 1
    offset = 0x7F
    exponent_bits = 8
    mantissa_bits = 23
    _total_bits = BitCounts.total_bits


class Double(BitCounts):
    sign_bit = 1
    offset = 0x400
    exponent_bits = 11
    mantissa_bits = 52
    _total_bits = BitCounts.total_bits

Mon intention est d'utiliser la sous-classe Single et Double dans d'autres fonctions comme un ensemble d'options comme ceci, par exemple :

    def some_function(option=Single):
        print("exponent bit counts are: %d", option.exponent_bits)
        print("mantissa bit counts are: %d", option.mantissa_bits)
        print("total bit counts are: %d", option.total_bits)

Je souhaite que total_bits soit automatiquement recalculé à l'aide des valeurs de la sous-classe Single ou Double.

J'essaie d'éviter des fonctions supplémentaires pour effectuer le calcul au niveau de la sous-classe.

Avec les codes ci-dessus, en appelant Single.total_bits ou Double.total_bits, je ne reçois qu'un message disant <property object at 0x000002258DF7CB30>, qu'est-ce que j'ai fait de mal et comment puis-je le réparer ?

0
user97662 28 nov. 2021 à 04:15

3 réponses

Meilleure réponse

La façon dont vous utilisez les sous-classes avec des valeurs statiques codées en dur suggère que celles-ci devraient être des instances et non des sous-classes. Ceci est également suggéré par votre tentation d'utiliser self même si vous n'avez créé aucune instance. self fait référence à une instance particulière.

De plus, les setters prennent généralement une valeur comme argument. Vous n'avez pas cela dans votre setter car total_bits dépend complètement d'autres valeurs. En tant que tel, vous devez simplement déplacer votre calcul de setter vers le getter et renvoyer le résultat du calcul.

Considérer:

class BitCounts:
    def __init__(self, sign,offset, exponent, mantissa):       
        self.sign_bit = sign
        self.offset = offset
        self.exponent_bits = exponent
        self.mantissa_bits = mantissa

    @property
    def total_bits(self):
        return self.sign_bit + self.exponent_bits + self.mantissa_bits

# now make two instances:
single = BitCounts(1, 0x7F, 8, 23 )
double = BitCounts(1, 0x400, 11, 52)

print(single.total_bits)
# 32

print(double.total_bits)
# 64
2
Mark 28 nov. 2021 à 04:43
J'aime beaucoup cette solution, cependant, j'ai remarqué qu'en utilisant @property, chaque fois que single.total_bits est appelé, il effectuera un recalcul. Existe-t-il un moyen d'éviter cela, car cela peut coûter cher avec des calculs compliqués avec plusieurs appels à single or double.total_bits.
 – 
user97662
28 nov. 2021 à 04:53
Vous pouvez le mettre en cache, mais vous devrez mettre à jour le cache lorsque l'une des variables dépendantes (comme sign_bit) change. Ce n'est un problème que si ces valeurs peuvent changer. Si ces valeurs ne changent jamais, vous pouvez définir la valeur une fois en tant que variable d'instance régulière dans __init__. avec self.total_bits = self.sign_bit + self.exponent_bits + self.mantissa_bits. Ensuite, vous n'avez pas du tout besoin d'un getter. Attention à la pensée d'optimisation prématurée. L'addition est bon marché.
 – 
Mark
28 nov. 2021 à 04:59

Vous pouvez utiliser:

class Single(BitCounts):
    sign_bit = 1
    offset = 0x7F
    exponent_bits = 8
    mantissa_bits = 23
    _total_bits = BitCounts.total_bits

    def get_total_bits(self):
        # Update values here, example below
        self._total_bits = self._total_bits + 1
        return self._total_bits

Appelez ensuite:

option = Single()
option.get_total_bits()
1
Maike Rodrigo 28 nov. 2021 à 04:44

Le problème ici est que vous essayez d'appeler une méthode d'instance à partir d'une classe.

class A:
  @property
  def foo(self):
    return 1

print(A.foo) # prints an object of function "foo"
print(A().foo) # prints "1"

Pour ce faire, au moins à ma connaissance, vous devez utiliser une métaclasse similaire à ce qu'ils font ici : Décorateur @property par classe en Python

1
bguest 28 nov. 2021 à 04:45