spring cc
spring cc

Reputation: 1027

How to use instance methods in python meta programming?

I have a class A:

class A(object):
  a = 'a'
  def __init__(self):
    self.b = 'b'
  def foo(self):
    print A.a
    print self.b

I just wondering how to construct this class by meta programming.

I have tried:

def Init(self):
  self.b = 'b' 

def Foo(self):
  print A_CLASS.a
  print self.b

A_CLASS = type('A_CLASS',(object,),{'a':'a','__init__':Init,'foo':Foo})

myObj = A_CLASS()
myObj.foo()

It's works, but still have some problem, that is, I have to use A_CLASS as the name of the class, if I use B_CLASS, it doesn't work anymore:

B_CLASS = type('A_CLASS',(object,),{'a':'a','__init__':Init,'foo':Foo})

myObj = B_CLASS()
myObj.foo() #Error ocurred

If there is a way to construct such a class, where the name of the variable 'X_CLASS' is not relevant at all?

Upvotes: 3

Views: 89

Answers (2)

ShadowRanger
ShadowRanger

Reputation: 155323

Your error occurs because Foo unconditionally references A_CLASS, but you bound the class to a global name B_CLASS. This is going to be a problem in other circumstances (pickle relies on the class name matching the name it was bound to in the defining module), but for this limited case it's fixable. Instead of referring to A_CLASS.a directly, refer to it in terms of self:

def Foo(self):
  print self.a
  print self.b

self will look for class attributes if no instance attribute of that name exists. If you want to be 100% sure it came from the class, not the instance, you can instead define it as:

def Foo(self):
  # New-style class only, but safe against weirdness like redefining __class__
  print type(self).a
  # Old-style class, and vast majority of non-pathological new-style classes
  print self.__class__.a

  print self.b

which looks up the class, then gets the attribute from the class, bypassing instance attributes.

In an inheritance hierarchy, this might be wrong. If there is a A_CHILD class with a different a class attribute, calling Foo on it will get the child's attribute. But that's the price of violating the rules; if you give a class the name A_CLASS and bind it to the name B_CLASS, you can't refer to it by the name A_CLASS for lookup (because there is no part of your program that has that binding).

Upvotes: 2

Silvio Mayolo
Silvio Mayolo

Reputation: 70257

The problem is that you use the name A_CLASS literally in Foo. You can always get the runtime class of the current object with self.__class__.

def Foo(self):
  print self.__class__.a
  print self.b

Upvotes: 2

Related Questions