【问题标题】:Python get class namePython获取类名
【发布时间】:2013-01-24 23:52:22
【问题描述】:

所以我有这个问题,我想通过这种方式获取python类的名称:

class TestClass():
    myName = (get class name here automatically)
    saveDirectory = os.path.join(saveDir, myName) # so i can save it in unique location
    def __init__(self):
        pass # do something

然而,__class__.__name__ 在创建myName 时似乎还不存在。所以我不得不把它放到__init__() 函数中,像这样:

class TestClass():
    def __init__(self):
        self.myName = self.__class__.__name__
        saveDirectory = os.path.join(saveDir, self.myName) # so i can save it in unique location
        pass # do something

但这有一个很大的问题,因为在实例化类之前我无法获得类的名称,我打算为要保存在saveDirectory中的类的每个实例创建几千兆字节的数据,所以它可以以后可以重复使用。所以我实际上不想继续我目前的解决方案。

有没有我想要的类名?还是我只是在做梦?

编辑:

感谢大家的好建议。我将花一点时间来看看元类。否则,我可能会在全局范围内创建一个字典,并引用这些实例化的类。

【问题讨论】:

  • 如果您在定义类后尝试获取类的名称,那么常量字符串属性是否足够?如果需要,您可以在子类中更改它
  • 如果你总是使用类名,为什么不直接使用字符串呢?类名是静态的,所以没有理由不断要求它。
  • 无法从类定义中获取类型名称,因为在解释它时,还没有创建类。
  • 你可以在元类或装饰器中做到这一点。但这太疯狂了。实现留给读者作为练习。
  • 没有理由在__init__() 中将self.MyName 设置为self.__class__.__name__。只需使用self.__class__.__name__

标签: python


【解决方案1】:

从python 3.3开始,你可以使用__qualname__变量:

class TestClass():
    myName = __qualname__

【讨论】:

    【解决方案2】:

    在类定义期间真正做你想做的事情的唯一方法是使用metaclass

    def saveDirMeta(name, bases, dct):
        dct['saveDirectory'] = os.path.join(saveDir, name)
        return type(name, bases, dct)
    
    class TestClass(object):
        __metaclass__ = saveDirMeta  # this adds the 'saveDirectory' attribute
        def __init__(self):
            pass # do something
    

    或者在 Python 3.x 上:

    class TestClass(metaclass=saveDirMeta):
        def __init__(self):
            pass # do something
    

    这肯定比仅使用以下内容更清楚:

    class TestClass():
        saveDirectory = os.path.join(saveDir, 'TestClass')
        def __init__(self):
            pass # do something
    

    【讨论】:

      【解决方案3】:

      只使用一种方法?

      class TestClass(object):
          @classmethod
          def get_save_directory(cls):
              return os.path.join(save_dir, cls.__name__)
      

      或者你可以只使用一个类属性来指示保存目录;减少魔法通常是一件好事。此外,您可以稍后更改课程名称,而不会破坏您的存储空间。

      还有,什么?千兆字节?!

      【讨论】:

        【解决方案4】:

        我猜你在做什么是不可能的,因为当你这样做的时候这个类甚至不存在:

        myName = (get class name here automatically)

        但是在类被解释后不久,您可以将类对象传递给其他函数 为您完成这项工作。

        In [1]: def save_class(cl):
            myName = cl.__name__
            print myName        #or do whatever you wanna do here
           ...:     
        
        In [2]: class A:pass
        
        In [3]: save_class(A)
        A
        

        【讨论】:

          【解决方案5】:

          在课堂解释期间,还没有“那里”。所以,是的,您最初的示例显示的内容是不可能的。但是请解释一下为什么在该课程在技术上存在之前就需要知道这一点?

          除非对这个悬而未决的问题有一个很好的答案,否则剩下的就是尝试从以下位置获取类的名称:

          1. outside the interpreted class definition, uninstantiated
          
              class demo(object):
                  pass
          
              print demo.__name__ # 'demo'
          
          
          2. from within the class definition, uninstantiated (or instantiated ;-)
          
              class demo2(object):
                  @classmethod
                  def myName(cls):
                      return cls.__name__
          
              print demo2.myName() # 'demo2'
              print demo2().myName() # 'demo2'
          
          
          or
          
          3. within an actual instance of the class
          
              class demo3(object):
                  def myClassName(self):
                      return self.__class__.__name__
          
              print demo3().myClassName() # 'demo3'
          

          除此之外,请编辑问题并添加一些详细信息,解释为什么您的初始尝试需要以您想要的方式工作,在实例化之前并且在类定义内部,而您的第二个示例存在问题。另外, saveDir 是如何通过/来自的? (类外的全局?)请显示一些代码,显示您打算如何使用您想要工作的内容。可能有一种重新设计的方法可以从这里到达那里,如果不是字面意思的话。

          【讨论】:

            【解决方案6】:

            除了 F J 的answer 中的元类,我还能想到两种其他方式。我将从看起来更好看的开始。您不需要使用元类;有时一个描述符就足够了。

            class ClassNameDescriptor(object):
                def __get__(self, instance, owner):
                    return owner.__name__
            
            class BaseClass(object):
                name = ClassNameDescriptor()
            
            class Foo(BaseClass):
                pass
            

            另一种方式,如果你真的需要类体内部中的类名(不太可能),你可以窥探调用堆栈。出现在源代码中的类名位于类定义正在执行的代码对象上:

            import sys
            
            def get_class_name_from_inside_class():
                return sys._getframe().f_back.f_code.co_name
            
            class Foo(object):
                name = get_class_name_from_inside_class()
                print name
            

            到目前为止,只有最后一个允许你在类体内使用名称作为字符串,不幸的是,这不适用于所有版本的 python ,特别是 IronPython 没有实现调用堆栈自省,因为它在 DLR 中不可用。

            有一种方法可以在不自省堆栈的情况下轻松获取它。它类似于 F J 提供的答案,使用元类,但使用 Python 3 中提供的__prepare__ 功能:

            class namedMeta(type):
                def __prepare__(mcls, name, bases, **kwargs):
                    return {'name': name}
            
            class Foo(metaclass=named):
                print name
            

            【讨论】:

              【解决方案7】:

              试试这个。您可以通过_class 参考您当前的课程。 (我使用的是 python 2.7)

              class Meta(type):
                  def __init__(self, *args):
                      super(Meta, self).__init__(*args)
                      self._class = self
                      self.saveDir = str(self._class)
              
              class Wow(object):
                   __metaclass__ = Meta
              
              >>> Wow.saveDir
              >>> Wow().saveDir
              

              【讨论】:

                猜你喜欢
                • 2014-01-22
                • 2021-11-07
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-01-14
                • 2016-09-30
                • 2020-08-19
                相关资源
                最近更新 更多