【问题标题】:Calling random functions from a list when functions have different number of parameters当函数具有不同数量的参数时从列表中调用随机函数
【发布时间】:2015-03-02 10:08:59
【问题描述】:

我是一名初学者,正在尝试编写基于文本的游戏,例如 Monopoly。因为我了解了函数,所以我认为最好的方法是为每个正方形定义一个函数。然后,我会将这些函数放在一个列表中并随机调用它们。问题是函数可能需要不同数量的参数或不需要参数。

from random import randrange

def foo1(param_of_foo1):
    x = param_of_foo1 + 1
    print "x is:", x

def foo2(param_of_foo2):
    y = param_of_foo2 + 2
    print "y is:", y

def foo3(useless_param):
    print "I have a parameter but I don't really need it..."

list_of_foo = [foo1, foo2, foo3]

arg = 0

function_index = randrange(0,3)

print "Function index is:", function_index

if function_index == 0:
    arg = 4

elif function_index == 1:
    arg = 10

list_of_foo [function_index](arg)

如您所见,这似乎可行,但这不是一个优雅的解决方案。我不喜欢我必须用参数定义第三个函数,即使它不需要它,当然。而且我也不喜欢我必须为某些函数指定一个条件来让他们知道他们应该使用什么作为参数。 当然,必须有更好的方法来做到这一点。总是有的。谢谢,对不起,如果这是愚蠢的或者已经被问过了。我找不到答案。

更新代码:

from random import randrange
from functools import partial

def foo1(arg_of_foo1):
    x = arg_of_foo1 + 1
    print "x is:", x

def foo2(arg1_of_foo2,arg2_of_foo2):
    y = arg1_of_foo2 + arg2_of_foo2
    print "y is:", y

def foo3():
    print "I don't need a parameter so I don't have one."

a = 0
b = 0

while b <= 100:
    print'='*20
    random_number = randrange(0,3)

    a += 1
    b += 10

    print "a is:", a
    print "b is:", b
    print "r_n is:", random_number

    print '-'*10
    raw_input("[Enter] to execute random function")

    list_of_foo = [partial(foo1,a), partial(foo2,a,b), partial(foo3)]

    list_of_foo[random_number]()

这段代码去掉了条件语句和不必要的参数。 谢谢督察!

【问题讨论】:

  • 只是提出一些想法,因为我认为这是没有明确答案的问题。 1)看起来没有任何实际输入会改变参数的值。也许只是摆脱参数并在函数内部有一个常数更有意义? 2)您可能会将使用类视为另一种抽象形式,这可能更适合此特定场景,也可能不适合。同样,在不了解所有细节的情况下很难给出明确的答案,但也许这是一个开始。
  • 一个相当雄心勃勃的项目开始。您可以考虑查看Game Elements as Programmatic Objects,了解使用对象而不是为每个方块定义离散函数的完全不同的游戏开发方法。
  • 谢谢贾斯汀和乔恩。我会考虑的。

标签: python list function random arguments


【解决方案1】:

你可以做三件事:

  1. 在函数定义中使用*args
  2. 重写您的函数以将列表(或元组或字典)作为唯一参数,并从中读取实际参数
  3. 使用ast 读取函数签名,并为其提供正确数量的参数(暂时省略)

使用*args

在 python 中,您可以将 *args 定义为您的函数获取的参数列表,这会将参数序列分配给名为 args 的列表:

In [113]: def func(*args):
   .....:     print "the arguments are:", ' '.join(args)
   .....:     

In [114]: func()
the arguments are:

In [115]: func('a')
the arguments are: a

In [116]: func('a', 'b')
the arguments are: a b

因此,考虑到这一点,您可以这样做:

def foo1(*args):
    param_of_foo1 = args[0]  # any other arguments will be discraded
    x = param_of_foo1 + 1
    print "x is:", x

def foo3(*uselessArgs):
    print "I have a parameter but I don't really need it..."

您仍然可以拨打foo3()foo3(1,2,3)


使用列表

这与以前的想法相同,但您使用参数列表调用:

def foo1(L):
    param_of_foo1 = L[0]  # other entries will be ignored

这需要使用参数列表调用:foo1([1])foo1([1,2,3])

def foo1(arg):
    print "I got this as my argument:", arg

现在,foo1([1,2,3]) 将给出:

我的论据是这样的:[1,2,3]

由于arg 的行为与任何其他列表一样(就像*args 的情况一样),您应该能够提取任意数量的参数(只要提供了它们)。因此,由于您的函数需要的最大参数数为 1,因此始终提供至少一个参数的列表,并且任何额外的参数都将被忽略(尤其是 foo3

还有另一种方式,使用ast,但我认为这不是你想要的,所以我暂时将其省略(评论,我会添加它)


另一方面,如果你只用 4 调用 foo1 和用 10 调用 foo2,那么这应该适合你:

>>> import functools
>>> import random
>>> def foo1(param_of_foo1):
...     x = param_of_foo1 + 1
...     print "x is:", x
... 
>>> def foo2(param_of_foo2):
...     y = param_of_foo2 + 2
...     print "y is:", y
... 
>>> def foo3(useless_param):
...     print "I have a parameter but I don't really need it..."
... 
>>> f = functools.partial(foo1, 4)
>>> f()
x is: 5
>>> list_of_foo = [functools.partial(foo1, 4), functools.partial(foo2, 10), functools.partial(foo3, 'discarded argument')]
>>> random.choice(list_of_foo)()
y is: 12
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
y is: 12
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
y is: 12
>>> random.choice(list_of_foo)()
I have a parameter but I don't really need it...
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> random.choice(list_of_foo)()
x is: 5
>>> 

【讨论】:

  • 谢谢你,检查员。正如我所看到的,当需要向同一个函数发送不同的参数时,*args 会有所帮助。但是,在我的例子中,我们讨论的是一个随机函数,每次调用它时都需要相同的参数。就像我在示例中写的那样,如果随机函数是 'foo1',则发送 'arg = 4'。 list_of_foo[function_index](arg) 的问题是我不知道“function_index”是什么,所以我当然不知道要传递什么参数。这可能比所有人想象的要简单。我只需要一种可以调用函数及其参数的列表。
  • @NyckM.: 你永远不想用 4 以外的任何东西打电话给 foo1 和用 10 以外的任何东西打电话给 foo2 吗?
  • 在游戏中它们实际上是变量,所以......它们各不相同。如果他们不这样做,这对我来说也会很容易......我猜。
  • 所以我注意到我可以在您的 functool 示例中使用变量而不是整数,这正是我想要的。希望我能找到一种使用 randrange 的方法。非常感谢!
【解决方案2】:

对于未知数量的参数或未知类型的参数,只需执行fn(*args)

【讨论】:

  • 这确实是正确答案,但可能需要更多解释,因为 OP 是 Python 的新手。
  • 在我的例子中,我们讨论的是调用需要特定参数的随机函数。 *args 可能会以某种方式工作,但我不知道如何。我敢说我认为它在这种情况下行不通。
  • @NyckM。您是否必须拥有三个独立的函数 foo1、foo2、foo3,或者您可以将它们组合成一个接受未知参数的函数?
  • 为了更容易理解,我基本上想要的是一个列表,我可以将函数名称与要传递的参数的名称放在一起。类似于:list_of_foo = [foo1(arg1,arg2), foo2(), foo3(arg1)]。使用括号将触发该函数,因此这不起作用。字典可能会以某种方式有用。元组也可能有帮助。如果我可以解压缩两个或多个元素的元组,其中第一个元素是函数的名称,其他元素是参数,那就太酷了。
猜你喜欢
  • 1970-01-01
  • 2011-01-26
  • 2011-11-13
  • 1970-01-01
  • 1970-01-01
  • 2019-07-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-10
相关资源
最近更新 更多