开发者

testing existing attribute of a @classmethod function, yields AttributeError

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 Non开发者_运维百科e 
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?


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
2
>>> b.x
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.


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


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.


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?"

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜