Q:

python: confusion with local class name

I have the following code:
def f():
    class XYZ:
        # ...
    cls = type('XXX', (XYZ, ), {})
    # ...
    return cls

I am now using it as follows:
C1 = f()
C2 = f()

and it seems to work fine: C1 is C2 returns False, there's no conflict between the class attributes of the two classes, etc.
Question 1
Why is that? How is it possible that C1 and C2 are both shown as class
<'__main__.XXX'>

and yet not the same class?
Question 2
Is there some problem with the fact that I have two identical names for two different classes?
Question 3
I would like to be able to write instead:
f('C1')
f('C2')

with the same effect. Is it possible?
Question 4
If I want C1 to look like a regular class, not main.XXX, is it ok to say:
C1.__name__ = '__main__.C1'

A:

Question 3
To have cls.__name__ be anything you want, (with a nod to delnan's suggestion)
def f(clsname):
    class XYZ:
        # ...
    XYZ.__name__ = XYZ
    # ...
    return XYZ

Question 1
The reason that c1 is not c2 is that they are two different objects stored at two different locations in memory. 
Question 4 
Try an answer to question 1 and see how it works out for you
Question 2
It can complicate debugging that their class attributes __name__ share a common value and this is bad enough to take pains to avoid. (see question 3).  I would maintain though that they don't have the same name. One is named C1 and the other is named C2 (at least in the scope you are showing. If you were to pass them to a function, then there name in that scope would be the same as the name of parameter that they were passed through)
In fact, I'm so sure that they don't have the same name that trying to tell me otherwise is likely to cause me to turn the music up louder and pretend I can't hear you.
In response to comment
It can be done but it's just wrong. I'll illustrate anyway because it's illuminating:
def f(clsname):
    class XYZ(object):
        pass
    XYZ.__name__ = clsname
    globals()[clsname] = XYZ

f('C1')
f('C2')

print C1
print C2

This just works by sticking the class in the globals dict keyed by clsname. But what's the point? You can stick it in the globals dict under any name in fact because this is just another assignment. You are best off just returning the class from the function and letting the caller decide what name to give the class in it's own scope. You still have the __name__ attribute of the class set to the string you pass to the function for debugging purposes.

