Python类变量更新

时间:2016-03-26 20:58:54

标签: python oop

class MyClass(object):
    next_number = 0

    def __init__(self):
        self.number = self.next_number
        MyClass.next_number += 1

class MyClassA(MyClass):
    pass

上面看来,自从写完以来我在第6行更新类变量时强制硬编码类名:

self.__class__.next_number += 1

在任何派生类中生成一个新的类变量。有没有替代硬编码的类名?

同样在第5行我应该写:

self.number = self.__class__.next_number

显而易见next_number是一个类变量。

4 个答案:

答案 0 :(得分:4)

避免重新绑定类变量问题的一种方法是使用包含其中数字的可变对象替换不可变整数值。然后,您可以在适当的位置改变对象。

这个简单版本是将数字放在一个元素列表中:

class MyClass(object):
    next_number = [0]

    def __init__(self):
        self.number = self.next_number[0]
        self.next_number[0] += 1

这有效,但它不是很优雅。

更好的方法是用itertools.count函数返回的迭代器替换整数类变量,每次在其上调用next时,它将连续产生更高的整数(永远,它&# 39;是一个无限的迭代器)。在高级别,这仍然像列表代码一样工作,因为next会改变迭代器,但确切的细节隐藏在迭代器协议(以及itertools.count的实现)之后。

class MyClass(object):
    number_iter = itertools.count()

    def __init__(self):
        self.number = next(self.number_iter) # this mutates number_iter by consuming a value

如果你需要更复杂的东西,itertools没有提供完全正确的序列,你可以编写自己的生成器函数并将其返回值赋给类变量。例如,这里是Fibonacci序列的生成器:

def fib():
    a, b = 0, 1
    while True:
        a, b = b, a+b
        yield a

答案 1 :(得分:2)

你是正确的self.__class__.next_number将为实例化调用此__init__的对象的每个类创建一个变量。

您有两种选择:硬编码类名,或者不从派生类调用super().__init__。 我会和前者一起去。

在我看来,你不必担心在这里对类名进行硬编码。毕竟,班级名称是"硬编码"当你执行class MyClass(object):时,无论如何都已经在这个模块中。

关于你的第二条评论,这是一个很好的考虑因素。我会选择:self.__class__.next_number += 1。这不仅对读者更明确,而且如果您稍后错误地定义了self.next_number,它也可以保证您保持适当的行为。

答案 2 :(得分:0)

def create
@message = Message.create(message_params)
if @message.save
  run_at_time = @message.send_at.present? ? @message.send_at : Time.zone.now
  people = Person.in_groups(message_params[:group_ids])
  if people.any?
    people.each do |person|
      person.delay(run_at: run_at_time).send_message(@message.body)
    end
    flash[:success] = "Messages on their way!"
  end
  redirect_to root_path
else
  render "new"
end
end

输出

class MyClass(object):
    next_number = 0

    def __init__(self):
        self.number = self.__class__.next_number
        self.__class__.next_number += 1

class MyClassA(MyClass):
    pass

a = MyClassA()
print a.next_number
b = MyClassA()
print a.next_number, b.next_number
print a.number, b.number

这是你需要的吗?

答案 3 :(得分:0)

class Test(object):
    next_number = 0

    def __new__(cls, *args, **kwargs):
        cls.next_number += 1
        instance = super(Test, cls).__new__(cls)
        instance.next_number = cls.next_number
        return instance

每个Test()调用方法调用类 new 方法作为构造函数返回对象实例,我们添加字段next_number(每次调用类增加),这是然后在您的班级 init 方法中提供。