【问题标题】:How to add mathematical function as argument in python function如何在python函数中添加数学函数作为参数
【发布时间】:2021-02-01 17:15:49
【问题描述】:

我知道关于将函数传递给函数有类似的问题,但我不清楚针对我的特定问题的有效解决方案。

以下函数有效,但公式是静态的。它仅适用于固定函数,即(在数学伪代码中)f(a) = 3^a mod 17 = b where f(11) = 7

def get_a(b):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
            x = pow(3, a) % 17
            if x == b:
                return a
            if a > 10000:
                return -1
            a += 1


def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')


if __name__ == '__main__':
    main()

我想让用户传入任何给定的函数。首先,我实现了一些稍微复杂但仍然非常简单的东西。

def get_a_variable(b, base, mod):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
        # print(F'a:{a}, b{b}')
        x = pow(base, a) % mod
        # print(F'x:{x}')
        if x == b:
            return a
        if a > 10000:
            return -1
        a += 1

def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')
    a = get_a_variable(7,3,17)
    print(F'Again, the preimage a of b={b} is: {a}')

这可行,但我想让它更加动态。

为了尝试实现这一点,我创建了一个可以作为参数传递的新函数:

def power_mod_function(base, x, mod):
  return power(base, x) % mod

我不确定应该如何处理试验值 arg x,或者它是否应该在这个函数中。

然后我“分叉”了“get_a(b)”函数,我相信该函数接受回调

def get_a_dynamic(b, crypt_func):
    '''
    Get preimage a from A for f(a) = b where b in B
    '''
    a = 1
    while(1):
            x = crypt_func() # Not sure how to manage the arg passing here
            if x == b:
                return a
            if a > 10000:
                return -1
            a += 1

然后我更新了 main():

def main():
    b = 7
    a = get_a(7)
    print(F'The preimage a of b={b} is: {a}')
    a = get_a_dynamic(b, power_mod_function(3, x, 17)) # Not sure how to pass my middle arg!! 
    print(F'Again the preimage a of b={b} is: {a}')

我收到以下错误消息:

 python pre_img_finder.py
The preimage a of b=7 is: 11
Traceback (most recent call last):
  File "pre_img_finder.py", line 45, in <module>
    main()
  File "pre_img_finder.py", line 41, in main
    a = get_a_dynamic(b, power_mod_function(3, x, 17))
NameError: name 'x' is not defined

我不知道如何正确设置它并进行变量传递,以便我可以在 main 中传递静态变量一次,中间测试变量 x 将始终递增并最终找到我想要的结果。

也许我只需要接收一个以“类型”参数开头的函数,该参数充当一种开关,然后根据类型接受可变数量的参数。例如,我们可以将上述称为 base-power-mod 函数或 (bpm),其中“power”是我们正在寻找的答案,即 a 是技术术语 b 的原像。然后只需调用

main():
    a = get_a_dynamic(7, ("bpm", 3,17))

然后以这种方式实现它? 感谢您的帮助!

【问题讨论】:

    标签: python function cryptanalysis


    【解决方案1】:

    使用*args 将额外的任意数量的参数传递给函数。

    def get_a_dynamic(b, crypt_func, *args):
        '''
        Get preimage a from A for f(a) = b where b in B
        '''
        a = 1
        while(1):
                x = crypt_func(*args) 
                if x == b:
                    return a
                if a > 10000:
                    return -1
                a += 1
    

    然后像这样在你的 main 中调用它

    def main():
        b = 7
        a = get_a(7)
        print(F'The preimage a of b={b} is: {a}')
        a = get_a_dynamic(b, power_mod_function, 3, x, 17) 
        print(F'Again the preimage a of b={b} is: {a}')
    

    【讨论】:

      【解决方案2】:

      生成带有部分定义参数的动态函数的方法是...functools.partial

      
      from functools import partial
      
      def get_a_variable_with_func(b, func):
          '''
          Get preimage a from A for f(a) = b where b in B
          '''
          a = 1
          while(1):
              x = func(a)
              if x == b:
                  return a
              if a > 10000:
                  return -1
              a += 1
      
      b = 7
      
      def power_mod_function(base, mod, x):
          return (base ** x) % mod
      
      partial_func = partial(power_mod_function, 3, 17)
      
      a = get_a_variable_with_func(7, partial_func)
      print(a)
      >>>
      11
      

      顺便说一句,这更像是pythonic:

      from functools import partial
      
      def get_a_variable_with_func(b, func):
          '''
          Get preimage a from A for f(a) = b where b in B
          '''
          for a in range(10001):
              if func(a) == b:
                  return a
          return -1
      
      def power_mod_function(base, mod, x):
          return (base ** x) % mod
      
      a = get_a_variable_with_func(7, partial(power_mod_function, 3, 17))
      print(a)
      
      

      【讨论】:

        【解决方案3】:

        当你这样做时:

        a = get_a_dynamic(b, power_mod_function(3, x, 17))
        

        你没有将power_mod_function 传递给get_a_dynamic,你传递了它的结果 反而。要传递函数,您只需传递函数名称。

        因此,由于该函数需要get_a_dynamic 的内部值(x 参数)以及两个外部参数(3 和 17),因此您必须将这两个参数分别传递给 get_a_dynamic,以便它能够调用传递的具有三个所需参数的函数。

        为此,可以使用 AnkurSaxena 的建议,特别是如果 args 的数量可以变化。但你也可以这样声明:

        def get_a_dynamic(b, crypt_func, pow, mod):
        

        然后像这样使用它:

        a = get_a_dynamic(b, power_mod_function, 3, 17))
        

        【讨论】:

          【解决方案4】:

          你做这样的事情:

          def get_a_dynamic(b, function, argtuple):
              # …
              x = function(*argtuple) # star-operator unpacks a sequence
              # … et cetera
          

          ……本质上。然后,您可以在传递 argtuple 时始终检查它的范围,或者对您的调用约定一丝不苟——但我认为,星号运算符解包位是您正在寻找的关键。

          如果您想将函数的名称作为字符串传递(根据您的示例),您可以执行以下操作:

          function = globals()["bpm"] # insert your passed string argument therein
          

          ……但这有点粗略,我不推荐它——在这种情况下,最好预先填充一个字典,将函数字符串名称映射到函数本身。

          【讨论】:

          • 另外:如果您要在这样的循环中调用标量数字纯函数,您可能会喜欢 Cython:cython.org
          猜你喜欢
          • 1970-01-01
          • 2022-01-22
          • 1970-01-01
          • 2019-02-14
          • 1970-01-01
          • 2011-09-11
          • 1970-01-01
          • 1970-01-01
          • 2014-04-01
          相关资源
          最近更新 更多