High-level vs. low-level is not a black-and-white thing, but a continuous scale. The terms are used to describe how close a programming language is to the hardware; the higher the level, the more it abstracts the hardware away.
The lowest level, obviously, is binary machine code - it is the exact representation the OS loads and feeds to the CPU. Assembly is the first level of abstraction built on top of it: instead of binary code, one writes mnemoics, human-readable symbolic codes that represent binary machine instructions. This is what people used for systems programming before UNIX.
C is the next step up in the abstraction chain, bundling common patterns into flow control constructs and abstracting machine-specific instructions into platform-agnostic syntax, and this last abstractions was one of the major factors that made UNIX both revolutionary and highly successful, because it meant that the same code could be compiled for any platform without any major changes.
C++ adds another layer of abstractions: it adds classes (abstracting vtables and context passing into an OOP syntax), new
and delete
(bundling memory allocation and variable initialization into a single construct), compile-time type checking, templates (type-safe compile-time metaprogramming), and a bunch of compile-time syntax conveniences like namespaces, function and operator overloading, etc.
Python takes another big step away from the hardware. C++ still gives the programmer full control over memory allocation, and allows for direct manipulation of RAM; Python takes care of memory management for you. Additionally, instead of compiling your code to all-native machine instructions, it runs it against a virtual machine; this carries a performance penalty (which can sometimes be hefty, but usually isn't something to worry about), but it also allows for neat things that would be tricky in C++ and excruciatingly hard in C, such as manipulating functions and classes at run time, getting the names of arbitrary objects at run time, instantiating classes by name at run time, monkey-patching, etc. etc.
So when people divide languages into "high level" and "low level" ones, they draw an arbitrary line somewhere, and that line isn't always the same. In 1970, the line was between assembly and C (abstracting away platform-specific machine instructions being the decisive factor); in 1987, it may have been somewhere between C and C++; today, it may be between C++ and Java (with automatic memory management as the decisive factor).
Long story short: high-level-ness is a sliding scale, and for the three languages you mention it's C < C++ < Python.