This is a question where the answer is complicated. What most people call a "shell" is a Read-Eval-Print Loop and therefore, even a python interpreter is a shell, provided you are running python interactively. However, this would mean that nologin is not a real shell! So what is a shell?
Technically speaking, any program can be used as a shell. In fact, here are a few pictures of me using unusual shells:
- Python shell as the login shell
- Nano as a shell (though you can't distinguish between it being run normally, since it's fullscreen)
- Cat running as a shell
- Top running as a shell (even though you, again, can't see it being a shell)
- And a hello world program!
However, this isn't what you'd expect to be running as shells. Usually, you'll want to be running one of the shells in /etc/shells. For example, mine contains:
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
/usr/bin/tmux
/usr/bin/screen
and none of the shells I mentioned previously! So why do they run?
To put it simply, they do, but only locally. If you look at the shells manpage with man shells, you will discover that /etc/shells is mostly used by programs such as FTP daemons. This is why you don't see the nologin shell in /etc/shells: It prevents login to FTP and other non-login daemons by not being there, while preventing login locally by being a simple printf("This account is currently not available"); program, and not a REPL.
So, to answer your question: There is only one type of shell, and that is executable. If you can run a program, it's a shell.