Python继承的类都返回相同的随机数?

时间:2018-07-04 22:36:11

标签: python

我有几个类几乎具有相同的内容,因此我尝试了两种方法来复制类及其属性。这些类可以正确复制,但是randint函数仅在主类中调用,因此每次输出相同的数字。有什么方法可以重新计算每个类别的随机数吗?

class a:
    exampleData = random.randint(1,100)

b = type('b', a.__bases__, dict(a.__dict__))

class c(a):
    pass

例如,如果a.exampleData = 50,则b.exampleData和c.exampleData将相同。有什么办法解决吗?

编辑-我的程序的一部分每次都会显示具有随机统计信息的字符,并且该类包含与每个字符相关的统计信息。随机数从列表中选择统计数据,但选择的统计数据相同,而不是在每个类别中都是随机的。我可能没有解释这个权利,所以基本上是这样:

data = [stat1,stat2,stat3,ect,,]
data[random.randint(1,3)]

2 个答案:

答案 0 :(得分:2)

当您写这篇文章时:

b = type('b', a.__bases__, dict(a.__dict__))

…您只是复制a.__dict__。由于a.__dict__只是{'exampleData': 50},所以最终以b.__dict__结尾的新副本也将是{'exampleData': 50}

有很多方法可以获取新的随机数。最简单的方法就是为b显式创建一个新的随机数:

bdict = dict(a.__dict__)
b['exampleData'] = random.randint(1,100)
b = type('b', a.__bases__, bdict)

如果要以这种方式创建一堆类,可以将其包装在一个函数中:

def make_clone(proto, name):
    clonedict = dict(proto.__dict__)
    clonedict['exampleData'] = random.randint(1,100)
    return type(name, proto.__bases__, clonedict)

如果愿意,可以使工厂功能更复杂(有关一个极端示例,请参见namedtuple)。


您可以将该行为包装在装饰器中

def randomize(cls):
    cls.exampleData = random.randint(1,100)

@randomize
class a:
    pass

b = randomize(type('b', a.__bases__, dict(a.__dict__)))

请注意,我这里必须使用普通的函数调用语法来调用装饰器,因为没有声明语句可以将@decorator附加到


或者您可以将其包装在一个元类中:

class RandomMeta(type):
    def __new__(mcls, name, bases, namespace):
        d = dict(namespace)
        d['exampleData'] = random.randint(1,100)
        return type.__new__(mcls, name, bases, d)

class a(metaclass=RandomMeta):
    pass

b = type(a)('b', a.__bases__, dict(a.__dict__))

请注意,我们必须在此处调用type(a),就像使用class定义语句一样,而不是基元类type

还要注意,我没有在**kwds方法中使用__new__,而是直接呼叫type.__new__。这意味着,如果您尝试将RandomMeta与另一个元类(除了type一起使用),则应该获得立即TypeError,而不是可能正确或不正确的东西。


与此同时,我怀疑您在这里真正想做的是建立一个基于原型的继承系统,在Python基于类的系统之上构建一个Self或JavaScript。尽管您可以通过使用特殊的Prototype元类和一堆类对象来做到这一点,但是拥有Prototype类和一堆实例对象要简单得多。元类方法的唯一优点是,您可以使用class语句(具有误导性,但很方便)来克隆原型,而在这里您显然没有这样做。

答案 1 :(得分:0)

尽管my other answer涵盖了所问的问题,但我怀疑这对OP的实际问题完全没有必要。

如果您只想创建一堆单独的对象,每个对象都具有isDisposed()的单独值,则只需要一堆单个类的实例,而不是一堆单独的类。

类是一种特殊的对象,除了完成所有常规对象的工作外,它还充当该类实例的其他对象的工厂。您不需要将exampleDataab都用作不同类型对象的工厂,只需要它们是同一类型的不同对象即可。所以:

c

…,或者,如果要确保class RandomThing: def __init__(self): self.exampleData = random.randint(1,100) a = RandomThing() b = RandomThing() b是同一类型的东西,但不知道是什么类型,

a

那真是太奇妙了。

请参见the official tutorial on Classes(或搜索更友好的教程,因为那里可能有更好的教程)。