Массивы в Numpy реализованы почти так-же как и в С++ . Главное отличие - это всегда непрерывный в оперативной памяти участок однотипных данных. За счет этих двух фундаментальных свойств и соответственно - отсутствия соответствующих проверок и преобразований, операции над элементами массивов Numpy выполняются ощутимо быстрее, чем над списками, особенно при больших объемах хранимой информации. Недостатком массивов в Numpy есть неэффективное использования оперативной памяти в случаях, если реальных элементов массиве меньше, чем задекларированный размер массива.
Списки реализованы в виде несколько модифицированной ссылочной структуры С++. Точнее - память там выделяется блоками, доступ не прямо к элементу, а через систему ссылок и пр. Кроме того, списки это разнотипные элементы, более того - это возможно еще и списки списков или списки других составных типов данных. В общем, что-бы выполнить простую операцию, интерпретатору необходимо выполнить достаточно много проверок и переходов.
В последних версиях реализация списков сильно оптимизирована. Тем не менее, операции с его элементами остаются более медленными, чем над элементами массивов Numpy.
Наличие "множества полезных и удобных функций" - это уже производное от базовых отличий.