One way to preserve the initial value of an argument to a recursive function is to use an additional keyword argument. It's conventional to give this argument a default value of None so callers of the function don't need to initialize this argument, but when the function calls itself recursively it gets set appropriately, when required.
For example:
def is_substring(sub, string, oldsub=None):
if sub == "":
return True
if string == "":
return False
if oldsub is None:
oldsub = sub
if sub[0] == string[0]:
return is_substring(sub[1:], string[1:], oldsub)
else:
return is_substring(oldsub, string[1:], oldsub)
Another way to preserve the value is to create a closure by defining the recursive function inside a wrapper function, like this:
def is_substring(sub, string):
oldsub = sub
def is_substringR(sub, string):
if sub == "":
return True
if string == "":
return False
if oldsub is None:
oldsub = sub
if sub[0] == string[0]:
return is_substringR(sub[1:], string[1:])
else:
return is_substringR(oldsub, string[1:])
return is_substringR(sub, string)
This function implements the same algorithm as the earlier version. And I'm pretty sure that's the algorithm you're trying to implement with your code. Unfortunately, this algorithm doesn't find substrings correctly.
So here's a recursive is_substring that does work correctly, but it doesn't need to preserve old argument values.
def is_substring(sub, string):
if sub == "":
return True
if string == "":
return False
if string.startswith(sub):
return True
else:
return is_substring(sub, string[1:])
# some tests
data = (
('misip', 'mississippi'),
('tle', 'cattle'),
)
for sub, target in data:
print('{!r} {!r} {}'.format(sub, target, is_substring(sub, target)))
output
'misip' 'mississippi' False
'tle' 'cattle' True
If you don't want to use the .startswith method, you can use slicing instead:
def is_substring(sub, string):
if sub == "":
return True
if string == "":
return False
if sub == string[:len(sub)]:
return True
else:
return is_substring(sub, string[1:])
As I said in the comments, the usual way to do a substring test is to use the in operator, which calls the string's .__contains__ method.
sub in string