Search iteratively in a ternary search tree
Iterables

Generally speaking, if you use range(len(some_iterable))and then access an index of the item, you can just iterate over the item itself:

for i in range(len(word)):  # okay
    print(word[i])

for character in word:  # better
    print(character)


In your case it'd be key[:-1]

Style

Good on you for following PEP8. The code looks beautiful. There are more blank lines than I usually see, but they work.

The ternary operator (x if y else z)

Your use of the ternary operator is quite elegant here, but be aware that this makes your code harder to test.

I often see code that use the ternary operator as a sort of cheat to get out of unit test coverage (coverage.py doesn't notice if only one of the cases in a ternary statement is executed).

The algorithm

It looks fine to me. I'm not certain about the correctness. Can you link that pseudo-code you're working from?

You can make it a bit more obvious if you like. How do I call this method? What kind of object is key? I'm sure this makes complete sense in context with the rest of the class, but you can always add argument annotations and function annotations to make your code that much more readable:

def nice_number(x: float) -&gt; str:
    ...


or

def f(n: 'must be prime'):
    ...


What can you do to improve this?

Write a unit test. It makes it so much easier to play with the implementation, to try out different things, without having to worry about breaking some edge case. Write a complete unit test, and be aware of what the algorithm can an can't do.

Run profiling. I don't think you will learn anything shocking by profiling the code, but it's always good to get a sense of what takes the most amount of time. My guess is that the slowest part of your code, considering how straightforward it is, will be the attribute access (node.key). (Rule of thumb: dots are expensive)

Write a docstring. Run help() on your module and try to imagine what it looks like to users.

Get rid of the wrapper method. Unless there's something I'm not seeing here, there's no reason to have a static method TST._search(), not visible to help() because of that underscore, and a wrapper method TST.search() that merely calls it.

If you do get rid of the static method, start off by setting node = self.root (going back to the earlier comment about dots being expensive, you don't want to have that in the hot part of your loop if avoiding it is so easy).

I almost never use staticmethod() in real-world code. If I do, I make sure to spend a minute thinking about whether it's really necessary.