stay Python in , There is no syntax sugar that can simplify function definitions at run time . However , This does not mean that it is impossible , Or it is difficult to achieve .
from types import FunctionType
foo_code = compile('def foo(): return "bar"', "<string>", "exec")
foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")
print(foo_func())
Output :
bar
analyse
View code line by line , You will find language / How fragile the barrier of the interpreter is .
>>> from types import FunctionType
Python Documentation usually does not list the characteristics of classes that are not created manually ( It's perfectly reasonable ). There are three ways to solve this problem :help()、inspect( Cannot view built-in methods )、 And the final solution , Check out CPython Source code .
In this case ,help() And inspect Can complete the work , But look at the actual source code , Will reveal more details about data types .
>>> from inspect import signature
>>> signature(FunctionType)
<Signature (code, globals, name=None, argdefs=None, closure=None)>
Built in globals() Method will return a global symbol table for the current module (global symbol table) References to , So it can be used to provide a dictionary that is always consistent with the state of the current table . It is also possible to pass in any other dictionary (FunctionType((lambda: bar).__code__, {"bar" : "baz"}, "foo")() == "baz").
name( Optional )
Control of the returned function __name__ attribute . Only really right lambdas Useful ( Because of anonymity , They usually have no name ), And rename the function .
argdefs( Optional )
By passing in a tuple containing an object of any type , Provides a way to supply default parameter values (def
foo(bar="baz")).(FunctionType((lambda bar: bar).code, {}, "foo", (10,))() == 10).
closure( Optional )
( If you need to CPython(PyPy,Jython,…) Other than Python VM In the implementation of , Probably shouldn't touch , Because it relies heavily on implementation details ).
One cell Tuples of objects . establish cell Objects are not entirely straightforward , Because you need to call CPython The internal components of , But there is a library that can make it more convenient :exalt( Shameless advertising ).( Translation notes : This library was developed by the author .)
>>> foo_code = compile('def foo(): return "bar"', "<string>", "exec")
compile() It's a built-in method , Therefore, it is also well documented .
exec Patterns are used , Because defining a function requires multiple statements .
>>> foo_func = FunctionType(foo_code.co_consts[0], globals(), "foo")
Aggregate everything , And assign the dynamically created function to a variable .
The function compiled by the previous code , Becomes the first constant of the generated code object , So just point to foo_code It's not enough . This is a exec The direct consequence of the pattern , Because the generated code object can contain multiple constants .
>>> print(foo_func())
Dynamically generated functions can be called just like other functions .
ending
Besides doing experiments , There are few scenarios where dynamic function creation is required .
play (Toying around) Python Is a good way to learn this language deeply .
if necessary , You can easily cross the interpreter / The boundaries of language .
As always : Don't abuse language ( ok , No harm at all , Right ?)
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing