测试@classmethod函数的现有属性时引发AttributeError

3 投票
4 回答
4020 浏览
提问于 2025-04-15 22:28
x = classA()
x.attribute2 is None 
True

我有一个函数,它是一个类的方法,我想测试这个类的一个属性,这个属性可能是None,也可能不是,但它总是会存在。

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  

我在访问这个属性时遇到了错误,如我所示,但在命令行上我可以看到它是可以工作的,

AttributeError: class classA has no attribute 'attributeB'

所以测试是有效的。

如果我把@classmethod这个装饰器从func中去掉,问题就消失了。
如果我保留@classmethod这个装饰器,它似乎只影响那些在超类构造函数中提供默认值的变量。

上面的代码到底发生了什么?

4 个回答

2

你首先应该用 hasattr() 这样的函数来检查一下你是否拥有这个属性。

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

你可能还需要确认一下子类是否在调用父类的构造方法。这个属性显然是在你引用它之后才被赋值的。所以要确保这个类是正确构造的,使用

parentclassName.__init__(self, ... )
2

在一个实例方法里,self代表的是这个实例本身。而在一个类方法里,self(或者更传统的说法是cls)则代表的是这个类。实例上绑定的属性在类里是看不到的。要让这个方法正常工作,唯一的办法就是把实例传给类方法,但这样的话,你不如直接把它做成一个实例方法。

7

类属性和实例属性是有区别的。简单来说,类属性是属于整个类的,而实例属性是属于类的每一个对象的。下面是一个简单的示例:

>>> 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'
>>> 

当一个类的方法被标记为classmethod时,这表示这个方法不需要实例对象,而是需要类本身作为参数。因此,通常我们把第一个参数命名为cls,而不是self。在你的代码中,classA没有属性,所以尝试访问attribute2会失败。这个区别可以通过下面的代码来展示:

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

我可能没有解释得很清楚,如果你还有疑问,可以搜索一下classmethod或者新式类,了解更多相关内容。

撰写回答