In TF1, the statement x.assign(1) does not actually assign the value 1 to x, but rather creates a tf.Operation that you have to explicitly run to update the variable.* A call to Operation.run() or Session.run() can be used to run the operation:
assign_op = x.assign(1)
sess.run(assign_op) # or `assign_op.op.run()`
print(x.eval())
# ==> 1
(* In fact, it returns a tf.Tensor, corresponding to the updated value of the variable, to make it easier to chain assignments.)
However, in TF2 x.assign(1) will now assign the value eagerly:
x.assign(1)
print(x.numpy())
# ==> 1