views:

106

answers:

4

i have a function which is a class method, and i want to test a attribute of the class which may or may not be None, but will exist always.

class classA():
 def __init__(self, var1, var2 = None):
  self.attribute1 = var1
  self.attribute2 = var2

 @classmethod
 def func(self,x):
  if self.attribute2 is None:
   do something  

i get the error

AttributeError: class classA has no attribute 'attributeB'

when i access the attribute like i showed but if on command line i can see it works,

x = classA()
x.attribute2 is None 
True

so the test works.

if i remove the @classmethod decorator from func, the problem disapears.
if i leave the @classmethod decorator, it only seems to affect variables which are supplied default values in the super-class's constructor.

whats going on in the above code?

+2  A: 

You should first test to see if you HAVE the attribute with hasattr() or somesuch.

class classA(superClass):
 def func(self,x):
  if not hasattr(self, "attributeB") or self.attributeB is None:
   do somthing  

You may also want to make sure that the sub-class is calling the constructor method from the parent class. That attribute is obviously getting assigned after you're referencing it. So make sure the class is properly constructed with

parentclassName.__init__(self, ... )
Ishpeck
+1: This is the right way to do it. Check if the attribute exists first, then act on that.
jathanism
If the superclass has the attribute (unconditionally), as the broken code example *seems* to suggest, there is no reason to test for it.
Thomas Wouters
-1: While this will work, it doesn't really fix the actual problem. In general, I would try to avoid design patterns that result in class attributes getting set sometimes and not others.
Brendan Abel
A: 

The two attributes are instance attributes, not class attributes. The class method is trying to reference class attributes. Neither your attribute1 nor your attribute2 exist on the class: they exist on the instance.

I don't know how to fix this, but this is the source of the problem.

(Verified by changing attribute2 to attribute1 in func.)

So the question should really be, "How to reference instance attributes within a class method?"

Vicki Laidler
+2  A: 

self in an instance method is the instance. self (or more traditionally, cls) in a class method is the class. Attributes bound on an instance are not visible on the class. The only way to make this work would be to pass the instance to the class method, at which point you may as well just make it an instance method.

Ignacio Vazquez-Abrams
not sure i totally understand this. why does it react different to argurments which are given default values and arguments which arent?
alex
A: 

There is a difference between class attributes and instance attributes. A quick demonstration would be this:

>>> class A(object):
...     x=4
...     def __init__(self):
...         self.y=2
>>> a=A() #a is now an instance of A
>>> A.x #Works as x is an attribute of the class
2: 4
>>> a.x #Works as instances can access class variables
3: 4
>>> a.y #Works as y is an attribute of the instance
4: 2
>>> A.y #Fails as the class A has no attribute y
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    A.y #Fails as the class A has no attribute y
AttributeError: type object 'A' has no attribute 'y'
>>> 

Now, when a method of a class is decorated with classmethod, that signals that it does not take an instance, but takes the class itself as the parameter. Thus, conventionally we name the first argument cls, and not self. In your code, classA has no attributes, and so trying to access attribute2 fails. This difference can be shown with the below code:

>>> class B(object):
...     x=2
...     def __init__(self):
...         self.x=7
...     def pr1(self):
...         print self.x
...     @classmethod
...     def pr2(cls):
...         print cls.x
>>> b=B()
>>> B.x
5: 2
>>> b.x
6: 7
>>> b.pr1()
7
>>> b.pr2()
2
>>> B.pr2()
2

I might not have been clear enough, so if you are still confused just search classmethod or new-style classes and read up a bit on this.

Nikwin
thanks. i got it.
alex