如何获取当前类对象的引用?
在Python中,如何在类声明中获取当前类对象的引用?举个例子:
def setup_class_members(cls, prefix): setattr(cls, prefix+"_var1", "hello") setattr(cls, prefix+"_var2", "goodbye") class myclass(object): setup_class_members(cls, "coffee") # How to get "cls"? def mytest(self): print(self.coffee_var1) print(self.coffee_var2) x = myclass() x.mytest() >>> hello >>> goodbye
我考虑过的一些替代方案有:
使用
locals()
:这个方法会在类声明中返回一个可以写入的字典。虽然这在类中似乎有效,但文档上建议不要这样做。(如果有人能保证这个方法在一段时间内仍然有效,我可能会考虑使用这个方案。)在
class
声明后添加成员到类对象:我实际的应用是从PyQt4的QWidget
类派生出一个类,并动态创建pyqtProperty
类属性。QWidget
有点特别,因为它有一个自定义的元类。简单来说,这个元类会编译一个pyqtProperties
的列表,并将其作为额外的成员存储。因此,在类创建后添加的属性不会起作用。下面是一个例子来说明这一点:
from PyQt4 import QtCore, QtGui # works class MyWidget1(QtGui.QWidget): myproperty = QtCore.pyqtProperty(int) # doesn't work because QWidget's metaclass doesn't get to "compile" myproperty class MyWidget2(QtGui.QWidget): pass MyWidget2.myproperty = QtCore.pyqtProperty(int)
请注意,上述方法在大多数编程情况下是有效的;我的情况恰好是一个不寻常的特例。
4 个回答
你还可以使用另外两种方法:
一种是类装饰器。
def setup_class_members(prefix):
def decorator(cls):
setattr(cls, prefix+"_var1", "hello")
setattr(cls, prefix+"_var2", "goodbye")
return cls
return decorator
@setup_class_members("coffee")
class myclass(object):
# ... etc
如果你需要以不同的组合添加属性,使用装饰器的方法很不错,因为它不会影响继承关系。
如果你只需要处理一小部分属性,并希望以不同的方式组合它们,可以使用混合类。混合类其实就是一个普通的类,它的目的是将各种属性“混合”到其他类中。
class coffee_mixin(object):
coffee_var1 = "hello"
coffee_var2 = "goodbye"
class tea_mixin(object):
tea_var1 = "good morning old bean"
tea_var2 = "pip pip cheerio"
class myclass(coffee_mixin, tea_mixin):
# ... etc
对于Python 3,类的声明方式应该是:
class myclass(object, metaclass = Meta):
prefix = "coffee"
...
还有几点需要注意:
元类可以是一个可调用的对象,而不仅仅是一个类(适用于Python 2和3)
如果你的类的基类已经有一个非标准的元类,你需要确保调用它的
__init__()
和__new__()
方法,而不是直接调用类型的。类声明可以接受一些关键字参数,这些参数会传递给元类(仅适用于Python 3)
下面是用Python 3重写mouad的解决方案,使用了以上所有内容:
def MetaFun(name, bases, attr, prefix=None):
if prefix:
attr[prefix+"_var1"] = "hello"
attr[prefix+"_var2"] = "goodbye"
return object.__class__(name, bases, attr)
class myclass(object, metaclass = MetaFun, prefix="coffee"):
def mytest(self):
print(self.coffee_var1)
print(self.coffee_var2)
据我所知,有两种方法可以实现你想要的:
使用元类,这样在创建类的时候就会生成你想要的两个变量(我觉得这正是你想要的):
class Meta(type): def __new__(mcs, name, bases, attr): prefix = attr.get("prefix") if prefix: attr[prefix+"_var1"] = "hello" attr[prefix+"_var2"] = "goodbye" return type.__new__(mcs, name, bases, attr) class myclass(object): __metaclass__ = Meta prefix = "coffee" def mytest(self): print(self.coffee_var1) print(self.coffee_var2)
在实例化的时候创建你的两个类变量:
class myclass(object):
prefix = "coffee"def __init__(self): setattr(self.__class__, self.prefix+"_var1", "hello") setattr(self.__class__, self.prefix+"_var2", "goodbye") def mytest(self): print(self.coffee_var1) print(self.coffee_var2)
注意:我不太确定你想要实现什么,因为如果你想根据prefix
变量来创建动态变量,那你为什么要像在mytest
方法中那样访问呢?希望这只是一个例子。