When you display the content of myvar in my_func with the exact code you gave as reference, it will check the global variable table to see if it was previously defined in the execution, which is why it works. Then, when you try to assign a value to it in the function by uncommenting myvar = "value", it tries to define myvar as a local variable of my_func, which shadows the reference to the global instance of myvar.
I'm not exactly sure how using the global keyword would cause any issue, but it should be working as intended. Here is an example of how you can use it:
def my_func(mval):
    global myvar
    print ("parameter:", mval)
    print ("myvar:", myvar)
    myvar = "value"
print ("IN MAIN")
myvar = "123"
my_func(999)
print("myvar after my_func:", myvar)
Output:
IN MAIN
parameter: 999
myvar: 123
myvar after my_func: value
If you really don't want to use the global keyword, you can achieve the desired behavior by passing myvar as a parameter of my_func and return the modified value to reassign it in the main scope:
def my_func(mval, myvar):
    print ("parameter:", mval)
    print ("myvar:", myvar)
    myvar = "value"
    return myvar
print ("IN MAIN")
myvar = "123"
myvar = my_func(999, myvar)
print ("myvar after my_func:", myvar)
Output:
IN MAIN
parameter: 999
myvar: 123
myvar after my_func: value
If my_func was already built to return a value, remember that you can return multiple values in Python. Therefore, assuming my_func would return a variable called returnvar, the above code could be written as:
def my_func(mval, myvar):
    returnvar = mval + 1
    print ("parameter:", mval)
    print ("myvar:", myvar)
    myvar = "value"
    return myvar, returnvar
print ("IN MAIN")
myvar = "123"
myvar, returnvar = my_func(999, myvar)
print ("myvar after my_func:", myvar)
print ("returnvar:", returnvar)
Output:
IN MAIN
parameter: 999
myvar: 123
myvar after my_func: value
returnvar: 1000