19

所以我有这个问题,我想以这种方式获取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中的类的每个实例创建几千兆字节的数据,因此可以重新以后用。所以我实际上不想继续我目前的解决方案。

有没有按照我的意图获得类名?还是我只是在做梦?

编辑:

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

4

7 回答 7

10

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

class TestClass():
    myName = __qualname__
于 2017-11-03T22:53:07.067 回答
8

只用一个方法?

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

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

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

于 2013-01-24T23:59:41.697 回答
7

在类定义期间实际执行您尝试的唯一方法是使用元类

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
于 2013-01-25T00:10:08.990 回答
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
于 2013-01-25T00:06:22.817 回答
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 是如何通过/来自的?(类之外的全局?)请显示一些代码,显示您打算如何使用您想要工作的内容。可能有一种重新设计的方法可以从这里到达那里,如果不是字面意思的话,实际上是这样。

于 2013-10-06T00:16:14.037 回答
2

除了 F J's 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 中不可用。

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

class namedMeta(type):
    def __prepare__(mcls, name, bases, **kwargs):
        return {'name': name}

class Foo(metaclass=named):
    print name
于 2013-10-06T02:28:30.060 回答
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
于 2014-06-03T12:41:30.150 回答