简体   繁体   English

仅从 python 文件导入函数

[英]Import only functions from a python file

I have many Python files (submission1.py, submission2.py, ... , submissionN.py) in the following format,我有以下格式的许多 Python 文件(submission1.py、submission2.py、...、submissionN.py),

#submission1.py
def fun():
   print('some fancy function')

fun()

I want to write a tester to test these submissions.我想编写一个测试器来测试这些提交。 (They are actually homeworks that I am grading.). (它们实际上是我正在评分的作业。)。 I have a tester for the fun() which is able to test the function itself.我有一个fun()测试器,它能够测试函数本身。 However, my problem is, when I import submission.py , it runs the fun() since it calls it at the end of file.但是,我的问题是,当我导入submission.py ,它运行fun()因为它在文件末尾调用它。

I know that, using if __name__ == "__main__": is the correct way of handling this issue, however, our submissions does not have it since we did not teach it.我知道,使用if __name__ == "__main__":是处理这个问题的正确方法,但是,我们的提交没有它,因为我们没有教它。

So, my question is, is there any way that I can import only fun() from the submission.py files without running the rest of the python file?所以,我的问题是,有什么方法可以只从submission.py文件中导入fun()而不运行 python 文件的其余部分?

For simple scripts with just functions the following will work:对于只有函数的简单脚本,以下将起作用:

submission1.py :提交1.py

def fun(x):
   print(x)

fun("foo")


def fun2(x):
   print(x)


fun2("bar")

print("debug print")

You can remove all bar the FunctionDef nodes then recompile:您可以删除 FunctionDef 节点的所有栏,然后重新编译:

import ast
import types

with open("submission1.py") as f:
   p = ast.parse(f.read())

for node in p.body[:]:
    if not isinstance(node, ast.FunctionDef):
        p.body.remove(node)



module = types.ModuleType("mod")
code = compile(p, "mod.py", 'exec')
sys.modules["mod"] = module
exec(code,  module.__dict__)

import mod

mod.fun("calling fun")
mod.fun2("calling fun2")

Output:输出:

calling fun
calling fun2

The module body contains two Expr and one Print node which we remove in the loop keeping just the FunctionDef's.模块主体包含两个 Expr 和一个 Print 节点,我们在循环中删除它们,只保留 FunctionDef 的。

[<_ast.FunctionDef object at 0x7fa33357f610>, <_ast.Expr object at 0x7fa330298a90>, 
<_ast.FunctionDef object at 0x7fa330298b90>, <_ast.Expr object at 0x7fa330298cd0>,
 <_ast.Print object at 0x7fa330298dd0>]

So after the loop out body only contains the functions:所以在循环出体之后只包含函数:

[<_ast.FunctionDef object at 0x7f49a786a610>, <_ast.FunctionDef object at 0x7f49a4583b90>]

This will also catch where the functions are called with print which if the student was calling the function from an IDE where the functions have return statements is pretty likely, also to keep any imports of there are any you can keep ast.Import's and ast.ImportFrom's:这也将捕获使用 print 调用函数的位置,如果学生从函数具有返回语句的 IDE 调用函数很可能,也可以保留任何导入,您可以保留 ast.Import 和 ast。进口自:

submission.py:提交.py:

from math import *
import datetime

def fun(x):
    print(x)


fun("foo")


def fun2(x):
    return x

def get_date():
    print(pi)
    return datetime.datetime.now()
fun2("bar")

print("debug print")

print(fun2("hello world"))

print(get_date())

Compile then import:编译然后导入:

for node in p.body[:]:
    if not isinstance(node, (ast.FunctionDef,ast.Import, ast.ImportFrom)):
        p.body.remove(node)
.....

import mod

mod.fun("calling fun")
print(mod.fun2("calling fun2"))
print(mod.get_date())

Output:输出:

calling fun
calling fun2
3.14159265359
2015-05-09 12:29:02.472329

Lastly if you have some variables declared that you need to use you can keep them using ast.Assign:最后,如果您声明了一些需要使用的变量,您可以使用 ast.Assign 保留它们:

submission.py:提交.py:

from math import *
import datetime

AREA = 25
WIDTH = 35

def fun(x):
    print(x)


fun("foo")


def fun2(x):
    return x

def get_date():
    print(pi)
    return datetime.datetime.now()
fun2("bar")

print("debug print")

print(fun2("hello world"))

print(get_date()

Add ast.Assign:添加 ast.Assign:

for node in p.body[:]:
    if not isinstance(node, (ast.FunctionDef,
        ast.Import, ast.ImportFrom,ast.Assign)):
        p.body.remove(node)
....

Output:输出:

calling fun
calling fun2
3.14159265359
2015-05-09 12:34:18.015799
25
35

So it really all depends on how your modules are structured and what they should contain as to what you remove.因此,这实际上完全取决于您的模块的结构以及它们应包含的内容以及您删除的内容。 If there are literally only functions then the first example will do what you want.如果字面上只有函数,那么第一个示例将执行您想要的操作。 If there are other parts that need to be kept it is just a matter of adding them to the isinstance check.如果还有其他部分需要保留,只需将它们添加到 isinstance 检查中即可。

The listing of all the abstract grammar definitions is in the cpython source under Parser/Python.asdl .所有抽象语法定义的列表位于Parser/Python.asdl下的 cpython 源代码中。

You could use sys.settrace() to catch function definitions.您可以使用sys.settrace()来捕获函数定义。

Whenever your fun() is defined, you save it somewhere, and you place a stub into the module you are importing, so that it won't get executed.只要定义了fun() ,就将其保存在某处,并将存根放入要导入的模块中,这样它就不会被执行。

Assuming that fun() gets defined only once, this code should do the trick:假设fun()只定义一次,这段代码应该可以解决问题:

import sys

fun = None

def stub(*args, **kwargs):
    pass

def wait_for_fun(frame, event, arg):
    global fun

    if frame.f_code.co_filename == '/path/to/module.py':
        if 'fun' in frame.f_globals:
            # The function has just been defined. Save it.
            fun = frame.f_globals['fun']
            # And replace it with our stub.
            frame.f_globals['fun'] = stub

            # Stop tracing the module execution.
            return None

    return wait_for_fun

sys.settrace(wait_for_fun)
import my_module

# Now fun() is available and we can test it.
fun(1, 2, 3)
# We can also put it again inside the module.
# This is important if other functions in the module need it.
my_module.fun = fun

This code can be improved in many ways, but it does its job.可以通过多种方式改进此代码,但它可以发挥作用。

maybe if you just want to import the fun () function from submission.py try也许如果你只是想从 submit.py 中导入 fun() 函数试试

from submission import fun从提交导入乐趣

To perform the function of fun, you must include the fun module要执行 fun 的功能,您必须包含 fun 模块

submission.fun()提交.fun()

or if you want to make it easier when calling the fun () function, give it a try from submission import fun as FUN或者如果你想在调用 fun() 函数时更容易一些,试试 from submit import fun as FUN

FUN ()乐趣 ()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM