Python pointers for arithmetic

Question in

Python pointers imitation

asking how to simulate pointers in Python, there was a good suggestion in the solutions, namely:

class ref: def __init__(self, obj): self.obj = obj def get(self): return self.obj def set(self, obj): self.obj = obj 

which can then be used, for example,

 a = ref(1.22) b = ref(a) print a # prints 1.22 print b.get() # prints 1.22 

The class can be changed to avoid using get for the print statement by adding

 def __str__(self): return self.obj.__str__() 

Then

 print b # prints out 1.22 

Now I would like to be able to do arithmetic with b in the same way as, which, I think, would be tantamount to saying that I want a and b to behave exactly like obj . Is there any way to do this? I tried to add methods like

 def __getattribute__(self, attribute): return self.obj.__getattribute__(attribute) def __call__(self): return self.obj.__call__() 

But regardless of this, the conclusion

 print a + b 

is always

 Traceback (most recent call last): File "test.py", line 13, in <module> print a + b TypeError: unsupported operand type(s) for +: 'instance' and 'instance' 

Does anyone have any ideas on how to change the ref class to allow this?

Thanks for any advice!

+4
source share
2 answers

The + operator is implemented using the __add__() method in the left operand or the __radd__() method in the right operand.

Here .

+3
source

There are two potential problems.

First, you rely on your __getattribute__ implementation to have the interpreter find the correct __add__ method. Unfortunately, I noticed that the Python interpreter often has problems finding special functions, such as __add__ or __call__ , if they are created on the fly (that is, they do not form an explicit part of the class when defining the class). The guides clearly confirm this, at least for new-style classes:

For classes of a new style, implied calls for special methods are only guaranteed to work correctly if determined by the type of objects, and not in the dictionary instance of objects.

although it seems to me that I had problems with similar tricks even with old-style classes.

Secondly, simply redirecting __add__ will not be enough. Even if the interpreter successfully reduces

 a + b 

to

 float.__add__( 1.22, b ) 

class float still does not know how to add float to ref . So your __add__ should explicitly dereference the target (and dereference it if it is an indirect reference (and dereference it ...). Thus:

 class ref: def __init__(self, obj): self.obj = obj def get(self): return self.obj def set(self, obj): self.obj = obj def __str__(self): return self.obj.__str__() def __add__( self, other ): while isinstance( other, ref ): other = other.obj return self.obj.__add__( other ) a = ref(1.22) b = ref(a) print a print b print a + b 

The while in __add__ ensures that you completely unpacked all nested references to the base object.

If I did this and I used similar constructions to implement proxy templates, I would reorganize the while loop in its own method, say getBaseObject (), and then it is called every time we need an object, i.e. on The actual basis of the link chain.

0
source

Source: https://habr.com/ru/post/1309793/


All Articles