Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get a reference for the current class object?

In Python, how do I get a reference to the current class object within a class statement? Example:

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


Alternatives that I've written off are:

  1. Use locals(): This gives a dict in a class statement that can be written to. This seems to work for classes, however the documentation tells you not to do this. (I might be tempted to go with this alternative if someone can assure me that this will continue to work for some time.)

  2. Add members to the class object after the class statement: My actual application is to derive a PyQt4 QWidget class with dynamically created pyqtProperty class attributes. QWidget is unusual in that it has a custom metaclass. Very roughly, the metaclass compiles a list of pyqtProperties and stores it as additional member. For this reason, properties that are added to the class after creation have no effect. An example to clear this up:

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)

Please note that the above will work for most programming cases; my case just happens to be one of those unusual corner cases.

like image 389
goertzenator Avatar asked Dec 28 '22 14:12

goertzenator


1 Answers

For Python 3, the class must be declared as

class myclass(object, metaclass = Meta):
   prefix = "coffee"
   ...


A few other points:

  • The metaclass may be a callable, not just a class (Python 2&3)

  • If the base class of your class already has a non-standard metaclass, you have to make sure you call it's __init__() and __new__() methods instead of type's.

  • The class statement accepts keyword parameters that are passed on to the metaclass (Python 3 only)

A rewrite of mouad's solution in Python 3 using all of the above is...

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)
like image 113
goertzenator Avatar answered Dec 31 '22 13:12

goertzenator