4

In Python, data types (like int, float) both represent a value, but also have some built-in attributes/functions/etc:

In [1]: a = 1.2

In [2]: a
Out[2]: 1.2

In [3]: a.is_integer()
Out[3]: False

Is it possible to reproduce this behavior within Python, e.g. define a class:

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

    # other code ....

s = Scalar(1.2)

where I could have s return 1.2 (instead of typing s.value), and do things like a = s -> a = 1.2? The closest I can get to this behavior is adding something like:

def __getitem__(self, key=None):
    return self.value

and using a = s[()], but that doesn't look very good.

7
  • possible duplicate of Python property callable Commented Aug 7, 2015 at 21:01
  • 1
    In particular, see the snippet with a WeirdInteger class. Commented Aug 7, 2015 at 21:01
  • 2
    This isn't a general solution, but you could make your Scalar class in your example work the way you want by simply subclassing float (or int, or whatever other scalar type you wanted to mimic). class Scalar(float): pass; s = Scalar(1.2) Commented Aug 7, 2015 at 21:05
  • See also: stackoverflow.com/questions/11024646/… Commented Aug 7, 2015 at 21:08
  • subclassing a type might work, I have to see if it works for my (more complicated..) problem, but I'll give it a try! Commented Aug 7, 2015 at 21:14

2 Answers 2

4

where I could have s return 1.2 (instead of typing s.value)

In the console? Then implement the __repr__ method.

a = s -> a = 1.2

To avoid having to use a = s.value, you can implement __call__ and call the object:

>>> class Scalar:
...     def __init__(self, value):
...         self.value = value
...     def __repr__(self):
...         return str(self.value)
...     def __call__(self):
...         return self.value
... 
>>> s = Scalar(1.2)
>>> s
1.2
>>> a = s()
>>> a
1.2

Check the documentation about the data model on emulating numeric types.

For example:

class Scalar:
    def __init__(self, value):
        self.value = value
    def __repr__(self):
        return str(self.value)
    def __call__(self):
        return self.value
    def __add__(self, other):
        return Scalar(self.value + other.value)
    def __lt__(self, other):
        return self.value < other.value
    def ___le__(self, other):
        return self.value <= other.value
    def __eq__(self, other):
        return self.value == other.value
    def __ne__(self, other):
        return self.value != other.value
    def __gt__(self, other):
        return self.value > other.value
    def __ge__(self, other):
        return self.value >= other.value

Can be used like this:

>>> s1 = Scalar(1.2)
>>> s2 = Scalar(2.1)
>>> s1 + s2
3.3
>>> s1 < s2
True
>>> s1 > s2
False
>>> s1 != s2
True
>>> s1 <= s2
True
>>> s1 >= s2
False

There are also the __int__ and __float__ magic methods, which you can implement and use like this (this is more semantically correct):

>>> a = int(s)
>>> a = float(s)
Sign up to request clarification or add additional context in comments.

2 Comments

Well, the __call__ gets rid of one set of brackets, so that's an improvement ;-) If I can't find another solution and the suggestions from above (using class Scalar(float)) don't work, it might be an acceptable solution
__repr__ is going to complain if you try to return anything but a string: TypeError: __repr__ returned non-string (type float). This also won't affect assignment statements (a = s) as described in the question.
1

As far as I know, that's not possible for your a = s example. You would have to change the behavior of =, the assignment operator. The assignment operator doesn't really do anything to the object on the right, it just copies a reference to it (in the case of an object, at least).

In general, it is possible to change the behavior of built in operators for your custom classes using operator overloading, but Python doesn't provide this sort of option for assignment (=) because of how different it is from operators like addition (+) and even equality (==).

4 Comments

Why is this answer getting downvoted when it says essentially the exact same thing as all of the answers here?
@Two-BitAlchemist - It says "that's not possible" when basic subclassing makes it possible.
@TigerhawkT3 Kind of... It doesn't make it possible in the general case, and it doesn't make sense to subclass, say, string if this is the only behavior you want.
This answer is correct. It only answers part of the question but since = can't be overridden OP can't get the complete behaviour they were after.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.