Say I make a class `Hello` with a method that calls `Hello`. If I assign the class to `Hello2` and `del Hello`, then that method will raise an exception indicating that it couldn't find the name `Hello`.

On the other hand, say I run a function that makes a class `dummyName` with a method that calls `dummyName` and assign the returned class to `Bye`. If I assign the class to `Bye2` and `del Bye`, then that method still runs. It appears as if the variable `dummyName` still exists. If it does, where is its namespace, and how is it decided what type of object keeps a cryptic reference after a function returns?

EDIT: A commenter suggested that the class is referenced by a closure. Indeed, a FUNCTION has a `__closure__` attribute, and if the function was nested in another function, the `__closure__` attribute references a tuple of `cell` objects, each of which has a `cell_contents` attribute referencing an object created in the outer function. However, the class `Bye2` does not have a `__closure__` attribute, so the question still stands.

```
def make_Bye():
    class dummyName:
        word = 'bye'
        def talk(self):
            return dummyName.word
    return dummyName

Bye = make_Bye()

class Hello:
    word = 'hello'
    def talk(self):
        return Hello.word

print('1.', Bye.talk(None)) # 1. bye
print('2.', Hello.talk(None)) # 2. hello

# now let's give these classes new names and delete the old names
Hello2 = Hello
del Hello
Bye2 = Bye
del Bye

print('3.', Bye2.talk(None)) # 3. bye
print('4.', Hello2.talk(None)) # NameError: name 'Hello' is not defined

```