How to Avoid Infinite Recursion with Super()

How to avoid infinite recursion with super()?

When instantiating C calls B.__init__, self.__class__ will still be C, so the super() call brings it back to B.

When calling super(), use the class names directly. So in B, call super(B, self), rather than super(self.__class__, self) (and for good measure, use super(C, self) in C). From Python 3, you can just use super() with no arguments to achieve the same thing

Calling an Overridden Super Method Causes Infinite Recursion

A similar question exists over here, which has the correct explanation: Java: Calling a super method which calls an overridden method

I solved my particular problem by changing the meowz variable in dog() to a class variable, and then hiCat() can save to that variable, thus negating the need to call hiCat() from dog() and avoiding the infinite recursion.

Note that I also tested this in C#, and it does work with this setup. It appears that only Java has this problem.

Most efficient way to prevent an infinite recursion in toString()?

The threadlocal bit I mentioned in the question:

public class AntiRecusionList<E> extends ArrayList<E> {

private final ThreadLocal<IdentityHashMap<AntiRecusionList<E>, ?>> fToStringChecker =
new ThreadLocal<IdentityHashMap<AntiRecusionList<E>, ?>>() {
@Override
protected IdentityHashMap<AntiRecusionList<E>, ?> initialValue() {
return new IdentityHashMap<>();
}
};

@Override
public String toString() {
boolean entry = fToStringChecker.get().size() == 0;
try {
if (fToStringChecker.get().containsKey(this)/* test if "this" has been seen before */) {
return "{skipping recursion}";
} else {
fToStringChecker.get().put(this, null);
entry = true;
}
return super.toString();
} finally {
if (entry)
fToStringChecker.get().clear();
}
}
}

recursion with super keyword in java

super() in your case just calls new Object() (all java classes inherit from the Object class), something that would happen anyway. No recursion here

Infinite recursion error

The parent's class' implementation just calls itself, and as the error notes, will continue to do so, endlessly. The parent class should either return some default (e.g., null), or, even better, leave this method abstract if there's no intelligent way it can implement the method.

Why there is infinite recursion loop risk in __getattribute__?

I will try to make it simpler by breaking the self.__dict__[item] into 2 parts:

class Count(object):
def __getattr__(self, item):
print('__getattr__:', item)
d = self.__dict__
print('resolved __dict__')
d[item] = 0
return 0

def __getattribute__(self, item):
print('__getattribute__:', item)
if item.startswith('cur'):
raise AttributeError
return super(Count, self).__getattribute__(item)

obj1 = Count()
print(obj1.current)

The output is

__getattribute__: current
__getattr__: current
__getattribute__: __dict__
resolved __dict__
0

Now, if we replace super(Count, self) with the incorrect construct super(object, self) the message is not printed. It is because __getattribute__ will also mask the access to __dict__. However the super object will point to the base class of object which does not exist and hence our __getattribute__ function will always throw AttributeError.

Now, after __getattribute__ fails, __getattr__ is being tried for it ... well, instead of just resolving __dict__ to some value, it tries to get it as an attribute - and ends up calling__getattribute__ again. Hence we get.

....
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
__getattribute__: __dict__
__getattr__: __dict__
Traceback (most recent call last):
File "getattribute.py", line 15, in <module>
print(obj1.current)
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
File "getattribute.py", line 4, in __getattr__
d = self.__dict__
[Previous line repeated 328 more times]
File "getattribute.py", line 8, in __getattribute__
print('__getattribute__: ', item)
RecursionError: maximum recursion depth exceeded while calling a Python object

Had you used setattr(self, item, 0) instead of looking up self.__dict__ this could have been "avoided":

class Count(object):
def __getattr__(self, item):
setattr(self, item, 0)
return 0

def __getattribute__(self, item):
if item.startswith('cur'):
raise AttributeError
return super(object, self).__getattribute__(item)

obj1 = Count()
print(obj1.current)

of course such code would not have been correct - trying to access any other attribute would have failed nevertheless.

Understand and avoid infinite recursion R

There are three problems.

First, you need an initial case for your recursion.
The following leads to infinite recursion (the value of i continually decreases, but that never stops).

f <- function(i) g(i-1)
g <- function(i) g(i-1) + f(i)
f(5)

The following would stop.

f <- function(i) g(i-1)
g <- function(i) if( i <= 0 ) 0 else g(i-1) + f(i)
f(5)

The second problem is that some of those values will be re-computed an exponential number of times.

f(500) # Too long

In more abstract terms, consider the graph whose vertices are f(i) and g(i), for all values of i,
with edges corresponding to function calls. Recursion allows you to explore this graph as if it were a tree.
But in this case, it is not a tree, and you end up evaluating the same function (exploring the same node) a very large number of times. The following code draw this graph.

library(igraph)
n <- 5
g <- graph.empty()
g <- g + vertices( paste0("f(", 1:n, ")" ) )
g <- g + vertices( paste0("g(", 0:n, ")" ) )
for( i in 1:n) {
g <- g + edge( paste0("f(", i ,")"), paste0( "g(", i-1, ")" ) )
g <- g + edge( paste0("g(", i ,")"), paste0( "f(", i, ")" ) )
g <- g + edge( paste0("g(", i ,")"), paste0( "g(", i-1, ")" ) )
}
plot(g)

Function call graph

One workaround is to store the values you have already computed to avoid recomputing them:
this is called memoization.

library(memoise)
f <- function(i) G(i-1)
g <- function(i) if( i <= 0 ) 1 else G(i-1) + F(i)
F <- memoize(f)
G <- memoize(g)
f(500)

When you memoise the function, the number of recursive calls becomes linear,
but it can still be too large. You can increase the limit as suggested by the initial error message:

options( expressions = 5e5 )

If this is not sufficient, you can prepopulate the table, by using increasingly larger values of i.
With your example:

options( expressions = 5e5 )
loss(1000,10) # Does not work: Error: protect(): protection stack overflow
loss(500,10) # Automatically stores the values of loss(i,100) for i=1:500
loss(1000,10) # Works

Third, there may be function calls that needlessly increase the size of the call stack.
In your example, if you type traceback() after the error, you will see that many intermediate functions
are in the call stack, because weight(i,k) and loss(i,k) are used inside function arguments.
If you move those calls outside the function arguments, the call stack is smaller, and it seems to work.

library(memoise)
gradient <- function(x,y,tau){
if (x-y > 0) { - tau }
else { (1-tau) }
}
aj <- c(-3,-4,-2,-3,-5,-6,-4,-5,-1,rep(-1,15))
f <- function(x,vec){sum(x^vec)-1}
root <- uniroot(f, interval=c(0,200), vec=aj)$root
memloss<-function(i,k){
cat( "loss(", i, ",", k, ")\n", sep="" )
if (i==1) {
c(rep(0,24))
} else if (i <= 0 | k < -5) {
0
} else {
w <- weight(i-1,k) # Changed
gradient(dailyreturn[i-1],w%*%A[i-1,],0.0025)*A[i-1,]
}
}
memweight <- function(i,k){
cat( "weight(", i, ",", k, ")\n", sep="" )
if (i==1) {
c(rep(root,24)^aj)
} else if (i <= 0 | k < -5) {
0
} else {
w <- weight(i-1,k) # Changed
l <- loss(i,k) # Changed
(exp(- (2^(k)/(sqrt(1415))) * l)) / (w %*% exp(- 2^(k)/(sqrt(1415)) * l) ) * w
}
}
loss <- memoize(memloss)
weight <- memoize(memweight)

A <- matrix(1, 1414, 24)
dailyreturn <- rep(1,2080)
options( expressions = 1e5 )
loss(1400,10)

Infinite Recursion with Jackson JSON and Hibernate JPA issue

You may use @JsonIgnore to break the cycle (reference).

You need to import org.codehaus.jackson.annotate.JsonIgnore (legacy versions) or com.fasterxml.jackson.annotation.JsonIgnore (current versions).

Python super class / sub class infinite loop

As you pointed out super().fit_transform(X, y) is equivalent to A.fit_transform(self, X, y) which calls self.fit and self is an instance of B. Hence the infinite recursion.

one way to go would be to hard_code the usage of A.fit in A.fit_transform as such:

class A:

def fit(self, X, y):
print("A fit")
return self

def transform(self, X):
print("A transform")
return "here we are"

def fit_transform(self, X, y):
print("A fit_transsform")
return A.fit(self, X, y).transform(X)

class B(A):


def fit(self, X, y):
print("B fit")
transformed_X = super().fit_transform(X, y)
return transformed_X

which prints:

B fit
A fit_transsform
A fit
A transform
'here we are'

However this code is very ugly and your classes/methods might not be designed properly (maybe compose rather than inherit since B seems to use A rather than being an A)



Related Topics



Leave a reply



Submit