30541


学生向けにプログラミング能力を試験するテストを作りました。  
<https://github.com/ernix/quiz/blob/master/q1.py>

python2で書かれており、指定の機能もったメソッドをクラスに実装するテストなのですが、実行することでクラス自身が自己採点できるような作りになっています。

その中でevalのような一部のビルトイン関数を使われる事が無いよう制限をかけたいのですが、`tokenize`を使ってメソッドの字面だけをパースする方法だとデコレータが使われりプライベートメソッドを呼び出した時に対応できません。

一部抜粋:

[code]

            """ test 3: keywords """
            from cStringIO import StringIO
            import inspect
            import tokenize
            code = StringIO(''.join(inspect.getsourcelines(method)[0][1:]))
            tokens = tokenize.generate_tokens(code.readline)
            name_tokens = []
            for toknum, tokval, _, _, _ in tokens:
                if toknum == tokenize.NAME and tokval in used_keyword.keys():
                    name_tokens.append(tokval)
    
            for t in set(name_tokens):
                if t in kw_not_allowed:
                    errors.append(['`%s` is not allowed' % (t)])
                elif used_keyword[t] is not None:
                    errors.append([
                        '`%s` is already used in %s' % (t, used_keyword[t]),
                    ])
                else:
                    used_keyword[t] = f
    
[/code]

特に`inspect.getsourcelines(method)[0][1:]`のあたりです。defから始まる最初の行はスキップするようになっています。

このようにメソッドの中身を単純にパースするのではなく、動的にビルトイン関数を上書きしてエラーを出すように変更することは可能でしょうか？


CC BY-SA 3.0
2016-11-19T11:07:24.240
30539
2016-11-19T15:31:09.033
62
question
python
メソッドで使用される標準関数によってエラーを出す方法


手軽な例として、これではどうでしょう？

[code]

    >>> x = 1
    >>> eval('x+1')
    2
    >>> __builtins__.eval = lambda x: 'eval is not allowed'
    >>> eval('x+1')
    'eval is not allowed'
    
[/code]

ただ、この方法では組み込み関数(eval, execfile)は置き換えられますが、予約語や文(print, exec)は置き換えられません。


CC BY-SA 3.0
2016-11-19T15:31:09.033
30541
2016-11-19T15:31:09.033
806
30539
answer