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)
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 functionsare 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
Python Pip on Windows - Command 'Cl.Exe' Failed
How to Know/Change Current Directory in Python Shell
Failed Loading English.Pickle with Nltk.Data.Load
Crontab Not Executing a Python Script
How to Assign the Same Value to Multiple Keys in a Dict Object at Once
Apt Command Line Interface-Like Yes/No Input
Python 'Requests' Library - Define Specific Dns
"Overflowerror: Python Int Too Large to Convert to C Long" on Windows But Not MAC
Python Argparse: Default Value or Specified Value
Best Way to Make Django's Login_Required the Default
Python Ignore Certificate Validation Urllib2
Print to the Same Line and Not a New Line
"Pip Install --Editable ./" VS "Python Setup.Py Develop"
Source Interface with Python and Urllib2