override class variable in python?

2019-02-12 18:04发布

Below, base_id and _id is a class variable and shared among all child classes.
Is there a way to separate them into each class?

from itertools import count

class Parent(object):
    base_id = 0
    _id = count(0)

    def __init__(self):
        self.id = self.base_id + self._id.next()


class Child1(Parent):
    base_id = 100
    def __init__(self):
        Parent.__init__(self)
        print 'Child1:', self.id

class Child2(Parent):
    base_id = 200
    def __init__(self):
        Parent.__init__(self)
        print 'Child2:', self.id

c1 = Child1()                   # 100
c2 = Child2()                   # 201 <- want this to be 200
c1 = Child1()                   # 102 <- want this to be 101
c2 = Child2()                   # 203 <- want this to be 201

标签: python class
3条回答
祖国的老花朵
2楼-- · 2019-02-12 18:18

If you don't want to violate the DRY principle like falsetru suggests, you'll need to use metaclasses. I was thinking of writing something up, but there's already a good long description of metaclasses on SO, so check it out.

Metaclasses, in short, let you control subclass creation.

Basically, what you need to do is, upon the creation of a subclass of Parent, add the _id member to the newly-created subclass.

查看更多
看我几分像从前
3楼-- · 2019-02-12 18:18

If you really need to use the ID this way, use parameters:

class Parent(object):
    def __init__(self, id):
        self.id = id

class Child1(Parent):
    _id_counter = count(0)
    def __init__(self):
        Parent.__init__(self, 100 + self._id_counter.next())
        print 'Child1:', self.id

etc.

This assumes you won't be constructing instances of Parent directly, but that looks reasonable with your example code.

查看更多
不美不萌又怎样
4楼-- · 2019-02-12 18:34

As you said in the question, _id is shared by parent and all children classes. Define _id for every children classes.

from itertools import count

class Parent(object):
    base_id = 0
    _id = count(0)

    def __init__(self):
        self.id = self.base_id + self._id.next()


class Child1(Parent):
    base_id = 100
    _id = count(0) # <-------
    def __init__(self):
        Parent.__init__(self)
        print 'Child1:', self.id

class Child2(Parent):
    base_id = 200
    _id = count(0) # <-------
    def __init__(self):
        Parent.__init__(self)
        print 'Child2:', self.id

c1 = Child1()                   # 100
c2 = Child2()                   # 200
c1 = Child1()                   # 101
c2 = Child2()                   # 201

UPDATE

Using metaclass:

class IdGenerator(type):
    def __new__(mcs, name, bases, attrs):
        attrs['_id'] = count(0)
        return type.__new__(mcs, name, bases, attrs)

class Parent(object):
    __metaclass__ = IdGenerator
    base_id = 0
    def __init__(self):
        self.id = self.base_id + next(self._id)
查看更多
登录 后发表回答