As mentioned in an earlier comment, returning an index into a list is not a good idea. Better, IMO, to return a reference to the object itself (or None if it can't be found).
Allow me to elaborate...
Let's assume that our student class looks like this:
class Student:
def __init__(self, name, id_):
self.name = name
self.id_ = id_
def __repr__(self):
return f'Student: name={self.name} id={self.id_}'
...and that we have a global list of students...
students = [Student('Arthur', 100),
Student('Lancelot', 101)]
Now we need a function to search the list for a student with a specific id:
def find_student(student_list, id_):
for student in student_list:
if id_ == student.id_:
return student
Then this is how we can bring everything together:
for i in [100, 101, 102]:
if (student := find_student(students, i)):
print(student)
else:
print(f'Student {i} not found')
Which will give this output:
Student: name=Arthur id=100
Student: name=Lancelot id=101
Student 102 not found
Notes:
Note the trailing underscore for the student id variable (id_). This is to avoid any possible conflict with the builtin id function.
Added a repr dunder function to the class to facilitate simple printing of a class instance.
Even though the student list is global, it's better to pass a reference to the find_student function. After all, somewhere else in the code you might have another list of students. This makes the function reusable.
And finally, this is the wrong way to maintain a list of students. Assuming their IDs are unique then a dictionary is more appropriate and has the added benefit of making a lookup much easier and faster. If the IDs are not unique then the find_student function could give unpredictable results.