61

たとえば、次のaddような関数がある場合

def add(x,y):
    return x+y

文字列または入力を変換して、次のような関数に転送する機能が必要です。

w=raw_input('Please input the function you want to use')

また

w='add'

関数を参照するためにwを使用する方法はありますaddか?

4

11 に答える 11

67

ユーザー入力を取得しているため、最も安全な方法は、有効な入力を正確に定義することです。

dispatcher={'add':add}
w='add'
try:
    function=dispatcher[w]
except KeyError:
    raise ValueError('invalid input')

のような文字列を評価する場合は、安全なeval'add(3,4)'を使用できます。

eval('add(3,4)',{'__builtins__':None},dispatcher)

eval一般に、ユーザー入力に適用すると危険な場合があります。上記__builtins__は無効であり、localsに制限されているため、より安全dispatcherです。私より賢い人はまだトラブルを起こすことができるかもしれませんが、私はそれを行う方法をあなたに教えることができませんでした。

警告:ユーザー入力に適用することも安全eval(..., {'__builtins__':None}, dispatcher)ではありません。悪意のあるユーザーは、自分の文字列をによって評価する機会が与えられた場合、マシン上で任意の関数を実行する可能性があります。eval

于 2011-10-10T22:40:39.800 に答える
21

安全な方法の 1 つは、名前から関数にマップすることです。を使うより安全ですeval

function_mappings = {
        'add': add,
}

def select_function():
    while True:
        try:
            return function_mappings[raw_input('Please input the function you want to use')]
        except KeyError:
            print 'Invalid function, try again.'
于 2011-10-10T22:43:11.890 に答える
17

組み込み関数evalは、あなたが望むことを行います。ユーザー提供の任意のコードの実行に関する通常の警告がすべて適用されます。

定義済み関数の数が限られている場合は、eval代わりにルックアップ テーブルを使用することを避けてください (つまりDict)。ユーザーを決して信用しないでください。

于 2011-10-10T22:43:02.370 に答える
15

unutbuの解決策は、私が通常使用するものですが、完全を期すために:

関数の正確な名前を指定している場合は、 を使用できますがeval、人々が悪意のあることを行う可能性があるため、非常に推奨されません。

eval("add")(x,y)
于 2011-10-10T22:44:04.227 に答える
5

ユーザーが何らかのコマンド ( addなど) を入力し、アプリケーションが応答する (合計を返す)シェルのようなアプリケーションを実装している場合はcmd、すべてのコマンドのやり取りとディスパッチを処理するモジュールを使用できます。次に例を示します。

#!/usr/bin/env python

import cmd
import shlex
import sys

class MyCmd(cmd.Cmd):
    def do_add(self, arguments):
        '''add - Adds two numbers the print the sum'''
        x, y = shlex.split(arguments)
        x, y = int(x), int(y)
        print x + y

    def do_quit(self, s):
        '''quit - quit the program'''
        sys.exit(0)

if __name__ == '__main__':
    cmd = MyCmd()
    cmd.cmdloop('type help for a list of valid commands')

実行中のセッションの例を次に示します。

$ python cmd_tryout.py
type help 有効なコマンドのリストを表示
(Cmd) help add
add - 2 つの数値を加算し、合計を出力
(Cmd) add 5 3
8
(Cmd) quit

プロンプト(Cmd)helpで、無料で入手できるコマンドを発行できます。その他のコマンドは、addおよび機能quitに対応するdo_add()およびdo_quit()です。

help コマンドは、関数のドキュメント文字列を表示することに注意してください。docstring は、関数宣言の直後に続く文字列です (do_add()例を参照)。

モジュールは引数のcmd分割や解析を行わないため、自分で行う必要があります。do_add()関数はこれを示しています。

このサンプル プログラムは、開始するのに十分なはずです。詳細については、cmdヘルプ ページを参照してください。プログラムのプロンプトやその他の側面をカスタマイズするのはトリビアです。

于 2013-04-30T15:49:34.773 に答える
2

Django テンプレート内で文字列を int と比較したり、その逆を行ったりする必要がある状況が数多くありました。

関数名を渡して eval() を使用して変換できるフィルターを作成しました。

例:

テンプレート:

{% ifequal string int|convert:'str' %} do something {% endifequal %}

テンプレート フィルター (文字列を使用して関数名を呼び出します):

@register.filter
def convert(value, funcname):
    try:
        converted = eval(funcname)(value)
        return converted
    except:
        return value
于 2013-04-30T15:04:42.430 に答える
0

[重複した質問からここにたどり着きました。私が最初に考えたのはargparseandを使用するshlexことでしたが、ここではそれが見られなかったので、別のオプションとして追加しています。]

argparse関数/コマンドのレジストリを設定し、それらの引数を安全に解析するために使用できます。これにより、たとえば、存在しないコマンドを入力したときに通知されるなど、ある程度の使いやすさも提供されます。

import argparse
import shlex

def hello(name):
    print('hello,', name)

def main():
    parser = argparse.ArgumentParser()
    subparsers = parser.add_subparsers()

    hello_parser = subparsers.add_parser('hello')
    hello_parser.add_argument('name')
    hello_parser.set_defaults(func=hello)

    print('Enter q to quit')

    while True:
        command = input('command> ')
        command = command.strip()

        if not command:
            continue

        if command.lower() == 'q':
            break

        words = shlex.split(command)

        try:
            args = parser.parse_args(words)
        except SystemExit:
            # argparse will sys.exit() on -h and errors; prevent that
            continue

        func_args = {name: value for name, value in vars(args).items()}
        del func_args['func']
        args.func(**func_args)

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        print()
于 2017-10-29T00:46:30.947 に答える