Переменные в локальной области работают быстро, потому что интерпретатору не нужно выполнять поиск по словарю. Во время компиляции он точно знает, сколько будет локальных переменных, и создает инструкции для доступа к ним в виде массива.
Атрибуты-члены требуют поиска в словаре, поэтому они выполняются аналогично первому примеру с использованием глобально изменяемых переменных.
Для скорости вы можете сделать что-то вроде:
attribute1 = self.attribute1
# do stuff with attribute1
который затеняет attribute1 в локальной переменной, поэтому требуется только один поиск по словарю. Я бы не стал беспокоиться, если бы не сделал какое-то профилирование, указывающее на то, что метод был узким местом.