如何获取当前类对象的引用?

问题描述:

在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 


替代品有:

  1. 使用locals():这给出了可以写入到一个类声明的字典。这似乎适用于类,但文档告诉你不要这样做。 (如果有人能向我保证这会继续工作一段时间,我可能会试着采用这种方法)。

  2. 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) 

请注意,以上将用于大多数编程情况下工作;我的情况恰好是这些不寻常的角落案件之一。

+0

mouad的答案绝对是一个必须解决的问题,但要描述发生了什么:类定义只是在它自己的本地范围内执行一系列语句。一旦完成后,类名,基类的列表,并且将所得的dict当地人被传递到[类型构造](http://docs.python.org/library/functions.html#type)为'类型( class_name,bases_tuple,locals_dict),然后返回'cls'。因此,'cls'在你想要的位置不可用,只有在之后。此外,使用元类将导致它被调用来代替'type',并且具有相同的签名。 –

+0

我不知道这事'当地人()'把戏班工作。有趣的一点琐事。 :-) – kindall

AFAIK有两路做你想要什么:

  1. 使用metaclass,这将创造一流的创建时间的两个变量(我认为这是你想要的):

    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) 
    
  2. 在实例化时创建你的两个类变量:

    MyClass类(对象): PREFIX = “咖啡”

    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) 
    

N.B:我不知道你想达到的,因为如果你要取决于prefix变量为什么你喜欢访问你在mytest方法做,以创建动态的变量是什么?!我希望这只是一个例子。

+0

我不知道为什么代码的格式不为我工作?! – mouad

+0

是的,例子很傻。这个解决方案看起来很有希我没有提到我使用的Python 3似乎有不同的元类支持。计算出现在的差异...... – goertzenator

请参阅zope.interface.declarations._implements了解这种魔法的例子。只是要警告,这是一个严重的可维护性和可移植性风险。

对于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) 
+0

+1,用于将我最初的答案移植到python 3中,并教给我元类可以是任何可调用的(我不知道),顺便说一句,我们应该称之为“元类函数或元函数;-),除此之外,如果我可能还有一些说法(问题):1.如果您正在为python 3编写代码,则不需要从'object'明确地继承'class myclass(metaclass =为什么你要调用'object .__ class__'而不是'type(...)'这当然是一样的,但我更喜欢最新的只是想知道:) – mouad

+0

@mouad:你是对的,我可以把'object'当作基础类。 2.在我的实际应用中,基类('PyQt4.QtGui.QWidget')的元类有* not *'type',当我使用'type'时给我一个错误。通过使用'object .__ class__',我正在说明如何检索实际的基类元类。 – goertzenator

您可能使用的另外两种方法:

类装饰器。

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 

特别是如果你需要在不同的组合中添加属性,因为它没有继承任何作用的装饰方法是很好的。

如果你正在处理一个小套的,你想以各种方式相结合的属性,你可以使用混入类。 mixin类是一个普通类,它只是为了将各种属性“混合”到其他类中。

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 
+0

+1,对于装饰者的方法,为什么我没有考虑它:) – mouad