Vou renomear variáveis para reduzir a confusão. n -> nf ou nmain . x -> xf ou xmain :
def f(nf, xf):
nf = 2
xf.append(4)
print 'In f():', nf, xf
def main():
nmain = 1
xmain = [0,1,2,3]
print 'Before:', nmain, xmain
f(nmain, xmain)
print 'After: ', nmain, xmain
main()
Quando você chama a função f , o tempo de execução do Python faz uma cópia do xmain e a atribui ao xf , e da mesma forma atribui uma cópia do nmain para nf .
No caso de n , o valor que é copiado é 1.
No caso de x, o valor copiado não é a lista literal [0, 1, 2, 3] . É uma referência a essa lista. xf e xmain estão apontando para a mesma lista; portanto, quando você modifica o xf, também está modificando o xmain .
Se, no entanto, você escrever algo como:
xf = ["foo", "bar"]
xf.append(4)
você descobriria que xmain não mudou. Isso ocorre porque, na linha xf = ["foo", "bar"], você alterou xf para apontar para uma nova lista. Quaisquer alterações feitas nessa nova lista não terão efeitos na lista para a qual o xmain ainda aponta.
Espero que ajude. :-)