Python获取类名

时间:2013-01-24 23:52:23

标签: python

所以我有这个问题,我希望以这种方式得到一个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中的类的实例创建几千兆字节的数据,所以它可以以后再重复使用。所以我实际上并不想继续使用我目前的解决方案。

有没有得到我想要的课程名称?或者我只是在做梦?

编辑:

谢谢你们提出的好建议。我将花一点时间看一下Metaclasses。否则,我可能会全局创建一个字典,而是引用这些实例化的类。

7 个答案:

答案 0 :(得分:7)

只需使用方法吗?

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

或者你可以只有一个指示保存目录的class属性;少魔法通常是件好事。另外,您可以在不破坏存储空间的情况下更改班级名称。

还有什么?千兆字节?!

答案 1 :(得分:5)

在课程定义中实际执行您尝试的操作的唯一方法是使用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

答案 2 :(得分:2)

我猜你正在做的事情是不可能的,因为当你这样做时,这个课程甚至不存在:

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

答案 3 :(得分:2)

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

如果对这个悬而未决的问题给出一个很好的答案,那就是试图从这个名字中获取该名称:

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如何通过/来自? (班级以外的全球?)请显示一些代码,说明您打算如何使用您想要的工作。可能有一种方法可以重新设计从这里到达那里,实际上如果不是字面上的话。

答案 4 :(得分:2)

除了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

答案 5 :(得分:0)

试试这个。你可以通过_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

答案 6 :(得分:0)

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

class TestClass():
    myName = __qualname__