'the value' of an object

Hi all,
The built-in classes of python ‘generate’ objects ‘with a value’. Eg the integer class has (somehow) generated an object with value 5. Observation: this ‘value’ is accessible without using the dot-notation. I wonder if we can replicate this behaviour for other, self written, classes.
I’m working on a simulation where sometimes variables need to be fixed (hence built-ins like int’s) and sometimes some variables should be stochastic (hence ‘returning’ a different value each time it is accessed). I don’t want to change the code of the simulation.

Note: I asked the same question on stackoverflow.

Any ideas? Suggestions?

Kind regards,
N.

There is no “value” 5 you can access (with dot-notation or otherwise).
The behavior of objects depends on the operations they support. Attribute access (dot notation) is the most easy/common to control in custom classes, but other behavior can be specified as well.

To print out the int as 5, the string representation of the object is computed using special method __str__, which you can redefine on your class.
To add the 5 to another number, Python calls the special method __add__, which you can again define for your class to handle addition.

Define enough of these and your objects will act like numbers.

1 Like

The built-in classes of python ‘generate’ objects ‘with a value’. Eg
the integer class has (somehow) generated an object with value 5.
Observation: this ‘value’ is accessible without using the dot-notation.

Objects have state. For an int, that state is the integer value.

But can you access it? What does that mean?

You can do artihmetic with an int. But you can define other classes with
'dotted" internal state and do arithmetic with them, too. The same for
printing and so forth.

Suppose I define a complex number type:

class Complex:
    def __init__(self, real, imag):
        self.real = real
        self.imag = image
    def __str__(self):
        return f"{self.real}+{self.imag}j"
    def __add__(self, other):
        return Complex(self.real+other.real, self.imag+other.imag)

c = Complex(1, 3)
d = Complex(4, 5)
e = c + d

I can print(c), or add c+d directly. How is this different from an int?
To be sure, you can access the real and imaginary components
individually via the .real and .imag attributes, but in other respects
this looks like any other value.

Can you elaborate on how this isn’t like an int (in the sense you’re
getting at in this message)?

I wonder if we can replicate this behaviour for other, self written,
classes.
I’m working on a simulation where sometimes variables need to be fixed (hence built-ins like int’s) and sometimes some variables should be stochastic (hence ‘returning’ a different value each time it is accessed). I don’t want to change the code of the simulation.

This normally amounts to providing the same methods on both types of
things.

Can you give an example of your attempt at each of these and a tiny
piece of simulation code you wish to work identically for both?

Cheers,
Cameron Simpson cs@cskk.id.au

I don’t really understand what you mean by fixed values versus
stochastic. Do you mean something like this?

value = something()  # a stochastic value?
print(value)  # prints (say) 15
print(value)  # prints (say) 27 this time
print(value)  # prints (say) 13 now

If that is the effect you are trying to get, no, that is not directly
possible in Python. Normally we would make value a function:

import random
def value():
    return random.randint(1, 100)

print(value())
print(value())
print(value())

But you can get close to the effect you want by hiding the function
inside a class using property.

import random
class Stochastic(object):
    @property
    def value(self):
        return random.randint(1, 100)

o = Stochastic()
print(o.value)
print(o.value)
print(o.value)

If that is not what you are after, I’m afraid you will need to explain
in more detail.

On further thought, you might be able to get something workable using
delegation.

(Alas, automatic delegation was easy in Python 1 and 2 but hard in
Python 3, so I’m going to give an incomplete solution.)

import random
class StochasticInt(object):
    def mutate(self):
        self.state = random.randint(1, 100)
    # Operators.
    def __add__(self, other):
        self.mutate()
        # Delegate to self.state
        return self.state + other
    def __sub__(self, other):
        self.mutate()
        return self.state - other
    def __rsub__(self, other):
        self.mutate()
        return other - self.state
    def __eq__(self, other):
        self.mutate()
        return self.state == other
    def __str__(self):
        self.mutate()
        return str(self.state)

Read the documentation for the full set of int methods you will need to
provide. There are a lot.

Something like this? This only redoes the str method. You’d probably need to redo all the other methods (like comparison, equal, etc… ) to be able to do what you want.

import random

class stochastic():
    stochastic = False

    def __init__(self, value):
        self.value = value

    def __str__(self):
        if self.stochastic:
            return str(random.randint(6, 15))
        else:
            return str(self.value)


x = stochastic(5)
print(x)
print(x)
print(x)
x.stochastic=True
print(x)
print(x)
print(x)

Output:

5
5
5
7
13
12

Hi Petr,

Thanks for your swift reply. Technically, with value I mean what is stored in an attribute, not the ‘symbol’ that is displayed. Yes, I could write a class replicating all methods of a builtin, but that does not seem very pythonic to me, nor DRY. I was thinking of sub-classing the int-class and then overriding the ‘value’ attribute with a @property and something stochastic. I’ve seen some examples but in the end all return a ‘normal’ int, which return the same value always.
So, I’m still hoping for something better :wink:

Hi all,

Your questions reveal some inaccuracies in my question:

  • value: this would be an attribute of a class. This ‘value’ contains a reference to an(other) object
  • access to the value: would be access to the attribute and thus to an(other) object

The 2 examples of @steven.daprano comes very close to what I want, but I don’t want repeat all methods of a builtin. As it is not pythonic, not DRY and not future proof.

I was thinking something like:

class StochasticVar(int):
   # assuming: VALUE is the attribute containing the value (object).

   @property
   def VALUE(self):
      return random.randint(...)

This way all existing methods would use the stochastic attribute without being rewritten.

Hi all pt.2,

Come to think of it, this is not a very good idea as there is an issue that I overlooked. And that is the simple fact that existing code assumes that the ‘value’ of an attribute is constant and with the proposed solution just isn’t. This will lead to inexplicable results and surely ‘undebuggable’ as well. This probably could be solved by using some sort of ‘protocol’ eg: after an assignment the receiving variable will contain a fixed value (thus a built-in), but for that the assignment operator has to be overloaded and the existing code still would have to be changed.

Sorry for the inconvenience, but you still helped me as I can stop looking now.

Kind regards,
N.

In CPython, the value of an int object is stored privately in the ob_size and ob_digit fields of the object record in C, beneath anything that’s accessible in Python, short of cringe-worthy use of the ctypes module. The methods of an int object, as implemented in C, access these low-level fields directly. There is no hook for a computed value property that a derived type can implement, since the value is intended to be a numeric constant.

If you want to implement your own integral number type with random behavior at the value level, you’ll have to do all of your own work by deriving a type from numbers.Integral and implementing all of the abstract methods in numbers.Integral.__abstractmethods__.

Hi Eryk,

Thank you for your clear answer. That closes the door firmly.

N.