代码之家  ›  专栏  ›  技术社区  ›  max

python:与本地类名混淆

  •  1
  • max  · 技术社区  · 14 年前

    我有以下代码:

    def f():
        class XYZ:
            # ...
        cls = type('XXX', (XYZ, ), {})
        # ...
        return cls
    

    我现在使用它如下:

    C1 = f()
    C2 = f()
    

    它看起来工作得很好:c1是c2返回false,两个类的类属性之间没有冲突,等等。

    问题1

    为什么会这样?c1和c2怎么可能都显示为类?

    <'__main__.XXX'>
    

    但不是同一个班?

    问题2

    对于两个不同的类,我有两个相同的名称这一事实有什么问题吗?

    问题3

    我希望能够写:

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

    同样的效果。有可能吗?

    问题4

    如果我想让C1看起来像一个普通班,不是 主要的 .xxx,可以说:

    C1.__name__ = '__main__.C1'
    
    2 回复  |  直到 14 年前
        1
  •  2
  •   aaronasterling    14 年前

    问题3

    拥有 cls.__name__ 做你想做的任何事,(对德尔南的建议点头)

    def f(clsname):
        class XYZ:
            # ...
        XYZ.__name__ = XYZ
        # ...
        return XYZ
    

    问题1

    原因在于 c1 is not c2 它们是存储在内存中两个不同位置的两个不同对象。

    问题4

    试着回答问题1,看看它对你的效果如何。

    问题2

    它们的类属性会使调试复杂化 __name__ 分享一个共同的价值观,这已经够糟糕的了,要努力避免。(见问题3)。尽管他们的名字不一样,我还是坚持说。命名为 C1 另一个名字是 C2 (至少在显示的范围内。如果要将它们传递给函数,那么该作用域中的名称将与传递它们的参数的名称相同)

    事实上,我很确定他们没有相同的名字,否则试图告诉我很可能导致我把音乐调大,假装我听不见你。

    回应评论

    这是可以做到的,但这是错误的。不管怎样,我会举例说明,因为它很有启发性:

    def f(clsname):
        class XYZ(object):
            pass
        XYZ.__name__ = clsname
        globals()[clsname] = XYZ
    
    f('C1')
    f('C2')
    
    print C1
    print C2
    

    这只需要把全班学生的听写键固定在 clsname . 但有什么意义呢?你可以把它写在环球英语词典里 任何 因为这只是另一个任务。最好是从函数返回类,并让调用者决定在它自己的范围内给类指定什么名称。你仍然拥有 第二代 为调试目的传递给函数的字符串设置的类的属性。

        2
  •  2
  •   user395760    14 年前

    实际上,你不需要 cls = ... 行。

    >>> def f():
    ...     class C:
    ...         pass
    ...     return C
    ... 
    >>> f() is f()
    False
    

    原因: class (以及 def )每次遇到新类时定义一个新类=每次调用函数时。

    至于 cls.__name__ 这真的没有语义上的区别。这个名称对于调试很有用(您不直接向用户公开它,是吗?)反省,但这不应该是个问题。但是如果你真的想要不同的名字,你可以改变 C.S.NAMEYSY 返回前(还要注意 C.__name__ = 'foo' , C.__name__ == '__main__.foo' !).

    问题3:可以直接将其注入全局命名空间… 不要 这样做。它没有优势,只有缺点:不明显的副作用,糟糕的风格,事实上它是一个黑客,等等!