为Python程序中的参数分配随机值

发布于 2024-11-16 20:13:21 字数 371 浏览 2 评论 0原文

我需要在 __init__() 中分配一个默认随机值。例如:

import math
import random
class Test:
    def __init__(self, r = random.randrange(0, math.pow(2,128)-1)):
        self.r = r
        print self.r

如果我创建 10 个 Test 实例,它们都会获得完全相同的随机值。我不明白为什么会发生这种情况。我知道我可以在 __init__() 内分配随机值,但我很好奇为什么会发生这种情况。我的第一个猜测是,种子是当前时间,并且对象创建的时间太接近,因此获得相同的随机值。我创建的对象相隔 1 秒,但结果仍然相同。

I need to assign a default random value in __init__(). For example:

import math
import random
class Test:
    def __init__(self, r = random.randrange(0, math.pow(2,128)-1)):
        self.r = r
        print self.r

If I create 10 instances of Test, they all get the exact same random value. I don't understand why this is happening. I know I can assign the random value inside the __init__(), but I am curious why this is happening. My first guess was that the seed is the current time and objects are being created too close together, and, as a result, get the same random value. I created objects 1 second apart, but still same result.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夏有森光若流苏 2024-11-23 20:13:21

默认参数的值是在创建函数时设置的,而不是在调用函数时设置的 - 这就是为什么它每次都是相同的。

处理此问题的典型方法是将默认参数设置为 None 并使用 if 语句进行测试。

import math
import random
class Test:
     def __init__(self, r = None):
             if r is None:
                 r = random.randrange(0, math.pow(2,128)-1)
             self.r = r
             print self.r

The value of the default parameter is being set at the time the function is created, not when it is called - that's why it's the same every time.

The typical way to deal with this is to set the default parameter to None and test it with an if statement.

import math
import random
class Test:
     def __init__(self, r = None):
             if r is None:
                 r = random.randrange(0, math.pow(2,128)-1)
             self.r = r
             print self.r
雨的味道风的声音 2024-11-23 20:13:21

random.randrange(0, math.pow(2,128)-1) 在定义函数时计算,而不是在调用函数时计算。

代替使用

class Test:
    def __init__(self, r = None):
        if r is None:
            r = random.randrange(0, math.pow(2,128)-1)
        self.r = r
        print self.r

The random.randrange(0, math.pow(2,128)-1) is evaluated when the function is defined, not when it is called.

Use

class Test:
    def __init__(self, r = None):
        if r is None:
            r = random.randrange(0, math.pow(2,128)-1)
        self.r = r
        print self.r

instead.

一场信仰旅途 2024-11-23 20:13:21

当您将表达式放入构造函数标头(而不是构造函数主体)中时,它只会被计算一次。

在身体里试试这个:

self.r = random.randrange(0,math.pow(0,128)-1)

When you put the expression inside the constructor header (instead of the constructor body) it only gets evaluated once.

Try this in the body:

self.r = random.randrange(0,math.pow(0,128)-1)
晨光如昨 2024-11-23 20:13:21

所有类实例的参数值都相同的原因是,当它所属的方法定义被编译为 class 语句执行的一部分时,它的默认值仅确定一次。

虽然这不是它的设计用途,但您可以使用标题为 自动初始化的配方 20.14实例属性来自有点过时的Python Cookbook,第二版来实现您想要做的事情。

这是它应用于您问题中的示例代码:

class AutoAttr(object):
    def __init__(self, name, factory, *args, **kwds):
        self.data = name, factory, args, kwds
    def __get__(self, obj, cls=None):
        name, factory, args, kwds = self.data
        setattr(obj, name, factory(*args, **kwds))
        return getattr(obj, name)

import math
import random

class Test(object):
    r = AutoAttr('r', random.randrange, 0, math.pow(2,128)-1)  # default value
    def __init__(self, r=None):
        if r is not None:  # argument value supplied to override default?
            self.r = r
        print format(self.r, ',d')

for i in xrange(5):
    Test()
Test(42)  # override default random initial value

示例输出:

282,608,676,427,101,189,083,121,399,193,871,110,434
211,475,719,281,604,076,410,306,973,803,289,140,631
86,842,148,927,120,143,765,936,219,265,140,532,918
41,767,122,731,332,110,507,836,985,804,081,250,336
97,993,619,669,833,151,963,441,072,354,430,500,011
42

它的工作原理如下:

配方中的 auto_attr 类称为 描述符。其中之一被分配给名为 rTest class 属性。第一次使用 self.rTest 实例中访问此属性时,Python 会注意到它绑定到描述符并调用其 __get__() 方法,将 Test 实例作为 obj 参数。

描述符的 __get__() 方法调用关联的工厂函数,并将结果分配给具有相同名称的实例属性,以便通过实例对该属性的所有进一步引用都将获取其实际值而不是 Test 类的 auto_attr 描述符。

The reason all your class instances have the same value for the argument is because its default value is determined only once, when the method definition it is part of is compiled as part of the class statement's execution.

Although this is not the use it was designed for, you could use Recipe 20.14 titled Automatic Initialization of Instance Attributes from the somewhat dated Python Cookbook, 2nd Edition to achieve what you want to do.

This is it applied to the sample code in your question:

class AutoAttr(object):
    def __init__(self, name, factory, *args, **kwds):
        self.data = name, factory, args, kwds
    def __get__(self, obj, cls=None):
        name, factory, args, kwds = self.data
        setattr(obj, name, factory(*args, **kwds))
        return getattr(obj, name)

import math
import random

class Test(object):
    r = AutoAttr('r', random.randrange, 0, math.pow(2,128)-1)  # default value
    def __init__(self, r=None):
        if r is not None:  # argument value supplied to override default?
            self.r = r
        print format(self.r, ',d')

for i in xrange(5):
    Test()
Test(42)  # override default random initial value

Sample output:

282,608,676,427,101,189,083,121,399,193,871,110,434
211,475,719,281,604,076,410,306,973,803,289,140,631
86,842,148,927,120,143,765,936,219,265,140,532,918
41,767,122,731,332,110,507,836,985,804,081,250,336
97,993,619,669,833,151,963,441,072,354,430,500,011
42

Here's how it works:

The auto_attr class from the recipe is a called a descriptor. One of them is assigned to a Test class attribute named r. The first time you access this attribute in an instance of Test using self.r, Python notices it's bound to a descriptor and calls its __get__() method with the Test instance as an obj argument.

The descriptor's __get__() method calls the associated factory function and assigns the result to an instance attribute with the same name, so that all further references to that attribute through the instance will get its actual value instead of the Test class's auto_attr descriptor.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文