I learned that when I call test(), it calls "deco(test)" internally. If so, it should return a "wrapper" function object instead of outputting strings. But, it outputs strings as the result. I'm wondering how it's doing the job internally.
Not quite, applying a decorator is syntatic sugar (meaning a nice way of doing something that is otherwise possible). The equivalent operation is
def test():
print("Hello, world!")
test = deco(test) # note that test is overwritten by the wrapper that deco returns
To illustrate this, consider the following example
>>> def deco(f):
... print 'applying deco' # this will print when deco is applied to test
... def wrapper():
... print("start")
... f()
... print("end")
... return wrapper
...
>>> @deco
... def test():
... print("Hello world!")
...
applying deco
Notice that the decorator is applied as soon as the function is defined. This matches up with the above "equivalent operation".
In the second case, you are seeing the double print statements as you are manually applying deco to an already decorated test function.