It's always a good idea to share an example people can run, if possible, like this:
places = [
('Becketts', 'Bed and Breakfast', '11 Bellevue Terrace Southsea Portsmouth PO5 3AT'),
('Charles Hope Apartments', 'Apartment', 'Exchange Court Southampton SO14 3SB'),
('Claremont Guest House', 'Bed and Breakfast', '33-35 The Polygon Southampton SO15 2BP', '8'),
('Farmhouse Hotel', 'Hotel', 'Burrfields Rd Portsmouth PO3 5HH'),
('Ferry House Lodge', 'Bed and Breakfast', '472 Mile End Rd Portsmouth PO2 7BX'),
('Freemantle Solent Lodge', 'Bed and Breakfast', 'Park Rd Freemantle Southampton SO15 3BB'),
('Hammersmith Rooms', 'Hostel', '28-30 Bute Gardens London, W6 7DS'),
]
def search_name():
response = input()
responses = [match for match in places if response in match]
print(responses)
search_name()
Note that there are many questions explaining how to find a substring in a list (or tuple for that matter) of strings, like How to check if a string is a substring of items in a list of strings
But you'll find that your function prints nothing when you enter 'Bec', but if you try entering 'Becketts', it does in fact find a result. This is an important clue to what the problem is.
The expression 'Bec' in ('Becketts', 'Bed and Breakfast') is False, since 'Bec' is not in the tuple. But you wanted to check if 'Bec' was part of any string in the tuple. So:
responses = [match for match in places for item in match if response in item]
With this line, the code works better.
But note that the solution doesn't quite work as expected yet: try entering 'mantle'. You'll get the Freemantle data twice. For a more precise solution:
responses = [match for match in places if any(response in item for item in match)]
This works differently, because it only loops len(places) iterations, and for each it checks if the response is in any of the items in each tuple - and then the tuple is added.
The previous response looks a bit simpler, but that loops over places and then each item in each of those places, so it loops for the sum of all tuple lengths iterations - and it can add each tuple as many times as it has elements. Probably not what you want.
By the way, your data has a problematic 8 as one of the tuple values. I've changed that into a string '8' but if you need to deal with the integer there, you'll need to check for it in the function. Otherwise, performing in on it will fail.
A quick fix for the problem with the 8 would be this (but this only works if all of the values can be converted to a str):
responses = [match for match in places if any(response in str(item) for item in match)]
Similar to what @shadowranger indicated in the comments, if you're only interested in matching part of the name (or whatever you consider the first field in the tuple to be), this would be a good solution:
responses = [(name, *_) for (name, *_) in places if response in name]
Here, the second (name, *_) unpacks the tuple into a name and 'the rest' in an unnamed variable, and after checking if response is in name, the first (name, *_) ensures the entire tuple is included in the result.
placesis a list of tuples (it's not clear from the bits of code you shared), that makes sense - the input will be a string and there's no literal'Bec'in any of the tuples, there is however the substring'Bec'in some of the elements of the tuples.inon a tuple, when they really want to perform that operation on all the members of the tuple.