exec() perform means that you can execute arbitrary Python code from a string or compiled code enter.
exec() perform will be useful when you might want to run dynamically generated Python code, however it may be fairly harmful in case you use it carelessly. On this tutorial, you’ll study not solely how you can use
exec(), however simply as importantly, when it’s okay to make use of this perform in your code.
On this tutorial, you’ll learn to:
- Work with Python’s built-in
exec()to execute code that comes as strings or compiled code objects
- Assess and decrease the safety dangers related to utilizing
exec()in your code
Moreover, you’ll write a couple of examples of utilizing
exec() to unravel totally different issues associated to dynamic code execution.
Attending to Know Python’s
exec() perform means that you can execute any piece of Python code. With this perform, you’ll be able to execute dynamically generated code. That’s the code that you simply learn, auto-generate, or get hold of throughout your program’s execution. Usually, it’s a string.
exec() perform takes a bit of code and executes it as your Python interpreter would. Python’s
exec() is like
eval() however much more highly effective and susceptible to safety points. Whereas
eval() can solely consider expressions,
exec() can execute sequences of statements, in addition to imports, perform calls and definitions, class definitions and instantiations, and extra. Basically,
exec() can execute a whole absolutely featured Python program.
The signature of
exec() has the next kind:
exec(code [, globals [, locals]])
The perform executes
code, which will be both a string containing legitimate Python code or a compiled code object.
Be aware: Python is an interpreted language as a substitute of a compiled one. Nonetheless, once you run some Python code, the interpreter interprets it into bytecode, which is an inside illustration of a Python program within the CPython implementation. This intermediate translation can also be known as compiled code and is what Python’s virtual machine executes.
code is a string, then it’s parsed as a set of Python statements, which is then internally compiled into bytecode, and eventually executed, except a syntax error happens through the parsing or compilation step. If
code holds a compiled code object, then it’s executed straight, making the method a bit extra environment friendly.
exec() perform’s return worth is
None, most likely as a result of not each piece of code has a closing, distinctive, and concrete outcome. It might simply have some side effects. This habits notably differs from
eval(), which returns the results of the evaluated expression.
To get an preliminary feeling of how
exec() works, you’ll be able to create a rudimentary Python interpreter with two strains of code:
>>> whereas True: ... exec(enter("->> ")) ... ->> print("Hiya, World!") Hiya, World! ->> import this The Zen of Python, by Tim Peters Lovely is healthier than ugly. Express is healthier than implicit. Easy is healthier than advanced. ... ->> x = 10 ->> if 1 <= x <= 10: print(f"x is between 1 and 10") 10 is between 1 and 10
On this instance, you employ an infinite
while loop to imitate the habits of a Python interpreter or REPL. Contained in the loop, you employ
input() to get the consumer’s enter on the command line. Then you definitely use
exec() to course of and run the enter.
This instance showcases what’s arguably the principle use case of
exec(): executing code that involves you as a string.
Be aware: You’ve discovered that utilizing
exec() can indicate safety dangers. Now that you simply’ve seen the principle use case of
exec(), what do you suppose these safety dangers could be? You’ll discover the reply later on this tutorial.
You’ll generally use
exec() when you might want to dynamically run code that comes as a string. For instance, you’ll be able to write a program that generates strings containing legitimate Python code. You possibly can construct these strings from components that you simply get hold of at totally different moments in your program’s execution. You may also use the consumer’s enter or another enter supply to assemble these strings.
When you’ve constructed the goal code as strings, then you should utilize
exec() to execute them as you’d execute any Python code.
On this state of affairs, you’ll be able to not often make certain of what your strings will include. That’s one purpose why
exec() implies critical safety dangers. That is notably true in case you’re utilizing untrusted enter sources, like a consumer’s direct enter, in constructing your code.
In programming, a perform like
exec() is an extremely highly effective instrument as a result of it means that you can write packages that generate and execute new code dynamically. To generate this new code, your packages will use data obtainable at runtime solely. To run the code, your packages will use
Nonetheless, with nice energy comes nice accountability. The
exec() perform implies critical security risks, as you’ll study quickly. So, you must keep away from utilizing
exec() more often than not.
Within the following sections, you’ll learn the way
exec() works and how you can use this perform for executing code that comes as strings or as compiled code objects.
Working Code From a String Enter
The commonest solution to name
exec() is with code that comes from a string-based enter. To construct this string-based enter, you should utilize:
- Single strains of code or one-liner code snippets
- A number of strains of code separated by semicolons
- A number of strains of code separated by newline characters
- A number of strains of code inside triple-quoted strings and with correct indentation
A one-liner program consists of a single line of code that performs a number of actions directly. Say that you’ve got a sequence of numbers, and also you need to construct a brand new sequence containing the sum of squares of all of the even numbers in an enter sequence.
To unravel this drawback, you should utilize the next one-liner code:
>>> numbers = [2, 3, 7, 4, 8] >>> sum(quantity**2 for quantity in numbers if quantity % 2 == 0) 84
Within the highlighted line, you employ a generator expression to compute the sq. worth of all of the even numbers within the enter sequence of values. Then you definitely use
sum() to compute the overall sum of squares.
To run this code with
exec(), you simply want to rework your one-liner code right into a single-line string:
>>> exec("outcome = sum(quantity**2 for quantity in numbers if quantity % 2 == 0)") >>> outcome 84
On this instance, you categorical the one-liner code as a string. Then you definitely feed this string into
exec() for execution. The one distinction between your unique code and the string is that the latter shops the computation lead to a variable for later entry. Keep in mind that
None fairly than a concrete execution outcome. Why? As a result of not each piece of code has a closing distinctive outcome.
Python means that you can write a number of statements in a single line of code, utilizing semicolons to separate them. Regardless that this apply is discouraged, nothing will cease you from doing one thing like this:
>>> title = enter("Your title: "); print(f"Hiya, title!") Your title: Leodanis Hiya, Leodanis!
You should utilize semicolons to separate a number of statements and construct a single-line string that serves as an argument to
exec(). Right here’s how:
>>> exec("title = enter('Your title: '); print(f'Hiya, title!')") Your title: Leodanis Hiya, Leodanis!
The thought of this instance is that you may mix a number of Python statements right into a single-line string by utilizing semicolons to separate them. Within the instance, the primary assertion takes the consumer’s enter, whereas the second assertion prints a greeting message to the display screen.
You may also mixture a number of statements in a single-line string utilizing the newline character,
>>> exec("title = enter('Your title: ')nprint(f'Hiya, title!')") Your title: Leodanis Hiya, Leodanis!
The newline character makes
exec() perceive your single-line string as a multiline set of Python statements. Then
exec() runs the aggregated statements in a row, which works like a multiline code file.
The ultimate method to constructing a string-based enter for feeding
exec() is to make use of triple-quoted strings. This method is arguably extra versatile and means that you can generate string-based enter that appears and works like regular Python code.
It’s vital to notice that this method requires you to make use of correct indentation and code formatting. Think about the next instance:
>>> code = """ ... numbers = [2, 3, 7, 4, 8] ... ... def is_even(quantity): ... return quantity % 2 == 0 ... ... even_numbers = [number for number in numbers if is_even(number)] ... ... squares = [number**2 for number in even_numbers] ... ... outcome = sum(squares) ... ... print("Unique knowledge:", numbers) ... print("Even numbers:", even_numbers) ... print("Sq. values:", squares) ... print("Sum of squares:", outcome) ... """ >>> exec(code) Unique knowledge: [2, 3, 7, 4, 8] Even numbers: [2, 4, 8] Sq. values: [4, 16, 64] Sum of squares: 84
On this instance, you employ a triple-quoted string to offer the enter to
exec(). Be aware that this string seems to be like every common piece of Python code. It makes use of applicable indentation, naming fashion, and formatting. The
exec() perform will perceive and execute this string as an everyday Python code file.
It’s best to word that once you move a string with code to
exec(), the perform will parse and compile the goal code into Python bytecode. In all instances, the enter string ought to include legitimate Python code.
exec() finds any invalid syntax through the parsing and compilation steps, then the enter code received’t run:
>>> exec("print('Hiya, World!)") Traceback (most up-to-date name final): File "<stdin>", line 1, in <module> File "<string>", line 1 print('Hiya, World!) ^ SyntaxError: unterminated string literal (detected at line 1)
On this instance, the goal code incorporates a name to
print() that takes a string as an argument. This string isn’t correctly ended with a closing single citation mark, so
exec() raises a
SyntaxError mentioning the difficulty and doesn’t run the enter code. Be aware that Python pinpoints the error initially of the string fairly than on the finish, the place the closing single citation mark ought to go.
Working code that comes as a string, such as you did within the instance above, is arguably the pure approach of utilizing
exec(). Nonetheless, if you might want to run the enter code many occasions, then utilizing a string as an argument will make the perform run the parsing and compilation steps each time. This habits could make your code inefficient when it comes to execution velocity.
On this state of affairs, probably the most handy method is to compile the goal code beforehand after which run the ensuing bytecode with
exec() as many occasions as wanted. Within the following part, you’ll learn to use
exec() with compiled code objects.
Executing Compiled Code
exec() will be fairly gradual once you use it to course of strings containing code. When you ever have to dynamically run a given piece of code greater than as soon as, then compiling it beforehand would be the most performant and really useful method. Why? Since you’ll be operating the parsing and compilation steps solely as soon as after which reusing the compiled code.
To compile a bit of Python code, you should utilize
compile(). This built-in perform takes a string as an argument and runs a one-time bytecode compilation on it, producing a code object that you may then move to
exec() for execution.
The signature of
compile() has the next kind:
compile(supply, filename, mode, flags=0, dont_inherit=False, optimize=-1)
On this tutorial, you’ll solely use the three first arguments to
supply argument holds the code that you might want to compile into bytecode. The
filename argument will maintain the file from which the code was learn. To learn from a string object, you’ll need to set
filename to the
Be aware: To dive deeper into the remainder of the arguments to
compile(), take a look at the perform’s official documentation.
compile() can generate code objects that you may execute utilizing both
eval(), relying on the
mode argument’s worth. This argument must be set to
"eval", relying on the goal execution perform:
>>> string_input = """ ... def sum_of_even_squares(numbers): ... return sum(quantity**2 for quantity in numbers if quantity % 2 == 0) ... ... print(sum_of_even_squares(numbers)) ... """ >>> compiled_code = compile(string_input, "<string>", "exec") >>> exec(compiled_code) >>> numbers = [2, 3, 7, 4, 8] >>> exec(compiled_code) 84 >>> numbers = [5, 3, 9, 6, 1] >>> exec(compiled_code) 36
Compiling often-repeated code up entrance with
compile() can assist you barely enhance your code’s efficiency by skipping the parsing and bytecode compilation steps on every name to
Working Code From Python Supply Information
You may also use
exec() to run code that you simply’ve learn from a dependable
.py file in your file system or someplace else. To do that, you should utilize the built-in
open() perform to learn the file’s content material as a string, which you’ll be able to then move as an argument to
For instance, say that you’ve got a Python file named
hey.py containing the next code:
# hey.py print("Hiya, Pythonista!") print("Welcome to Actual Python!") def greet(title="World"): print(f"Hiya, title!")
This pattern script prints a greeting and a welcome message to the display screen. It additionally defines a pattern
greet() perform for testing functions. The perform takes a reputation as an argument and prints a personalized greeting to the display screen.
Now get again to your Python interactive session and run the next code:
>>> with open("hey.py", mode="r", encoding="utf-8") as hey: ... code = hey.learn() ... >>> exec(code) Hiya, Pythonista! Welcome to Actual Python! >>> greet() Hiya, World! >>> greet("Pythonista") Hiya, Pythonista!
On this instance, you first open the goal
.py file as an everyday textual content file utilizing the built-in
open() perform in a
with statement. Then you definitely name
.read() on the file object to learn the file’s content material into the
code variable. This name to
.learn() returns the file’s content material as a string. The ultimate step is to name
exec() with this string as an argument.
This instance runs the code and makes the
greet() perform and objects that stay in
hey.py obtainable in your present namespace. That’s why you should utilize
greet() straight. The key behind this habits has to do with the
locals arguments, which you’ll study within the subsequent part.
Utilizing the approach within the above instance, you’ll be able to open, learn, and execute any file containing Python code. This system may fit once you don’t know up entrance which supply information you’ll be operating. So, you’ll be able to’t write
import module, since you don’t know the module’s title once you’re writing the code.
Be aware: In Python, you’ll discover safer methods to acquire an analogous outcome. You should utilize the import system, for instance. To dive deeper into this various, take a look at Dynamic Imports.
When you ever select to make use of this system, then just be sure you solely execute code from trusted supply information. Ideally, probably the most dependable supply information are people who you have consciously created to run dynamically. You need to by no means run code information that come from exterior sources, together with your customers, with out inspecting the code first.
You possibly can move an execution context to
exec() utilizing the
locals arguments. These arguments can settle for dictionary objects that’ll work as the worldwide and native namespaces that
exec() will use to run the goal code.
These arguments are non-compulsory. When you omit them, then
exec() will execute the enter code within the present scope, and all of the names and objects on this scope can be obtainable to
exec(). Likewise, all of the names and objects that you simply outline within the enter code can be obtainable within the present scope after the decision to
Think about the next instance:
>>> code = """ ... z = x + y ... """ >>> # World names are accessible from exec() >>> x = 42 >>> y = 21 >>> z Traceback (most up-to-date name final): ... NameError: title 'z' will not be outlined >>> exec(code) >>> # Names in code can be found within the present scope >>> z 63
This instance reveals that in case you name
exec() with out offering particular values to the
locals arguments, then the perform runs the enter code within the present scope. On this case, the present scope is the worldwide one.
Be aware that after you name
exec(), the names outlined within the enter code are additionally obtainable within the present scope. That’s why you’ll be able to entry
z within the closing line of code.
When you solely present a worth to
globals, then that worth have to be a dictionary. The
exec() perform will use this dictionary for each world and native names. This habits will prohibit entry to most names within the present scope:
>>> code = """ ... z = x + y ... """ >>> x = 42 >>> y = 21 >>> exec(code, "x": x) Traceback (most up-to-date name final): ... NameError: title 'y' will not be outlined >>> exec(code, "x": x, "y": y) >>> z Traceback (most up-to-date name final): ... NameError: title 'z' will not be outlined
Within the first name to
exec(), you employ a dictionary because the
globals argument. As a result of your dictionary doesn’t present a key holding the
y title, the decision to
exec() doesn’t have entry to this title and raises a
Within the second name to
exec(), you present a distinct dictionary to
globals. On this case, the dictionary incorporates each variables,
y, which permits the perform to work accurately. Nonetheless, this time you don’t have entry to
z after the decision to
exec(). Why? Since you’re utilizing a customized dictionary to offer an execution scope to
exec() fairly than falling again to your present scope.
When you name
exec() with a
globals dictionary that doesn’t include the
__builtins__ key explicitly, then Python will robotically insert a reference to the built-in scope or namespace underneath that key. So, all of the built-in objects can be accessible out of your goal code:
>>> code = """ ... print(__builtins__) ... """ >>> exec(code, ) '__name__': 'builtins', '__doc__': "Constructed-in features, ...
On this instance, you’ve supplied an empty dictionary to the
globals argument. Be aware that
exec() nonetheless has entry to the built-in namespace as a result of this namespace is robotically inserted into the supplied dictionary underneath the
When you present a worth for the
locals argument, then it may be any mapping object. This mapping object will maintain the native namespace when
exec() is operating your goal code:
>>> code = """ ... z = x + y ... print(f"z=") ... """ >>> x = 42 # World title >>> def func(): ... y = 21 # Native title ... exec(code, "x": x, "y": y) ... >>> func() z=63 >>> z Traceback (most up-to-date name final): ... NameError: title 'z' will not be outlined
The decision to
exec() is embedded in a perform on this instance. Due to this fact, you will have a world (module-level) scope and a neighborhood (function-level) scope. The
globals argument offers the
x title from the worldwide scope, and the
locals argument offers the
y title from the native scope.
Be aware that after operating
func(), you don’t have entry to
z as a result of this title was created underneath the native scope of
exec(), which isn’t obtainable from the surface.
locals arguments, you’ll be able to tweak the context during which
exec() runs your code. These arguments are fairly useful with regards to minimizing the safety dangers related to
exec(), however you must nonetheless just be sure you’re operating code from trusted sources solely. Within the following part, you’ll study these safety dangers and how you can cope with them.
Uncovering and Minimizing the Safety Dangers Behind
As you’ve discovered to this point,
exec() is a robust instrument that means that you can execute arbitrary code that involves you as strings. It’s best to use
exec() with excessive care and warning due to its capacity to run any piece of code.
Sometimes, the code that feeds
exec() is dynamically generated at runtime. This code could have many sources of enter, which may embrace your program consumer, different packages, a database, a stream of knowledge, and a community connection, amongst others.
On this state of affairs, you’ll be able to’t be fully positive what the enter string will include. So, the likelihood of going through an untrusted and malicious supply of enter code is fairly excessive.
The safety points related to
exec() are the most typical purpose why many Python builders advocate avoiding this perform altogether. Discovering a greater, sooner, extra strong, and safer resolution is sort of at all times attainable.
Nonetheless, in case you should use
exec() in your code, then the widely really useful method is to make use of it with specific
One other vital subject with
exec() is that it breaks a elementary assumption in programming: the code that you simply’re at present studying or writing is the code that you simply’ll be executing once you fireplace up your program. How does
exec() break this assumption? It makes your packages run new and unknown code that’s dynamically generated. This new code will be laborious to observe, keep, and even management.
Within the following sections, you’ll dive into a couple of suggestions, methods, and practices that you must apply in case you ever want to make use of
exec() in your code.
Avoiding Enter From Untrusted Sources
In case your customers can present your packages with arbitrary Python code at runtime, then points can come up in the event that they enter code that violates or breaks your safety guidelines. For instance this drawback, get again to the Python interpreter instance that makes use of
exec() for code execution:
>>> whereas True: ... exec(enter("->> ")) ... ->> print("Hiya, World!") Hiya, World!
Now say that you simply need to use this system to implement an interactive Python interpreter on considered one of your Linux net servers. When you permit your customers to move arbitrary code into your program straight, then a malicious consumer may present one thing like
"import os; os.system('rm -rf *')". This code snippet will most likely take away all of the content material of your server’s disk, so don’t run it.
To stop this threat, you’ll be able to prohibit entry to the
import system by benefiting from the
>>> exec("import os", "__builtins__": , ) Traceback (most up-to-date name final): ... ImportError: __import__ not discovered
import system internally makes use of the built-in
__import__() perform. So, in case you forbid entry to the built-in namespace, then the
import system received’t work.
Regardless that you’ll be able to tweak the
globals dictionary as proven within the above instance, one factor that you will need to by no means do is to make use of
exec() for operating exterior and probably unsafe code by yourself pc. Even in case you rigorously clear up and validate the enter, you’ll threat being hacked. So, you’re finest avoiding this apply.
locals to Reduce Dangers
You possibly can present customized dictionaries because the
locals arguments if you wish to fine-tune the entry to world and native names when operating code with
exec(). For instance, in case you move empty dictionaries to each
exec() received’t have entry to your present world and native namespaces:
>>> x = 42 >>> y = 21 >>> exec("print(x + y)", , ) Traceback (most up-to-date name final): ... NameError: title 'x' will not be outlined
When you name
exec() with empty dictionaries for
locals, you then forbid entry to world and native names. This tweak means that you can prohibit the names and objects obtainable once you’re operating code with
Nonetheless, this system doesn’t assure a protected use of
exec(). Why? As a result of the perform nonetheless has entry to all of Python’s built-in names, as you discovered within the section concerning the
>>> exec("print(min([2, 3, 7, 4, 8]))", , ) 2 >>> exec("print(len([2, 3, 7, 4, 8]))", , ) 5
In these examples, you employ empty dictionaries for
exec() can nonetheless entry built-in features like
print(). How would you stop
exec() from accessing built-in names? That’s the subsequent part’s matter.
Deciding on Allowed Constructed-in Names
As you’ve already discovered, in case you move a customized dictionary to
globals and not using a
__builtins__ key, then Python will robotically replace that dictionary with all of the names within the built-in scope underneath a brand new
__builtins__ key. To limit this implicit habits, you should utilize a
globals dictionary containing a
__builtins__ key with an applicable worth.
For instance, if you wish to forbid entry to built-in names utterly, then you’ll be able to name
exec() like within the following instance:
>>> exec("print(min([2, 3, 7, 4, 8]))", "__builtins__": , ) Traceback (most up-to-date name final): ... NameError: title 'print' will not be outlined
On this instance, you set
globals to a customized dictionary containing a
__builtins__ key with an empty dictionary as its related worth. This apply prevents Python from inserting a reference to the built-in namespace into
globals. This fashion, you make sure that
exec() received’t have entry to built-in names whereas executing your code.
You may also tweak your
__builtins__ key in case you want
exec() to entry sure built-in names solely:
>>> allowed_builtins = "__builtins__": "min": min, "print": print >>> exec("print(min([2, 3, 7, 4, 8]))", allowed_builtins, ) 2 >>> exec("print(len([2, 3, 7, 4, 8]))", allowed_builtins, ) Traceback (most up-to-date name final): ... NameError: title 'len' will not be outlined
Within the first instance,
exec() efficiently runs your enter code as a result of
print() are current within the dictionary related to the
__builtins__ key. Within the second instance,
exec() raises a
NameError and doesn’t run your enter code as a result of
len() isn’t current within the supplied
The methods within the above examples permit you to decrease the safety implications of utilizing
exec(). Nonetheless, these methods aren’t fully foolproof. So, everytime you really feel that you might want to use
exec(), strive to think about one other resolution that doesn’t use the perform.
exec() Into Motion
Up up to now, you’ve discovered how the built-in
exec() perform works. You recognize that you should utilize
exec() to run both string-based or compiled-code enter. You additionally discovered that this perform can take two non-compulsory arguments,
locals, which let you tweak the execution namespace for
Moreover, you’ve discovered that utilizing
exec() implies some critical safety points, together with permitting customers to run arbitrary Python code in your pc. You studied some really useful coding practices that assist decrease the safety dangers related to
exec() in your code.
Within the following sections, you’ll code a couple of sensible examples that’ll assist you to spot these use instances during which utilizing
exec() will be applicable.
Working Code From Exterior Sources
exec() to execute code that comes as strings from both your customers or another supply might be the most typical and harmful use case of
exec(). This perform is the quickest approach so that you can settle for code as strings and run it as common Python code within the context of a given program.
You need to by no means use
exec() to run arbitrary exterior code in your machine, as a result of there’s no safe solution to do it. When you’re going to make use of
exec(), then use it as a solution to let your customers run their very own code on their very own machines.
timeit module offers a fast solution to time small items of Python code that come as strings. Try the next instance from the module’s documentation:
>>> from timeit import timeit >>> timeit("'-'.be a part of(str(n) for n in vary(100))", quantity=10000) 0.1282792080000945
timeit() perform takes a code snippet as a string, runs the code, and returns a measurement of the execution time. The perform additionally takes a number of different arguments. For instance,
quantity means that you can present the variety of occasions that you simply need to execute the goal code.
On the coronary heart of this perform, you’ll discover the
Timer makes use of
exec() to run the supplied code. When you examine the supply code of
Timer within the
timeit module, you then’ll discover that the category’s initializer,
.__init__(), consists of the next code:
# timeit.py # ... class Timer: """Class for timing execution velocity of small code snippets.""" def __init__( self, stmt="move", setup="move", timer=default_timer, globals=None ): """Constructor. See class doc string.""" self.timer = timer local_ns = global_ns = _globals() if globals is None else globals # ... src = template.format(stmt=stmt, setup=setup, init=init) self.src = src # Save for traceback show code = compile(src, dummy_src_name, "exec") exec(code, global_ns, local_ns) self.inside = local_ns["inner"] # ...
The decision to
exec() within the highlighted line executes the consumer’s code utilizing
local_ns as its world and native namespaces.
This fashion of utilizing
exec() is acceptable once you’re offering a instrument on your customers, who should present their very own goal code. This code will run on the customers’ machines, so that they’ll be chargeable for guaranteeing that the enter code is safe to run.
One other instance of utilizing
exec() to run code that comes as a string is the
doctest module. This module inspects your docstrings searching for textual content that appears like a Python interactive session. If
doctest finds any interactive-session-like textual content, then it executes that textual content as Python code to verify if it really works as anticipated.
For instance, say that you’ve got the next perform for including two numbers collectively:
# calculations.py def add(a, b): """Return the sum of two numbers. Assessments: >>> add(5, 6) 11 >>> add(2.3, 5.4) 7.7 >>> add("2", 3) Traceback (most up-to-date name final): TypeError: numeric kind anticipated for "a" and "b" """ if not (isinstance(a, (int, float)) and isinstance(b, (int, float))): increase TypeError('numeric kind anticipated for "a" and "b"') return a + b # ...
On this code snippet,
add() defines a docstring with a number of assessments that verify how the perform ought to work. Be aware that the assessments characterize calls to
add() in a hypothetical interactive session utilizing legitimate and invalid argument varieties.
After getting these interactive assessments and their anticipated outputs in your docstrings, then you should utilize
doctest to run them and verify in the event that they subject the anticipated outcome.
Be aware: The doctest module offers an incredible and great tool that you should utilize for testing your code when you’re writing it.
Go to your command line and run the next command within the listing containing your
$ python -m doctest calculations.py
This command received’t subject any output if all of the take a look at works as anticipated. If not less than one take a look at fails, you then’ll get an exception mentioning the issue. To substantiate this, you’ll be able to change one of many anticipated outputs within the perform’s docstring and run the above command once more.
doctest module makes use of
exec() to execute any interactive docstring-embedded code, as you’ll be able to affirm within the module’s source code:
# doctest.py class DocTestRunner: # ... def __run(self, take a look at, compileflags, out): # ... strive: # Do not blink! That is the place the consumer's code will get run. exec( compile(instance.supply, filename, "single", compileflags, True), take a look at.globs ) self.debugger.set_continue() # ==== Instance Completed ==== exception = None besides KeyboardInterrupt: # ...
As you’ll be able to affirm on this code snippet, the consumer’s code runs in an
exec() name, which makes use of
compile() to compile the goal code. To run this code,
exec() makes use of
take a look at.globs as its
globals argument. Be aware that the remark proper earlier than the decision to
exec() jokingly states that that is the place the place the consumer’s code runs.
Once more, on this use case of
exec(), the accountability of offering safe code examples is on the customers. The
doctest maintainers aren’t chargeable for making certain that the decision to
exec() doesn’t trigger any injury.
It’s vital to notice that
doctest doesn’t stop the safety dangers related to
exec(). In different phrases,
doctest will run any Python code. For instance, somebody may modify your
add() perform to incorporate the next code within the docstring:
# calculations.py def add(a, b): """Return the sum of two numbers. Assessments: >>> import os; os.system("ls -l") 0 """ if not (isinstance(a, (int, float)) and isinstance(b, (int, float))): increase TypeError('numeric kind anticipated for "a" and "b"') return a + b
When you run
doctest on this file, then the
ls -l command will efficiently run. On this instance, the embedded command is generally innocent. Nonetheless, a malicious consumer may modify your docstring and embed one thing like
os.system("rm -rf *") or another harmful command.
Once more, you at all times need to watch out with
exec() and with instruments that use this perform, like
doctest does. Within the particular case of
doctest, so long as you understand the place your embedded take a look at code is coming from, this instrument can be fairly protected and helpful.
Utilizing Python for Configuration Information
One other state of affairs during which you should utilize
exec() to run code is when you will have a configuration file that makes use of legitimate Python syntax. Your file can outline a number of configuration parameters with particular values. Then you’ll be able to learn the file and course of its content material with
exec() to construct a dictionary object containing all of your configuration parameters and their values.
For instance, say that you’ve got the next configuration file for a textual content editor app that you simply’re engaged on:
# settings.conf font_face = "" font_size = 10 line_numbers = True tab_size = 4 auto_indent = True
This file has legitimate Python syntax, so you’ll be able to execute its content material utilizing
exec() as you’d do with an everyday
Be aware: You’ll discover a number of higher and safer methods to work with configuration information than utilizing
exec(). Within the Python commonplace library, you will have the
configparser module, which lets you course of configuration information that use the INI file format.
The under perform reads your
settings.conf file and builds a configuration dictionary:
>>> from pathlib import Path >>> def load_config(config_file): ... config_file = Path(config_file) ... code = compile(config_file.read_text(), config_file.title, "exec") ... config_dict = ... exec(code, "__builtins__": , config_dict) ... return config_dict ... >>> load_config("settings.conf") 'font_face': '', 'font_size': 10, 'line_numbers': True, 'tab_size': 4, 'auto_indent': True
load_config() perform takes the trail to a configuration file. Then it reads the goal file as textual content and passes that textual content into
exec() for execution. Throughout the
exec() run, the perform injects the configuration parameters into the
locals dictionary, which is later returned to the caller code.
Be aware: The approach on this part is most likely a protected use case of
exec(). Within the instance, you’ll have an app operating in your system, particularly a textual content editor.
When you modify the app’s configuration file to incorporate malicious code, you then’ll solely injury your self, which you almost certainly wouldn’t do. Nonetheless, there’s nonetheless a risk that you could possibly by chance embrace probably harmful code within the app’s configuration file. So, this system may find yourself being unsafe in case you’re not cautious.
After all, in case you’re coding the app your self and also you launch a configuration file with malicious code, you then’ll hurt the group at massive.
That’s it! Now you’ll be able to learn all of your configuration parameters and their corresponding values from the ensuing dictionary and use the parameters to arrange your editor venture.
You’ve discovered how you can use the built-in
exec() perform to execute Python code from a string or bytecode enter. This perform offers a fast instrument for executing dynamically generated Python code. You additionally discovered how you can decrease the safety dangers related to
exec() and when it’s okay to make use of the perform in your code.
On this tutorial, you’ve discovered how you can:
- Work with Python’s built-in
- Use Python’s
exec()to run string-based and compiled-code enter
- Assess and decrease the safety dangers related to utilizing
Moreover, you’ve coded a couple of sensible examples that helped you higher perceive when and how you can use
exec() in your Python code.