在__init__中更改类属性

时间:2015-09-11 15:57:49

标签: python python-2.7 python-internals

我正在查看Stack Overflow问题Counting instances of a class?,我不确定为什么该解决方案有效,而且使用简单添加的问题并不存在。我想这更像是一个关于如何存储和访问类与实例变量的问题。

以下是我认为应该有效的代码,而是为每个4生成id

class foo():
      num = 3    # trying 3 instead of 0 or 1 to make sure the add is working

      def __init__(self):
        self.num += 1
        self.id = self.num

f = foo()
g = foo()

print f.id    # 4
print g.id    # 4

self.num +=1语句有些工作(添加正在进行,但不是分配)。

在此处发生此任务失败的情况下发生了什么,而itertools.count任务在另一个问题的解决方案中成功了?

3 个答案:

答案 0 :(得分:5)

整数不会实现__iadd__(就地添加,+=),因为它们是不可变的。解释器回退到标准作业而不是__add__,所以行:

self.num += 1

变为:

self.num = self.num + 1

在右侧,您可以通过foo.num获得3(即self.num),但正如您所料,这里有趣的是分配给实例属性num 阴影类属性。所以该行实际上相当于:

self.num = foo.num + 1  # instance attribute equals class attribute plus one

所有实例最终都是self.num == 4仍为foo.num == 3。相反,我怀疑你想要的是:

foo.num += 1  # explicitly update the class attribute

或者,您可以将其实现为@classmethod,更明确地处理该类:

class Foo():  # note naming convention

    num = 3

    def __init__(self):
        self.increment()
        self.id = self.num  # now you're still accessing the class attribute

    @classmethod
    def increment(cls):
        cls.num += 1

答案 1 :(得分:4)

if (!s.toString().isEmpty()) { try { List<Address> addresses = geocoder.getFromLocationName(s.toString(), 4); if (addresses.size() > 0) { Address userAddress = addresses.get(0); double latitude = userAddress.getLatitude(); double longitude = userAddress.getLongitude(); mRestaurantLatLng = new LatLng(latitude, longitude); if (userAddress != null) { mPin.setVisibility(View.VISIBLE); } else { mPin.setVisibility(View.GONE); mRestaurantLatLng = null; } } else { mPin.setVisibility(View.GONE); mRestaurantLatLng = null; } } catch (Exception e) { e.printStackTrace(); } 基本上意味着'获取self.num += 1的值,递增它,并分配给self.num

如果没有相应的实例变量,在self.num上查找属性将找到类变量。但是,分配将始终写入实例变量。因此,这会尝试查找实例var,失败,回退到类var,获取值,递增它,然后将分配给实例var

链接问题的答案起作用的原因是因为没有分配正在进行;他们直接在类变量上调用self,它的值被改变但名称没有重新分配。

答案 2 :(得分:2)

增强赋值不会更新类变量。它这样做:

tmp = self.num
self.num = tmp.__iadd__(1)

注意在那里分配回self.num!因此,您的类属性保持不变。整数的object.__iadd__() method不能就地改变数字,因为整数是不可变的,所以foo.num永远不会改变。

您需要显式引用类变量:

foo.num += 1

self.__class__.num += 1