If A changes the value of C.X, does that change the value of C.X that B sees?
tl;dr:
It depends on how you import X, and on X's mutability.
With import C
If both A and B import the C module with a import C statement, they both can access and modify C.X. The name X is bound to the C module, which both A and B have access to. Example:
C.py
X = 1
B.py
import C
def func():
print(C.X)
A.py
import B
import C
C.X = 2
B.func()
Running A.py prints 2 - A effectively modified the X attribute of the C module's namespace, and this change is reflected in B when calling func().
With from C import X
The from _ import _ statement takes an attribute from an external module and binds it to the current module. When module A imports X from C, it simply binds that value to A's namespace. In other words, changes to X in A's namespace will not reflect on changes to B.X or C.X. Example:
C.py
X = 1
B.py
from C import X
def func():
print(X)
A.py
import B
from C import X
X = 2
B.func()
Running A.py prints 1, because B.func() will print the value stored at B.X, and we've only modified A.X.
What if X is mutable?
If X is mutable (lists, dictionaries, user-defined classes or instances, etc), then it doesn't really matter how you import it - mutating the imported object in any module will propagate across all modules. Example:
C.py
X = {} # mutable object (empty dictionary)
B.py
from C import X
def func():
print(X)
A.py
import B
import C
C.X['key'] = 'value'
B.func()
Running A.py prints {'key': 'value'}. We've effectively modified the same object, even though A used a import _ statement, and B used a from _ import _ statement. This is true for any mutable object, no matter how A or B imports it.