user97662
user97662

Reputation: 970

Python Class update parent variables by subclass

With my limited understanding of @property,@setter, and @getter, I came up with following code.

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

My intention is to use the subclass Single and Double in other functions as a set of options like so, for example:

    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)

I would like total_bits to be automatically recalculated using values from subclass Single or Double.

I am trying to avoid extra functions to perform the calculation at subclass level.

With above codes, by calling Single.total_bits, or Double.total_bits, I am only getting a message saying <property object at 0x000002258DF7CB30>, what did I do wrong, and how can I fix it?

Upvotes: 1

Views: 1043

Answers (3)

bguest
bguest

Reputation: 235

The problem here is that you are trying to call an instance method from a class.

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

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

To accomplish this, at least from my knowledge you need to use a metaclass similar to what they do here: Per-class @property decorator in Python

Upvotes: 1

Maike Rodrigo
Maike Rodrigo

Reputation: 36

You can use:

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

Then call:

option = Single()
option.get_total_bits()

Upvotes: 1

Mark
Mark

Reputation: 92460

The way you are using subclasses with hard-coded static values suggests these should be instances not subclasses. This is also suggested by your temptation to use self even though you haven't made any instances. self refers to a particular instance.

Also, setters typically take a value as an argument. You don't have that in your setter because total_bits is completely dependent on other values. As such you should just move your setter calculation to the getter and return the result of the calculation.

Consider:

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

Upvotes: 2

Related Questions