• Python Basics
  • Interview Questions
  • Python Quiz
  • Popular Packages
  • Python Projects
  • Practice Python
  • AI With Python
  • Learn Python3
  • Python Automation
  • Python Web Dev
  • DSA with Python
  • Python OOPs
  • Dictionaries
  • Python Built in Functions
  • abs() in Python
  • Python - all() function
  • Python any() function
  • ascii() in Python
  • bin() in Python
  • bool() in Python
  • Python bytes() method
  • chr() Function in Python
  • Python dict() Function
  • divmod() in Python and its application
  • Enumerate() in Python

eval in Python

  • filter() in python
  • float() in Python
  • Python String format() Method
  • Python - globals() function
  • Python hash() method
  • hex() function in Python
  • id() function in Python
  • Python 3 - input() function
  • Python int() Function
  • Python len() Function
  • Python map() function
  • Python - max() function

Python eval() function parse the expression argument and evaluate it as a Python expression and runs Python expression (code) within the program.

Python eval() Function Syntax

Syntax: eval(expression, globals=None, locals=None) Parameters: expression: String is parsed and evaluated as a Python expression globals [optional]: Dictionary to specify the available global methods and variables. locals [optional]: Another dictionary to specify the available local methods and variables. Return: Returns output of the expression.

Uses of Python eval() Function in Python

Python eval() is not much used due to security reasons, as we explored above. Still, it comes in handy in some situations like:

  • You may want to use it to allow users to enter their own “scriptlets”: small expressions (or even small functions), that can be used to customize the behavior of a complex system.
  • eval() is also sometimes used in applications needing to evaluate math expressions. This is much easier than writing an expression parser.

eval() Function in Python Example

Simple demonstration of eval() works.

Let us explore it with the help of a simple Python program. function_creator is a function that evaluates the mathematical functions created by the user. Let us analyze the code a bit:

  • The above function takes any expression in variable x as input.
  • Then the user has to enter a value of x .
  • Finally, we evaluate the Python expression using the eval() built-in function by passing the expr as an argument.

Evaluating Expressions using Python’s eval()

Evaluate mathematical expressions in python.

Evaluating a mathematical expression using the value of the variable x.

Evaluate Boolean Expressions in Python

Here the eval statement x == 4 will evaluate to False because the value of x is 5, which is not equal to 4. In the second eval statement, x is None will evaluate to True because the value of x is None, and is None checks for object identity, not value equality.

Evaluate Conditional Expressions in Python

We can also evaluate condition checking on the Python eval() function.

Vulnerability issues with Python eval() Function

Our current version of solve_expression has a few vulnerabilities. The user can easily expose hidden values in the program or call a dangerous function, as eval will execute anything passed to it.

For example, if you input like this:

You will get the output:

Also, consider the situation when you have imported the os module into your Python program. The os module provides a portable way to use operating system functionalities like reading or writing a file. A single command can delete all files in your system. Of course, in most cases (like desktop programs) the user can’t do any more than they could do by writing their own Python script, but in some applications (like web apps, kiosk computers), this could be a risk!

The solution is to restrict eval to only the functions and variables we want to make available.

Making eval() safe

Python eval function comes with the facility of explicitly passing a list of functions or variables that it can access. We need to pass it as an argument in the form of a dictionary.

Now if we try to run the above programs like:

We get the output:

Let us analyze the above code step by step:

  • First, we create a list of methods we want to allow as safe_list .
  • Next, we create a dictionary of safe methods. In this dictionary, keys are the method names and values are their local namespaces.
  • locals() is a built-in method that returns a dictionary that maps all the methods and variables in the local scope with their namespaces.

Here, we add the local variable x to the safe_dict too. No local variable other than x will get identified by the eval function.

  • eval accepts dictionaries of local as well as global variables as arguments. So, in order to ensure that none of the built-in methods is available to eval expression, we pass another dictionary along with safe_dict as well, as shown below:

So, in this way, we have made our eval function safe from any possible hacks!

Please Login to comment...

Similar reads.

  • Python-Built-in-functions

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

  • Contributors

The eval() function in Python evaluates and executes a Python expression dynamically. It takes a string as input, which should be a valid Python expression, and returns the result of the expression. This function can be used to dynamically evaluate user input or to execute Python code stored in strings .

Parameter Values

Return values.

The eval() function can return any data type that the evaluated expression represents.

How to Use eval() in Python

The eval() function parses the expression argument and evaluates it as a Python expression.

It can also evaluate expressions with variables defined in the local scope.

Caution should be taken when using eval() with user inputs as it can execute arbitrary code.

Built-In Functions

  • breakpoint()
  • bytearray()
  • classmethod()
  • enumerate()
  • frozenset()
  • isinstance()
  • issubclass()
  • memoryview()
  • staticmethod()

Learn Python practically and Get Certified .

Popular Tutorials

Popular examples, reference materials, learn python interactively, built-in functions.

  • Python abs()
  • Python any()
  • Python all()
  • Python ascii()
  • Python bin()
  • Python bool()
  • Python bytearray()
  • Python callable()
  • Python bytes()
  • Python chr()
  • Python compile()
  • Python classmethod()
  • Python complex()
  • Python delattr()
  • Python dict()
  • Python dir()
  • Python divmod()
  • Python enumerate()
  • Python staticmethod()
  • Python filter()

Python eval()

  • Python float()
  • Python format()
  • Python frozenset()
  • Python getattr()

Python globals()

Python exec()

  • Python hasattr()
  • Python help()
  • Python hex()
  • Python hash()
  • Python input()
  • Python id()
  • Python isinstance()
  • Python int()
  • Python issubclass()
  • Python iter()
  • Python list() Function

Python locals()

  • Python len()
  • Python max()
  • Python min()
  • Python map()
  • Python next()
  • Python memoryview()
  • Python object()
  • Python oct()
  • Python ord()
  • Python open()
  • Python pow()
  • Python print()
  • Python property()
  • Python range()
  • Python repr()
  • Python reversed()
  • Python round()
  • Python set()
  • Python setattr()
  • Python slice()
  • Python sorted()
  • Python str()
  • Python sum()
  • Python tuple() Function
  • Python type()
  • Python vars()
  • Python zip()

Python __import__()

  • Python super()

Python Tutorials

  • Python Programming Built-in Functions
  • Python Mathematical Functions

The eval() method parses the expression passed to this method and runs python expression (code) within the program.

eval() Syntax

The syntax of eval() is:

eval() Parameters

The eval() function takes three parameters:

  • expression - the string parsed and evaluated as a Python expression
  • globals (optional) - a dictionary
  • locals (optional)- a mapping object. Dictionary is the standard and commonly used mapping type in Python.

The use of globals and locals will be discussed later in this article.

eval() Return Value

The eval() method returns the result evaluated from the expression .

Example 1: How eval() works in Python

Here, the eval() function evaluates the expression x + 1 and print() is used to display this value.

Example 2: Practical Example to Demonstrate Use of eval()

Warnings when using eval().

Consider a situation where you are using a Unix system (macOS, Linux etc) and you have imported the os module. The os module provides a portable way to use operating system functionalities like reading or writing to a file.

If you allow users to input a value using eval(input()) , the user may issue commands to change file or even delete all the files using the command: os.system('rm -rf *') .

If you are using eval(input()) in your code, it is a good idea to check which variables and methods the user can use. You can see which variables and methods are available using dir() method .

Restricting the Use of Available Methods and Variables in eval()

More often than not, all the available methods and variables used in the expression (first parameter to eval() ) may not be needed, or even may have a security hole. You may need to restrict the use of these methods and variables for eval() . You can do so by passing optional globals and locals parameters (dictionaries) to the eval() function.

1. When both globals and locals parameters omitted

If both parameters are omitted (as in our earlier examples), the expression is executed in the current scope. You can check the available variables and methods using following code:

2. Passing globals parameter; locals parameter is omitted

The globals and locals parameters (dictionaries) are used for global and local variables respectively. If the locals dictionary is omitted, it defaults to globals dictionary. Meaning, globals will be used for both global and local variables.

Note: You can check the current global and local dictionary in Python using globals() and locals() built-in methods respectively.

Example 3: Passing empty dictionary as globals parameter

If you pass an empty dictionary as globals , only the __builtins__ are available to expression (first parameter to the eval() ).

Even though we have imported the math module in the above program, expression can't access any functions provided by the math module .

Example 4: Making Certain Methods available

Here, the expression can only use the sqrt() and the pow() methods along with __builtins__ .

It is also possible to change the name of the method available for the expression as to your wish:

In the above program, square_root() calculates the square root using sqrt() . However, trying to use sqrt() directly will raise an error.

Example 5: Restricting the Use of built-ins

You can restrict the use of __builtins__ in the expression as follows:

3. Passing both globals and locals dictionary

You can make needed functions and variables available for use by passing the locals dictionary. For example:

In this program, expression can have sqrt() method and variable a only. All other methods and variables are unavailable.

Restricting the use of eval() by passing globals and locals dictionaries will make your code secure particularly when you are using input provided by the user to the eval() method.

Note: Sometimes, eval() is not secure even with limited names. When an object and its methods are made accessible, almost anything can be done. The only secure way is by validating the user input.

Sorry about that.

Python References

Python Library

Python eval() function

Python Eval() Function

Hello, readers. In this article we will be focusing on Python eval() function .

Understanding Python eval() function

Python eval() function converts and computes the expressions passed to it.

NOTE: Use this method only for testing purposes. The eval() function does not sanitize the expressions passed to it. It can easily become a loophole into your server if malicious users execute Python code here.

The eval() function parses the python expressions and runs the code passed to it as a parameter within the python program.

  • expression : It can be any python expression(string parameter) that the user wants to compute within the python code itself.
  • globals : It is a dictionary that specifies the expressions available for the eval() function to execute.
  • locals : It describes the local methods and data variables that the eval() function can avail.

Example 1: Passing expression to add two local variables

In the above snippet of code, we have passed an expression ‘a+b’ to the eval() function in order to add two local variables: a, b.

Example 2: Python eval() function with user input

In the above example, we have accepted the input from the user and assigned the same to the variables. Further, we have passed the expression for the multiplication of those two input values.

Python eval() function with Pandas module

Python eval function can also operate with Pandas Module . The pandas.eval() function accepts the expression and executes the same within the python program.

  • expression : The python expression enclosed within the string quotes to be executed within the python program.
  • inplace : Default value=TRUE. If the python expression turns out to be an assignment expression, inplace decides to perform the operation and mutate the data frame object. If FALSE, a new dataframe gets created and is returned as a result.

Example 1: Passing an expression with inplace = TRUE

In the above example, we have created a dataframe and have passed an expression to be executed within the python script.

As the inplace is set to TRUE, the data values obtained from the expression will be stored in the same dataframe object ‘data’.

Example 2: Executing expression within python script with inplace = FALSE

In the above snippet of code, we have passed inplace = FALSE to the eval() function. Thus, the results of the python expression will be stored in a new dataframe object ‘data1’.

Security issues with eval() function

  • Python eval() function is more prone to security threats.
  • The sensitive user input data can easily be made available through Python eval() function.
  • Thus, the parameters globals and locals is provided to restrict the access to the data directly.
  • Python eval() function is used to execute python expressions within a python script directly.
  • The eval() function can also be used in a similar fashion with the Pandas module .
  • Python eval() function is more prone to security threats . Thus, it is necessary to check the information being passed to the eval() function before it’s execution.

Therefore, in this article, we have understood the working and the vulnerabilities of Python eval() function.

  • Python eval() function — JournalDev

How to Assign the Result of eval() to a Python Variable?

💬 Question : Say you have an expression you want to execute using the eval() function. How to store the result of the expression in a Python variable my_result ?

Before I show you the solution, let’s quickly recap the eval() function:

Recap Python eval()

Python eval(s) parses the string argument s into a Python expression, runs it, and returns the result of the expression.

Python eval() -- How to Dynamically Evaluate a Code Expression in Python

Related Tutorial : Python’s eval() built-in function

Without further ado, let’s learn how you can store the result of the eval() function in a Python variable:

Method 1: Simple Assignment

The most straightforward way to store the result of an eval() expression in a Python variable is to as s ign the whole return value to the variable. For example, the expression my_result = eval('2+2') stores the result 4 in the variable my_result .

Here’s a minimal example:

This simple approach may not always work, for example, if you have a print() statement in the expression.

Read on to learn how to fix this issue next and learn something new!

Method 2: Redirect Standard Output

This method assumes you have a print() statement within the expression passed into the eval() function such as shown in the following three examples:

  • eval('print(2+2)')
  • eval('print([1, 2, 3, 4] + [5, 6])')
  • eval('print(2+2*0)')

To get the output and store it in a variable my_result , you need to temporarily redirect the standard output to the variable.

The following code shows you how to accomplish exactly this:

If you need some assistance understanding this whole idea of redirecting the standard output, have a look at our in-depth guide on the Finxter blog.

👀 Related Article: 7 Easy Steps to Redirect Your Standard Output to a Variable (Python)

Note that this approach even works if you don’t have a print() statement in the original eval() expression because you can always artificially add the print() statement around the original expression like so:

  • eval('2+2') becomes eval('print(2+2)')
  • eval('2+2*0') becomes eval('print(2+2*0)')
  • eval('[1, 2, 3] + [4, 5]') becomes eval('print([1, 2, 3] + [4, 5])')

Even if it’s a bit clunky, after applying this short trick, you can redirect the standard output and store the result of any eval() expression in a variable.

Method 3: Use exec()

Using only Python’s eval() function, you cannot define variables inside the expression to be evaluated. However, you can define a variable inside the exec() function that will then be added to the global namespace. Thus, you can access the defined variable in your code after termination of the exec() expression!

Here’s how that works in a minimal example:

Variable my_result is only defined in the string expression passed into exec() , but you can use it in the code like it was part of the original source code.

Recap exec() vs eval()

Python’s exec() function takes a Python program, as a string or executable object, and runs it. The eval() function evaluates an expression and returns the result of this expression. There are two main differences:

  • exec() can execute all Python source code, whereas eval() can only evaluate expressions.
  • exec() always returns None , whereas eval() returns the result of the evaluated expression.
  • exec() can import modules, whereas eval() cannot.

You can learn more about the exec() function here:

  • Related Article: Python exec() — A Hacker’s Guide to A Dangerous Function

Python exec() — A Hacker’s Guide to A Dangerous Function

Where to Go From Here?

Enough theory. Let’s get some practice!

Coders get paid six figures and more because they can solve problems more effectively using machine intelligence and automation.

To become more successful in coding, solve more real problems for real people. That’s how you polish the skills you really need in practice. After all, what’s the use of learning theory that nobody ever needs?

You build high-value coding skills by working on practical coding projects!

Do you want to stop learning with toy projects and focus on practical code projects that earn you money and solve real problems for people?

🚀 If your answer is YES! , consider becoming a Python freelance developer ! It’s the best way of approaching the task of improving your Python skills—even if you are a complete beginner.

If you just want to learn about the freelancing opportunity, feel free to watch my free webinar “How to Build Your High-Income Skill Python” and learn how I grew my coding business online and how you can, too—from the comfort of your own home.

Join the free webinar now!

While working as a researcher in distributed systems, Dr. Christian Mayer found his love for teaching computer science students.

To help students reach higher levels of Python success, he founded the programming education website Finxter.com that has taught exponential skills to millions of coders worldwide. He’s the author of the best-selling programming books Python One-Liners (NoStarch 2020), The Art of Clean Code (NoStarch 2022), and The Book of Dash (NoStarch 2022). Chris also coauthored the Coffee Break Python series of self-published books. He’s a computer science enthusiast, freelancer , and owner of one of the top 10 largest Python blogs worldwide.

His passions are writing, reading, and coding. But his greatest passion is to serve aspiring coders through Finxter and help them to boost their skills. You can join his free email academy here.

PrepBytes Blog

ONE-STOP RESOURCE FOR EVERYTHING RELATED TO CODING

Sign in to your account

Forgot your password?

Login via OTP

We will send you an one time password on your mobile number

An OTP has been sent to your mobile number please verify it below

Register with PrepBytes

Python eval function.

' src=

Last Updated on October 30, 2023 by Ankit Kochar

python assignment in eval

The eval function in Python is a powerful yet potentially risky feature that allows you to dynamically execute Python code from a string. It can take a string containing a Python expression or statement, evaluate it, and return the result. This capability makes eval() a versatile tool for various use cases, such as dynamic configuration, mathematical calculations, and creating mini-interpreters within your Python programs.

In this article, we’ll explore the concept of the eval function in Python in depth. We’ll discuss how to use eval(), its advantages, and common scenarios where it can be beneficial. Additionally, we’ll address the potential security risks associated with eval() and best practices for using it safely in your Python applications.

What is Eval Function in Python?

The eval in Python is a built-in function that evaluates a string as a Python expression and returns the result. It takes a single parameter which is a string containing a Python expression or statement to be evaluated. The expression can include any valid Python code, such as arithmetic operations, function calls, and control structures.

For example, if you have a string "3 + 5" and you pass it to the eval() function, it will evaluate the expression and return the result 8. Similarly, if you have a string "print(‘Hello, World!’)" and you pass it to eval(), it will execute the print() statement and print "Hello, World!" to the console.

It’s important to note that the eval() function can execute arbitrary code and therefore can be a security risk if used improperly. It should only be used with trusted input and should never be used to evaluate untrusted or user-generated input.

Here’s a simple example of using the Python eval function:

Explanation: In this example, we define a string expression that contains a Python expression. We then pass this string to the eval() function, which evaluates the expression and returns the result (14). Finally, we print the result using the print() function.

Point to Note: eval() can also be used to execute more complex expressions, such as function calls or control structures. However, as mentioned before, it should only be used with trusted input, not untrusted user-generated input, to avoid potential security risks.

Syntax of Eval Function in Python

The syntax of the eval() function in Python is

The eval() function takes one required argument, which is an expression, a string containing a valid Python expression or statement to be evaluated. In addition to the required argument, eval() can also take two optional arguments.

Parameters of Eval Function in Python

The Python eval function takes up to three parameters:

expression: This is the required parameter and represents the expression to be evaluated. It can be any valid Python expression or statement, including arithmetic expressions, function calls, or even more complex expressions involving control structures and loops.

globals (optional): This is an optional parameter that represents a dictionary of global variables. The values of these variables are used during the evaluation of the expression. If this parameter is not provided, the eval() function uses the global namespace of the calling module.

locals (optional): This is an optional parameter that represents a dictionary of local variables. The values of these variables are used during the evaluation of the expression. If this parameter is not provided, the eval() function uses the local namespace of the calling function or module.

Here’s an example that demonstrates the use of all three parameters:

Explanation: In this example, we define a dictionary global_vars containing global variables x and y. We then define a function my_function() that has a local variable z, and we use the eval() function to evaluate an expression "x + y + z" using both the global and local variables. Finally, we print the result of the expression.

Return Value of Eval Function in Python

The Python eval function returns the result of evaluating the expression that is passed to it as a string. The type of return value depends on the expression that is evaluated.

If the expression is a single Python expression that evaluates to a value, the return value of eval() will be that value. For example, if we evaluate the expression "2 + 3", the return value will be 5, which is the result of the expression.

If the expression contains multiple statements, eval() will return None. For example, if we evaluate the expression "x = 5; y = 10;", eval() will set the values of x and y but return None.

Practical Examples To Demonstrate Use Of Eval in Python

Here are some practical examples that demonstrate the use of the eval() function in Python:

Example 1: Evaluating Simple Arithmetic Expressions Below is code implementation and explanation of the example

Explanation: In this example, we define a string expression containing a simple arithmetic expression. We then use the eval() function to evaluate the expression and assign the result to the variable result. Finally, we print the value of result, which is 13.

Example 2: Evaluating Functions with Arguments The eval() function in Python can be used to evaluate functions with arguments, just like calling a regular function. Here’s an example that demonstrates how this can be done:

Explanation: In this example, we define a string expression that contains a call to a custom my_function() function with two string arguments. We define the function before evaluating the expression using eval(). The eval() function can access and use the function in the expression, as long as it’s defined in the current scope. The result of the evaluation is stored in the variable result and printed to the console, which should output the concatenated string "Hello, prepBytes!".

Example 3: Evaluating Boolean Expressions The eval() function in Python can be used to evaluate boolean expressions, just like any other Python expression. Here’s an example that demonstrates how this can be done:

Explanation: In this example, we define a string expression that contains a boolean expression to evaluate. The expression checks if the variable x is greater than 0 and the variable y is less than 10. We then define two variables x and y with values 5 and 15, respectively.

We use the eval() function to evaluate the expression by passing it as a string argument. Since x and y are defined in the current scope, eval() can access and use them in the expression. The result of the evaluation is stored in the variable result and printed to the console, which should output False.

Example 4: Evaluating Expressions using Global and Local Variables When using the eval() function in Python, it’s possible to evaluate expressions that use both global and local variables. Here’s an example that demonstrates how this can be done:

Explanation: In this example, we define a global variable x and a function evaluate_expression() that accepts an expression as an argument. Within the function, we define a local variable y and use eval() to evaluate the expression passed in as an argument.

To ensure that eval() can access the global variable x, we pass a dictionary with a single entry mapping the name ‘x’ to the value of x as the second argument to eval(). Similarly, to ensure that eval() can access the local variable y, we pass a dictionary with a single entry mapping the name ‘y’ to the value of y as the third argument to eval().

By using these dictionaries to specify the global and local variables available to eval(), we can evaluate expressions that reference both global and local variables.

Issues with Python Eval Function

The eval() function in Python can be a powerful tool for dynamically executing Python code, but it also poses a number of potential issues and risks. Here are some of the main issues to be aware of when using eval():

  • Security vulnerabilities: As I mentioned earlier, the eval() function can execute any arbitrary code that is passed to it as a string, which can lead to security vulnerabilities such as injection attacks if the input is not properly sanitized or validated. This can potentially allow an attacker to execute malicious code on the system.
  • Performance overhead: The eval() function can be slower than executing equivalent code directly because it has to parse and compile the input string at runtime. This can be a concern in performance-critical applications or when evaluating large or complex expressions.
  • Debugging difficulties: Using eval() can make debugging more difficult because errors can occur in the evaluated code and not in the calling code. This can make it harder to diagnose and fix issues.
  • Maintainability challenges: Dynamically generated code can be more difficult to maintain than code that is written directly. This can be a concern if the dynamically generated code is complex or if it changes frequently.

To address these issues, it’s important to use eval() judiciously and to follow best practices for secure coding and input validation. It’s also a good idea to consider alternative approaches such as using pre-compiled code or more limited parsing frameworks like ast.literal_eval() where possible. By taking these steps, you can minimize the risks associated with using eval() and ensure that your code is as secure, performant, and maintainable as possible.

Uses Of Python Eval Function

The eval() function in Python can be used in a variety of situations where it’s necessary to dynamically evaluate a Python expression or execute code at runtime. Here are some common use cases:

  • Mathematical expressions: eval() can be used to evaluate mathematical expressions entered by the user. For example, you could use eval() to calculate the result of a user-entered equation.
  • Dynamic configuration: eval() can be used to dynamically configure Python objects or modules at runtime. For example, you could use eval() to read a configuration file and dynamically set the properties of a Python object based on the contents of the file.
  • Template rendering: eval() can be used to dynamically generate HTML or other text-based formats based on a template or other input. For example, you could use eval() to render a dynamically generated web page or email message.
  • Custom scripting: eval() can be used to provide a custom scripting environment within a Python application. For example, you could use eval() to allow users to write and execute Python scripts within your application.
  • Code generation: eval() can be used to dynamically generate Python code at runtime. For example, you could use eval() to generate code based on a set of user-defined rules or parameters.

The eval function in Python is a powerful tool for dynamically executing Python code from strings, offering versatility and convenience for certain use cases. It allows you to evaluate expressions and statements, making it useful for tasks like dynamic configuration and mathematical calculations.

In this article, we’ve delved into the world of eval in Python, discussing its usage, advantages, and potential security concerns. We’ve emphasized the importance of using eval() judiciously and provided best practices to mitigate risks when employing it in your code. As you continue to develop Python applications, remember that while eval() can be a valuable tool, it should be used sparingly and cautiously, especially when dealing with untrusted input. By mastering the art of eval() and following security best practices, you can harness its power effectively in your Python projects.

FAQs Related to Eval in Python

Here are some frequently asked questions on Python eval Function

1. Can I use eval() for complex operations, such as file I/O or network requests? It’s generally not recommended to use eval() for complex operations like file I/O or network requests. These operations should be handled using dedicated Python libraries and modules, as they can introduce security risks and are not its intended use.

2. What are some common use cases for the eval() function? Common use cases for eval() include dynamic configuration, mathematical calculations, parsing expressions from user input, and creating mini-interpreters or domain-specific languages.

3. What are the potential security risks associated with using eval()? Using eval() with untrusted or unsanitized input can lead to security vulnerabilities, as it allows execution of arbitrary code. This can lead to code injection and other malicious activities.

4. How can I use eval() safely in my Python code? To use eval() safely, avoid executing untrusted code, sanitize input, and validate expressions. Consider using alternatives like ast.literal_eval() when dealing with literals, and restrict eval() to known and safe inputs.

5. Are there alternatives to eval() in Python? Yes, Python provides alternatives like ast.literal_eval() for safely evaluating literals and exec() for executing dynamic code in a controlled environment. These alternatives may be more secure depending on your use case.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Save my name, email, and website in this browser for the next time I comment.

  • Linked List
  • Segment Tree
  • Backtracking
  • Dynamic Programming
  • Greedy Algorithm
  • Operating System
  • Company Placement
  • Interview Tips
  • General Interview Questions
  • Data Structure
  • Other Topics
  • Computational Geometry
  • Game Theory

Related Post

Python list functions & python list methods, python interview questions, namespaces and scope in python, what is the difference between append and extend in python, python program to check for the perfect square, python program to find the sum of first n natural numbers.

Python Tutorial

File handling, python modules, python numpy, python pandas, python matplotlib, python scipy, machine learning, python mysql, python mongodb, python reference, module reference, python how to, python examples, python eval() function.

❮ Built-in Functions

Evaluate the expression 'print(55)':

Definition and Usage

The eval() function evaluates the specified expression, if the expression is a legal Python statement, it will be executed.

Parameter Values

Get Certified

COLOR PICKER

colorpicker

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: [email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail: [email protected]

Top Tutorials

Top references, top examples, get certified.

Python Enhancement Proposals

  • Python »
  • PEP Index »

PEP 572 – Assignment Expressions

The importance of real code, exceptional cases, scope of the target, relative precedence of :=, change to evaluation order, differences between assignment expressions and assignment statements, specification changes during implementation, _pydecimal.py, datetime.py, sysconfig.py, simplifying list comprehensions, capturing condition values, changing the scope rules for comprehensions, alternative spellings, special-casing conditional statements, special-casing comprehensions, lowering operator precedence, allowing commas to the right, always requiring parentheses, why not just turn existing assignment into an expression, with assignment expressions, why bother with assignment statements, why not use a sublocal scope and prevent namespace pollution, style guide recommendations, acknowledgements, a numeric example, appendix b: rough code translations for comprehensions, appendix c: no changes to scope semantics.

This is a proposal for creating a way to assign to variables within an expression using the notation NAME := expr .

As part of this change, there is also an update to dictionary comprehension evaluation order to ensure key expressions are executed before value expressions (allowing the key to be bound to a name and then re-used as part of calculating the corresponding value).

During discussion of this PEP, the operator became informally known as “the walrus operator”. The construct’s formal name is “Assignment Expressions” (as per the PEP title), but they may also be referred to as “Named Expressions” (e.g. the CPython reference implementation uses that name internally).

Naming the result of an expression is an important part of programming, allowing a descriptive name to be used in place of a longer expression, and permitting reuse. Currently, this feature is available only in statement form, making it unavailable in list comprehensions and other expression contexts.

Additionally, naming sub-parts of a large expression can assist an interactive debugger, providing useful display hooks and partial results. Without a way to capture sub-expressions inline, this would require refactoring of the original code; with assignment expressions, this merely requires the insertion of a few name := markers. Removing the need to refactor reduces the likelihood that the code be inadvertently changed as part of debugging (a common cause of Heisenbugs), and is easier to dictate to another programmer.

During the development of this PEP many people (supporters and critics both) have had a tendency to focus on toy examples on the one hand, and on overly complex examples on the other.

The danger of toy examples is twofold: they are often too abstract to make anyone go “ooh, that’s compelling”, and they are easily refuted with “I would never write it that way anyway”.

The danger of overly complex examples is that they provide a convenient strawman for critics of the proposal to shoot down (“that’s obfuscated”).

Yet there is some use for both extremely simple and extremely complex examples: they are helpful to clarify the intended semantics. Therefore, there will be some of each below.

However, in order to be compelling , examples should be rooted in real code, i.e. code that was written without any thought of this PEP, as part of a useful application, however large or small. Tim Peters has been extremely helpful by going over his own personal code repository and picking examples of code he had written that (in his view) would have been clearer if rewritten with (sparing) use of assignment expressions. His conclusion: the current proposal would have allowed a modest but clear improvement in quite a few bits of code.

Another use of real code is to observe indirectly how much value programmers place on compactness. Guido van Rossum searched through a Dropbox code base and discovered some evidence that programmers value writing fewer lines over shorter lines.

Case in point: Guido found several examples where a programmer repeated a subexpression, slowing down the program, in order to save one line of code, e.g. instead of writing:

they would write:

Another example illustrates that programmers sometimes do more work to save an extra level of indentation:

This code tries to match pattern2 even if pattern1 has a match (in which case the match on pattern2 is never used). The more efficient rewrite would have been:

Syntax and semantics

In most contexts where arbitrary Python expressions can be used, a named expression can appear. This is of the form NAME := expr where expr is any valid Python expression other than an unparenthesized tuple, and NAME is an identifier.

The value of such a named expression is the same as the incorporated expression, with the additional side-effect that the target is assigned that value:

There are a few places where assignment expressions are not allowed, in order to avoid ambiguities or user confusion:

This rule is included to simplify the choice for the user between an assignment statement and an assignment expression – there is no syntactic position where both are valid.

Again, this rule is included to avoid two visually similar ways of saying the same thing.

This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

This rule is included to discourage side effects in a position whose exact semantics are already confusing to many users (cf. the common style recommendation against mutable default values), and also to echo the similar prohibition in calls (the previous bullet).

The reasoning here is similar to the two previous cases; this ungrouped assortment of symbols and operators composed of : and = is hard to read correctly.

This allows lambda to always bind less tightly than := ; having a name binding at the top level inside a lambda function is unlikely to be of value, as there is no way to make use of it. In cases where the name will be used more than once, the expression is likely to need parenthesizing anyway, so this prohibition will rarely affect code.

This shows that what looks like an assignment operator in an f-string is not always an assignment operator. The f-string parser uses : to indicate formatting options. To preserve backwards compatibility, assignment operator usage inside of f-strings must be parenthesized. As noted above, this usage of the assignment operator is not recommended.

An assignment expression does not introduce a new scope. In most cases the scope in which the target will be bound is self-explanatory: it is the current scope. If this scope contains a nonlocal or global declaration for the target, the assignment expression honors that. A lambda (being an explicit, if anonymous, function definition) counts as a scope for this purpose.

There is one special case: an assignment expression occurring in a list, set or dict comprehension or in a generator expression (below collectively referred to as “comprehensions”) binds the target in the containing scope, honoring a nonlocal or global declaration for the target in that scope, if one exists. For the purpose of this rule the containing scope of a nested comprehension is the scope that contains the outermost comprehension. A lambda counts as a containing scope.

The motivation for this special case is twofold. First, it allows us to conveniently capture a “witness” for an any() expression, or a counterexample for all() , for example:

Second, it allows a compact way of updating mutable state from a comprehension, for example:

However, an assignment expression target name cannot be the same as a for -target name appearing in any comprehension containing the assignment expression. The latter names are local to the comprehension in which they appear, so it would be contradictory for a contained use of the same name to refer to the scope containing the outermost comprehension instead.

For example, [i := i+1 for i in range(5)] is invalid: the for i part establishes that i is local to the comprehension, but the i := part insists that i is not local to the comprehension. The same reason makes these examples invalid too:

While it’s technically possible to assign consistent semantics to these cases, it’s difficult to determine whether those semantics actually make sense in the absence of real use cases. Accordingly, the reference implementation [1] will ensure that such cases raise SyntaxError , rather than executing with implementation defined behaviour.

This restriction applies even if the assignment expression is never executed:

For the comprehension body (the part before the first “for” keyword) and the filter expression (the part after “if” and before any nested “for”), this restriction applies solely to target names that are also used as iteration variables in the comprehension. Lambda expressions appearing in these positions introduce a new explicit function scope, and hence may use assignment expressions with no additional restrictions.

Due to design constraints in the reference implementation (the symbol table analyser cannot easily detect when names are re-used between the leftmost comprehension iterable expression and the rest of the comprehension), named expressions are disallowed entirely as part of comprehension iterable expressions (the part after each “in”, and before any subsequent “if” or “for” keyword):

A further exception applies when an assignment expression occurs in a comprehension whose containing scope is a class scope. If the rules above were to result in the target being assigned in that class’s scope, the assignment expression is expressly invalid. This case also raises SyntaxError :

(The reason for the latter exception is the implicit function scope created for comprehensions – there is currently no runtime mechanism for a function to refer to a variable in the containing class scope, and we do not want to add such a mechanism. If this issue ever gets resolved this special case may be removed from the specification of assignment expressions. Note that the problem already exists for using a variable defined in the class scope from a comprehension.)

See Appendix B for some examples of how the rules for targets in comprehensions translate to equivalent code.

The := operator groups more tightly than a comma in all syntactic positions where it is legal, but less tightly than all other operators, including or , and , not , and conditional expressions ( A if C else B ). As follows from section “Exceptional cases” above, it is never allowed at the same level as = . In case a different grouping is desired, parentheses should be used.

The := operator may be used directly in a positional function call argument; however it is invalid directly in a keyword argument.

Some examples to clarify what’s technically valid or invalid:

Most of the “valid” examples above are not recommended, since human readers of Python source code who are quickly glancing at some code may miss the distinction. But simple cases are not objectionable:

This PEP recommends always putting spaces around := , similar to PEP 8 ’s recommendation for = when used for assignment, whereas the latter disallows spaces around = used for keyword arguments.)

In order to have precisely defined semantics, the proposal requires evaluation order to be well-defined. This is technically not a new requirement, as function calls may already have side effects. Python already has a rule that subexpressions are generally evaluated from left to right. However, assignment expressions make these side effects more visible, and we propose a single change to the current evaluation order:

  • In a dict comprehension {X: Y for ...} , Y is currently evaluated before X . We propose to change this so that X is evaluated before Y . (In a dict display like {X: Y} this is already the case, and also in dict((X, Y) for ...) which should clearly be equivalent to the dict comprehension.)

Most importantly, since := is an expression, it can be used in contexts where statements are illegal, including lambda functions and comprehensions.

Conversely, assignment expressions don’t support the advanced features found in assignment statements:

  • Multiple targets are not directly supported: x = y = z = 0 # Equivalent: (z := (y := (x := 0)))
  • Single assignment targets other than a single NAME are not supported: # No equivalent a [ i ] = x self . rest = []
  • Priority around commas is different: x = 1 , 2 # Sets x to (1, 2) ( x := 1 , 2 ) # Sets x to 1
  • Iterable packing and unpacking (both regular or extended forms) are not supported: # Equivalent needs extra parentheses loc = x , y # Use (loc := (x, y)) info = name , phone , * rest # Use (info := (name, phone, *rest)) # No equivalent px , py , pz = position name , phone , email , * other_info = contact
  • Inline type annotations are not supported: # Closest equivalent is "p: Optional[int]" as a separate declaration p : Optional [ int ] = None
  • Augmented assignment is not supported: total += tax # Equivalent: (total := total + tax)

The following changes have been made based on implementation experience and additional review after the PEP was first accepted and before Python 3.8 was released:

  • for consistency with other similar exceptions, and to avoid locking in an exception name that is not necessarily going to improve clarity for end users, the originally proposed TargetScopeError subclass of SyntaxError was dropped in favour of just raising SyntaxError directly. [3]
  • due to a limitation in CPython’s symbol table analysis process, the reference implementation raises SyntaxError for all uses of named expressions inside comprehension iterable expressions, rather than only raising them when the named expression target conflicts with one of the iteration variables in the comprehension. This could be revisited given sufficiently compelling examples, but the extra complexity needed to implement the more selective restriction doesn’t seem worthwhile for purely hypothetical use cases.

Examples from the Python standard library

env_base is only used on these lines, putting its assignment on the if moves it as the “header” of the block.

  • Current: env_base = os . environ . get ( "PYTHONUSERBASE" , None ) if env_base : return env_base
  • Improved: if env_base := os . environ . get ( "PYTHONUSERBASE" , None ): return env_base

Avoid nested if and remove one indentation level.

  • Current: if self . _is_special : ans = self . _check_nans ( context = context ) if ans : return ans
  • Improved: if self . _is_special and ( ans := self . _check_nans ( context = context )): return ans

Code looks more regular and avoid multiple nested if. (See Appendix A for the origin of this example.)

  • Current: reductor = dispatch_table . get ( cls ) if reductor : rv = reductor ( x ) else : reductor = getattr ( x , "__reduce_ex__" , None ) if reductor : rv = reductor ( 4 ) else : reductor = getattr ( x , "__reduce__" , None ) if reductor : rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )
  • Improved: if reductor := dispatch_table . get ( cls ): rv = reductor ( x ) elif reductor := getattr ( x , "__reduce_ex__" , None ): rv = reductor ( 4 ) elif reductor := getattr ( x , "__reduce__" , None ): rv = reductor () else : raise Error ( "un(deep)copyable object of type %s " % cls )

tz is only used for s += tz , moving its assignment inside the if helps to show its scope.

  • Current: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) tz = self . _tzstr () if tz : s += tz return s
  • Improved: s = _format_time ( self . _hour , self . _minute , self . _second , self . _microsecond , timespec ) if tz := self . _tzstr (): s += tz return s

Calling fp.readline() in the while condition and calling .match() on the if lines make the code more compact without making it harder to understand.

  • Current: while True : line = fp . readline () if not line : break m = define_rx . match ( line ) if m : n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v else : m = undef_rx . match ( line ) if m : vars [ m . group ( 1 )] = 0
  • Improved: while line := fp . readline (): if m := define_rx . match ( line ): n , v = m . group ( 1 , 2 ) try : v = int ( v ) except ValueError : pass vars [ n ] = v elif m := undef_rx . match ( line ): vars [ m . group ( 1 )] = 0

A list comprehension can map and filter efficiently by capturing the condition:

Similarly, a subexpression can be reused within the main expression, by giving it a name on first use:

Note that in both cases the variable y is bound in the containing scope (i.e. at the same level as results or stuff ).

Assignment expressions can be used to good effect in the header of an if or while statement:

Particularly with the while loop, this can remove the need to have an infinite loop, an assignment, and a condition. It also creates a smooth parallel between a loop which simply uses a function call as its condition, and one which uses that as its condition but also uses the actual value.

An example from the low-level UNIX world:

Rejected alternative proposals

Proposals broadly similar to this one have come up frequently on python-ideas. Below are a number of alternative syntaxes, some of them specific to comprehensions, which have been rejected in favour of the one given above.

A previous version of this PEP proposed subtle changes to the scope rules for comprehensions, to make them more usable in class scope and to unify the scope of the “outermost iterable” and the rest of the comprehension. However, this part of the proposal would have caused backwards incompatibilities, and has been withdrawn so the PEP can focus on assignment expressions.

Broadly the same semantics as the current proposal, but spelled differently.

Since EXPR as NAME already has meaning in import , except and with statements (with different semantics), this would create unnecessary confusion or require special-casing (e.g. to forbid assignment within the headers of these statements).

(Note that with EXPR as VAR does not simply assign the value of EXPR to VAR – it calls EXPR.__enter__() and assigns the result of that to VAR .)

Additional reasons to prefer := over this spelling include:

  • In if f(x) as y the assignment target doesn’t jump out at you – it just reads like if f x blah blah and it is too similar visually to if f(x) and y .
  • import foo as bar
  • except Exc as var
  • with ctxmgr() as var

To the contrary, the assignment expression does not belong to the if or while that starts the line, and we intentionally allow assignment expressions in other contexts as well.

  • NAME = EXPR
  • if NAME := EXPR

reinforces the visual recognition of assignment expressions.

This syntax is inspired by languages such as R and Haskell, and some programmable calculators. (Note that a left-facing arrow y <- f(x) is not possible in Python, as it would be interpreted as less-than and unary minus.) This syntax has a slight advantage over ‘as’ in that it does not conflict with with , except and import , but otherwise is equivalent. But it is entirely unrelated to Python’s other use of -> (function return type annotations), and compared to := (which dates back to Algol-58) it has a much weaker tradition.

This has the advantage that leaked usage can be readily detected, removing some forms of syntactic ambiguity. However, this would be the only place in Python where a variable’s scope is encoded into its name, making refactoring harder.

Execution order is inverted (the indented body is performed first, followed by the “header”). This requires a new keyword, unless an existing keyword is repurposed (most likely with: ). See PEP 3150 for prior discussion on this subject (with the proposed keyword being given: ).

This syntax has fewer conflicts than as does (conflicting only with the raise Exc from Exc notation), but is otherwise comparable to it. Instead of paralleling with expr as target: (which can be useful but can also be confusing), this has no parallels, but is evocative.

One of the most popular use-cases is if and while statements. Instead of a more general solution, this proposal enhances the syntax of these two statements to add a means of capturing the compared value:

This works beautifully if and ONLY if the desired condition is based on the truthiness of the captured value. It is thus effective for specific use-cases (regex matches, socket reads that return '' when done), and completely useless in more complicated cases (e.g. where the condition is f(x) < 0 and you want to capture the value of f(x) ). It also has no benefit to list comprehensions.

Advantages: No syntactic ambiguities. Disadvantages: Answers only a fraction of possible use-cases, even in if / while statements.

Another common use-case is comprehensions (list/set/dict, and genexps). As above, proposals have been made for comprehension-specific solutions.

This brings the subexpression to a location in between the ‘for’ loop and the expression. It introduces an additional language keyword, which creates conflicts. Of the three, where reads the most cleanly, but also has the greatest potential for conflict (e.g. SQLAlchemy and numpy have where methods, as does tkinter.dnd.Icon in the standard library).

As above, but reusing the with keyword. Doesn’t read too badly, and needs no additional language keyword. Is restricted to comprehensions, though, and cannot as easily be transformed into “longhand” for-loop syntax. Has the C problem that an equals sign in an expression can now create a name binding, rather than performing a comparison. Would raise the question of why “with NAME = EXPR:” cannot be used as a statement on its own.

As per option 2, but using as rather than an equals sign. Aligns syntactically with other uses of as for name binding, but a simple transformation to for-loop longhand would create drastically different semantics; the meaning of with inside a comprehension would be completely different from the meaning as a stand-alone statement, while retaining identical syntax.

Regardless of the spelling chosen, this introduces a stark difference between comprehensions and the equivalent unrolled long-hand form of the loop. It is no longer possible to unwrap the loop into statement form without reworking any name bindings. The only keyword that can be repurposed to this task is with , thus giving it sneakily different semantics in a comprehension than in a statement; alternatively, a new keyword is needed, with all the costs therein.

There are two logical precedences for the := operator. Either it should bind as loosely as possible, as does statement-assignment; or it should bind more tightly than comparison operators. Placing its precedence between the comparison and arithmetic operators (to be precise: just lower than bitwise OR) allows most uses inside while and if conditions to be spelled without parentheses, as it is most likely that you wish to capture the value of something, then perform a comparison on it:

Once find() returns -1, the loop terminates. If := binds as loosely as = does, this would capture the result of the comparison (generally either True or False ), which is less useful.

While this behaviour would be convenient in many situations, it is also harder to explain than “the := operator behaves just like the assignment statement”, and as such, the precedence for := has been made as close as possible to that of = (with the exception that it binds tighter than comma).

Some critics have claimed that the assignment expressions should allow unparenthesized tuples on the right, so that these two would be equivalent:

(With the current version of the proposal, the latter would be equivalent to ((point := x), y) .)

However, adopting this stance would logically lead to the conclusion that when used in a function call, assignment expressions also bind less tight than comma, so we’d have the following confusing equivalence:

The less confusing option is to make := bind more tightly than comma.

It’s been proposed to just always require parentheses around an assignment expression. This would resolve many ambiguities, and indeed parentheses will frequently be needed to extract the desired subexpression. But in the following cases the extra parentheses feel redundant:

Frequently Raised Objections

C and its derivatives define the = operator as an expression, rather than a statement as is Python’s way. This allows assignments in more contexts, including contexts where comparisons are more common. The syntactic similarity between if (x == y) and if (x = y) belies their drastically different semantics. Thus this proposal uses := to clarify the distinction.

The two forms have different flexibilities. The := operator can be used inside a larger expression; the = statement can be augmented to += and its friends, can be chained, and can assign to attributes and subscripts.

Previous revisions of this proposal involved sublocal scope (restricted to a single statement), preventing name leakage and namespace pollution. While a definite advantage in a number of situations, this increases complexity in many others, and the costs are not justified by the benefits. In the interests of language simplicity, the name bindings created here are exactly equivalent to any other name bindings, including that usage at class or module scope will create externally-visible names. This is no different from for loops or other constructs, and can be solved the same way: del the name once it is no longer needed, or prefix it with an underscore.

(The author wishes to thank Guido van Rossum and Christoph Groth for their suggestions to move the proposal in this direction. [2] )

As expression assignments can sometimes be used equivalently to statement assignments, the question of which should be preferred will arise. For the benefit of style guides such as PEP 8 , two recommendations are suggested.

  • If either assignment statements or assignment expressions can be used, prefer statements; they are a clear declaration of intent.
  • If using assignment expressions would lead to ambiguity about execution order, restructure it to use statements instead.

The authors wish to thank Alyssa Coghlan and Steven D’Aprano for their considerable contributions to this proposal, and members of the core-mentorship mailing list for assistance with implementation.

Appendix A: Tim Peters’s findings

Here’s a brief essay Tim Peters wrote on the topic.

I dislike “busy” lines of code, and also dislike putting conceptually unrelated logic on a single line. So, for example, instead of:

instead. So I suspected I’d find few places I’d want to use assignment expressions. I didn’t even consider them for lines already stretching halfway across the screen. In other cases, “unrelated” ruled:

is a vast improvement over the briefer:

The original two statements are doing entirely different conceptual things, and slamming them together is conceptually insane.

In other cases, combining related logic made it harder to understand, such as rewriting:

as the briefer:

The while test there is too subtle, crucially relying on strict left-to-right evaluation in a non-short-circuiting or method-chaining context. My brain isn’t wired that way.

But cases like that were rare. Name binding is very frequent, and “sparse is better than dense” does not mean “almost empty is better than sparse”. For example, I have many functions that return None or 0 to communicate “I have nothing useful to return in this case, but since that’s expected often I’m not going to annoy you with an exception”. This is essentially the same as regular expression search functions returning None when there is no match. So there was lots of code of the form:

I find that clearer, and certainly a bit less typing and pattern-matching reading, as:

It’s also nice to trade away a small amount of horizontal whitespace to get another _line_ of surrounding code on screen. I didn’t give much weight to this at first, but it was so very frequent it added up, and I soon enough became annoyed that I couldn’t actually run the briefer code. That surprised me!

There are other cases where assignment expressions really shine. Rather than pick another from my code, Kirill Balunov gave a lovely example from the standard library’s copy() function in copy.py :

The ever-increasing indentation is semantically misleading: the logic is conceptually flat, “the first test that succeeds wins”:

Using easy assignment expressions allows the visual structure of the code to emphasize the conceptual flatness of the logic; ever-increasing indentation obscured it.

A smaller example from my code delighted me, both allowing to put inherently related logic in a single line, and allowing to remove an annoying “artificial” indentation level:

That if is about as long as I want my lines to get, but remains easy to follow.

So, in all, in most lines binding a name, I wouldn’t use assignment expressions, but because that construct is so very frequent, that leaves many places I would. In most of the latter, I found a small win that adds up due to how often it occurs, and in the rest I found a moderate to major win. I’d certainly use it more often than ternary if , but significantly less often than augmented assignment.

I have another example that quite impressed me at the time.

Where all variables are positive integers, and a is at least as large as the n’th root of x, this algorithm returns the floor of the n’th root of x (and roughly doubling the number of accurate bits per iteration):

It’s not obvious why that works, but is no more obvious in the “loop and a half” form. It’s hard to prove correctness without building on the right insight (the “arithmetic mean - geometric mean inequality”), and knowing some non-trivial things about how nested floor functions behave. That is, the challenges are in the math, not really in the coding.

If you do know all that, then the assignment-expression form is easily read as “while the current guess is too large, get a smaller guess”, where the “too large?” test and the new guess share an expensive sub-expression.

To my eyes, the original form is harder to understand:

This appendix attempts to clarify (though not specify) the rules when a target occurs in a comprehension or in a generator expression. For a number of illustrative examples we show the original code, containing a comprehension, and the translation, where the comprehension has been replaced by an equivalent generator function plus some scaffolding.

Since [x for ...] is equivalent to list(x for ...) these examples all use list comprehensions without loss of generality. And since these examples are meant to clarify edge cases of the rules, they aren’t trying to look like real code.

Note: comprehensions are already implemented via synthesizing nested generator functions like those in this appendix. The new part is adding appropriate declarations to establish the intended scope of assignment expression targets (the same scope they resolve to as if the assignment were performed in the block containing the outermost comprehension). For type inference purposes, these illustrative expansions do not imply that assignment expression targets are always Optional (but they do indicate the target binding scope).

Let’s start with a reminder of what code is generated for a generator expression without assignment expression.

  • Original code (EXPR usually references VAR): def f (): a = [ EXPR for VAR in ITERABLE ]
  • Translation (let’s not worry about name conflicts): def f (): def genexpr ( iterator ): for VAR in iterator : yield EXPR a = list ( genexpr ( iter ( ITERABLE )))

Let’s add a simple assignment expression.

  • Original code: def f (): a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def f (): if False : TARGET = None # Dead code to ensure TARGET is a local variable def genexpr ( iterator ): nonlocal TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Let’s add a global TARGET declaration in f() .

  • Original code: def f (): global TARGET a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def f (): global TARGET def genexpr ( iterator ): global TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Or instead let’s add a nonlocal TARGET declaration in f() .

  • Original code: def g (): TARGET = ... def f (): nonlocal TARGET a = [ TARGET := EXPR for VAR in ITERABLE ]
  • Translation: def g (): TARGET = ... def f (): nonlocal TARGET def genexpr ( iterator ): nonlocal TARGET for VAR in iterator : TARGET = EXPR yield TARGET a = list ( genexpr ( iter ( ITERABLE )))

Finally, let’s nest two comprehensions.

  • Original code: def f (): a = [[ TARGET := i for i in range ( 3 )] for j in range ( 2 )] # I.e., a = [[0, 1, 2], [0, 1, 2]] print ( TARGET ) # prints 2
  • Translation: def f (): if False : TARGET = None def outer_genexpr ( outer_iterator ): nonlocal TARGET def inner_generator ( inner_iterator ): nonlocal TARGET for i in inner_iterator : TARGET = i yield i for j in outer_iterator : yield list ( inner_generator ( range ( 3 ))) a = list ( outer_genexpr ( range ( 2 ))) print ( TARGET )

Because it has been a point of confusion, note that nothing about Python’s scoping semantics is changed. Function-local scopes continue to be resolved at compile time, and to have indefinite temporal extent at run time (“full closures”). Example:

This document has been placed in the public domain.

Source: https://github.com/python/peps/blob/main/peps/pep-0572.rst

Last modified: 2023-10-11 12:05:51 GMT

  • DataFrame.query() Method
  • Performance: When to Use These Functions
  • Further Resources

This notebook contains an excerpt from the Python Data Science Handbook by Jake VanderPlas; the content is available on GitHub .

The text is released under the CC-BY-NC-ND license , and code is released under the MIT license . If you find this content useful, please consider supporting the work by buying the book !

< Working with Time Series | Contents | Further Resources >

High-Performance Pandas: eval() and query() ¶

As we've already seen in previous sections, the power of the PyData stack is built upon the ability of NumPy and Pandas to push basic operations into C via an intuitive syntax: examples are vectorized/broadcasted operations in NumPy, and grouping-type operations in Pandas. While these abstractions are efficient and effective for many common use cases, they often rely on the creation of temporary intermediate objects, which can cause undue overhead in computational time and memory use.

As of version 0.13 (released January 2014), Pandas includes some experimental tools that allow you to directly access C-speed operations without costly allocation of intermediate arrays. These are the eval() and query() functions, which rely on the Numexpr package. In this notebook we will walk through their use and give some rules-of-thumb about when you might think about using them.

Motivating query() and eval() : Compound Expressions ¶

We've seen previously that NumPy and Pandas support fast vectorized operations; for example, when adding the elements of two arrays:

As discussed in Computation on NumPy Arrays: Universal Functions , this is much faster than doing the addition via a Python loop or comprehension:

But this abstraction can become less efficient when computing compound expressions. For example, consider the following expression:

Because NumPy evaluates each subexpression, this is roughly equivalent to the following:

In other words, every intermediate step is explicitly allocated in memory . If the x and y arrays are very large, this can lead to significant memory and computational overhead. The Numexpr library gives you the ability to compute this type of compound expression element by element, without the need to allocate full intermediate arrays. The Numexpr documentation has more details, but for the time being it is sufficient to say that the library accepts a string giving the NumPy-style expression you'd like to compute:

The benefit here is that Numexpr evaluates the expression in a way that does not use full-sized temporary arrays, and thus can be much more efficient than NumPy, especially for large arrays. The Pandas eval() and query() tools that we will discuss here are conceptually similar, and depend on the Numexpr package.

pandas.eval() for Efficient Operations ¶

The eval() function in Pandas uses string expressions to efficiently compute operations using DataFrame s. For example, consider the following DataFrame s:

To compute the sum of all four DataFrame s using the typical Pandas approach, we can just write the sum:

The same result can be computed via pd.eval by constructing the expression as a string:

The eval() version of this expression is about 50% faster (and uses much less memory), while giving the same result:

Operations supported by pd.eval() ¶

As of Pandas v0.16, pd.eval() supports a wide range of operations. To demonstrate these, we'll use the following integer DataFrame s:

Arithmetic operators ¶

pd.eval() supports all arithmetic operators. For example:

Comparison operators ¶

pd.eval() supports all comparison operators, including chained expressions:

Bitwise operators ¶

pd.eval() supports the & and | bitwise operators:

In addition, it supports the use of the literal and and or in Boolean expressions:

Object attributes and indices ¶

pd.eval() supports access to object attributes via the obj.attr syntax, and indexes via the obj[index] syntax:

Other operations ¶

Other operations such as function calls, conditional statements, loops, and other more involved constructs are currently not implemented in pd.eval() . If you'd like to execute these more complicated types of expressions, you can use the Numexpr library itself.

DataFrame.eval() for Column-Wise Operations ¶

Just as Pandas has a top-level pd.eval() function, DataFrame s have an eval() method that works in similar ways. The benefit of the eval() method is that columns can be referred to by name . We'll use this labeled array as an example:

Using pd.eval() as above, we can compute expressions with the three columns like this:

The DataFrame.eval() method allows much more succinct evaluation of expressions with the columns:

Notice here that we treat column names as variables within the evaluated expression, and the result is what we would wish.

Assignment in DataFrame.eval() ¶

In addition to the options just discussed, DataFrame.eval() also allows assignment to any column. Let's use the DataFrame from before, which has columns 'A' , 'B' , and 'C' :

We can use df.eval() to create a new column 'D' and assign to it a value computed from the other columns:

In the same way, any existing column can be modified:

Local variables in DataFrame.eval() ¶

The DataFrame.eval() method supports an additional syntax that lets it work with local Python variables. Consider the following:

The @ character here marks a variable name rather than a column name , and lets you efficiently evaluate expressions involving the two "namespaces": the namespace of columns, and the namespace of Python objects. Notice that this @ character is only supported by the DataFrame.eval() method , not by the pandas.eval() function , because the pandas.eval() function only has access to the one (Python) namespace.

DataFrame.query() Method ¶

The DataFrame has another method based on evaluated strings, called the query() method. Consider the following:

As with the example used in our discussion of DataFrame.eval() , this is an expression involving columns of the DataFrame . It cannot be expressed using the DataFrame.eval() syntax, however! Instead, for this type of filtering operation, you can use the query() method:

In addition to being a more efficient computation, compared to the masking expression this is much easier to read and understand. Note that the query() method also accepts the @ flag to mark local variables:

Performance: When to Use These Functions ¶

When considering whether to use these functions, there are two considerations: computation time and memory use . Memory use is the most predictable aspect. As already mentioned, every compound expression involving NumPy arrays or Pandas DataFrame s will result in implicit creation of temporary arrays: For example, this:

Is roughly equivalent to this:

If the size of the temporary DataFrame s is significant compared to your available system memory (typically several gigabytes) then it's a good idea to use an eval() or query() expression. You can check the approximate size of your array in bytes using this:

On the performance side, eval() can be faster even when you are not maxing-out your system memory. The issue is how your temporary DataFrame s compare to the size of the L1 or L2 CPU cache on your system (typically a few megabytes in 2016); if they are much bigger, then eval() can avoid some potentially slow movement of values between the different memory caches. In practice, I find that the difference in computation time between the traditional methods and the eval / query method is usually not significant–if anything, the traditional method is faster for smaller arrays! The benefit of eval / query is mainly in the saved memory, and the sometimes cleaner syntax they offer.

We've covered most of the details of eval() and query() here; for more information on these, you can refer to the Pandas documentation. In particular, different parsers and engines can be specified for running these queries; for details on this, see the discussion within the "Enhancing Performance" section .

  • Python »
  • 3.14.0a0 Documentation »
  • Python 常見問題 »
  • Theme Auto Light Dark |

程式開發常見問答集 ¶

是否有可以使用在程式碼階段,具有中斷點,步驟執行等功能的除錯器? ¶.

下面描述了幾個 Python 除錯器,內建函式 breakpoint() 允許你進入其中任何一個。

pdb 模組是一個簡單但足夠的 Python 控制台模式除錯器。它是標準 Python 函式庫的一部分,並 記錄在函式庫參考手冊 中。你也可以參考 pdb 的程式碼作為範例來編寫自己的除錯器。

IDLE 交互式開發環境,它是標準 Python 發行版的一部分(通常作為 Tools/scripts/idle3 提供),包括一個圖形除錯器。

PythonWin 是一個 Python IDE,它包含一個基於 pdb 的 GUI 除錯器。 PythonWin 除錯器為斷點著色並具有許多很酷的功能,例如除錯非 PythonWin 程式。 PythonWin 作為 pywin32 專案的一部分和作為 ActivePython 的一部分發佈。

Eric 是一個基於 PyQt 和 Scintilla 編輯元件所建構的 IDE。

trepan3k 是一個類似 gdb 的除錯器。

Visual Studio Code 是一個整合了版本控制軟體與除錯工具的 IDE。

有數個商業化Python整合化開發工具包含圖形除錯功能。這些包含:

有沒有工具能夠幫忙找 bug 或執行靜態分析? ¶

Pylint 和 Pyflakes 進行基本檢查以幫助你儘早抓出錯誤。

靜態型別檢查器,例如 Mypy 、 Pyre 和 Pytype 可以檢查 Python 原始碼中的型別提示。

如何從 Python 腳本建立獨立的二進位檔案? ¶

如果只是想要一个独立的程序,以便用户不必预先安装 Python 即可下载和运行它,则不需要将 Python 编译成 C 代码。有许多工具可以检测程序所需的模块,并将这些模块与 Python 二进制程序捆绑在一起生成单个可执行文件。

一种方案是使用 freeze 工具,它以 Tools/freeze 的形式包含在 Python 源代码树中。 它可将 Python 字节码转换为 C 数组;你可以使用 C 编译器将你的所有模块嵌入到一个新程序中,再将其与标准 Python 模块进行链接。

它的工作原理是递归扫描源代码,获取两种格式的 import 语句,并在标准 Python 路径和源码目录(用于内置模块)检索这些模块。然后,把这些模块的 Python 字节码转换为 C 代码(可以利用 marshal 模块转换为代码对象的数组初始化器),并创建一个定制的配置文件,该文件仅包含程序实际用到的内置模块。然后,编译生成的 C 代码并将其与 Python 解释器的其余部分链接,形成一个自给自足的二进制文件,其功能与 Python 脚本代码完全相同。

以下套件可以幫助建立 console 和 GUI 可執行檔案:

Nuitka (跨平台)

PyInstaller (跨平台)

PyOxidizer (跨平台)

cx_Freeze (跨平台)

py2app (僅限 macOS)

py2exe (僅限 Windows)

Python 程式碼是否有編碼標準或風格指南? ¶

是的。標準函式庫模組所需的編碼風格稱為 PEP 8 。

為什麼當變數有值時,我仍得到錯誤訊息 UnboundLocalError? ¶

当在函数内部某处添加了一条赋值语句,因而导致之前正常工作的代码报出 UnboundLocalError 错误,这确实有点令人惊讶。

可以執行,但是這段程式:

導致 UnboundLocalError :

原因就是,当对某作用域内的变量进行赋值时,该变量将成为该作用域内的局部变量,并覆盖外部作用域中的同名变量。由于 foo 的最后一条语句为 x 分配了一个新值,编译器会将其识别为局部变量。因此,前面的 print(x) 试图输出未初始化的局部变量,就会引发错误。

在上面的示例中,你可以透過將其聲明為全域變數來存取外部範圍變數:

与类和实例变量貌似但不一样,其实以上是在修改外部作用域的变量值,为了提示这一点,这里需要显式声明一下。

你可以使用 nonlocal 关键字在嵌套作用域中执行类似的操作:

Python 的區域變數和全域變數有什麼規則? ¶

函数内部只作引用的 Python 变量隐式视为全局变量。如果在函数内部任何位置为变量赋值,则除非明确声明为全局变量,否则均将其视为局部变量。

起初尽管有点令人惊讶,不过考虑片刻即可释然。一方面,已分配的变量要求加上 global 可以防止意外的副作用发生。另一方面,如果所有全局引用都要加上 global ,那处处都得用上 global 了。那么每次对内置函数或导入模块中的组件进行引用时,都得声明为全局变量。这种杂乱会破坏 global 声明用于警示副作用的有效性。

为什么在循环中定义的参数各异的 lambda 都返回相同的结果? ¶

假設你使用 for 循環來定義幾個不同的 lambda(甚至是普通函式),例如:

以上会得到一个包含5个 lambda 函数的列表,这些函数将计算 x**2 。大家或许期望,调用这些函数会分别返回 0 、 1 、 4 、 9 和 16 。然而,真的试过就会发现,他们都会返回 16 :

这是因为 x 不是 lambda 函数的内部变量,而是定义于外部作用域中的,并且 x 是在调用 lambda 时访问的——而不是在定义时访问。循环结束时 x 的值是 4 ,所以此时所有的函数都将返回 4**2 ,即 16 。通过改变 x 的值并查看 lambda 的结果变化,也可以验证这一点。

为了避免发生上述情况,需要将值保存在 lambda 局部变量,以使其不依赖于全局 x 的值:

以上 n=x 创建了一个新的 lambda 本地变量 n ,并在定义 lambda 时计算其值,使其与循环当前时点的 x 值相同。这意味着 n 的值在第 1 个 lambda 中为 0 ,在第 2 个 lambda 中为 1 ,在第 3 个中为 2 ,依此类推。因此现在每个 lambda 都会返回正确结果:

請注意,此行為並非 lambda 所特有,也適用於常規函式。

如何跨模組共享全域變數? ¶

在单个程序中跨模块共享信息的规范方法是创建一个特殊模块(通常称为 config 或 cfg)。只需在应用程序的所有模块中导入该 config 模块;然后该模块就可当作全局名称使用了。因为每个模块只有一个实例,所以对该模块对象所做的任何更改将会在所有地方得以体现。 例如:

请注意,出于同样的原因,使用模块也是实现单例设计模式的基础。

导入模块的“最佳实践”是什么? ¶

通常请勿使用 from modulename import * 。因为这会扰乱 importer 的命名空间,且会造成未定义名称更难以被 Linter 检查出来。

请在代码文件的首部就导入模块。这样代码所需的模块就一目了然了,也不用考虑模块名是否在作用域内的问题。每行导入一个模块则增删起来会比较容易,每行导入多个模块则更节省屏幕空间。

按如下顺序导入模块就是一种好做法:

标准库模块——例如: sys 、 os 、 argparse 、 re 等。

第三方库模块(安装于 Python site-packages 目录中的内容)——例如: dateutil 、 requests 、 PIL.Image 等。

为了避免循环导入引发的问题,有时需要将模块导入语句移入函数或类的内部。Gordon McMillan 的说法如下:

当两个模块都采用 "import <module>" 的导入形式时,循环导入是没有问题的。但如果第 2 个模块想从第 1 个模块中取出一个名称("from module import name")并且导入处于代码的最顶层,那导入就会失败。原因是第 1 个模块中的名称还不可用,这时第 1 个模块正忙于导入第 2 个模块呢。

如果只是在一个函数中用到第 2 个模块,那这时将导入语句移入该函数内部即可。当调用到导入语句时,第 1 个模块将已经完成初始化,第 2 个模块就可以进行导入了。

如果某些模块是平台相关的,可能还需要把导入语句移出最顶级代码。这种情况下,甚至有可能无法导入文件首部的所有模块。于是在对应的平台相关代码中导入正确的模块,就是一种不错的选择。

只有为了避免循环导入问题,或有必要减少模块初始化时间时,才把导入语句移入类似函数定义内部的局部作用域。如果根据程序的执行方式,许多导入操作不是必需的,那么这种技术尤其有用。如果模块仅在某个函数中用到,可能还要将导入操作移入该函数内部。请注意,因为模块有一次初始化过程,所以第一次加载模块的代价可能会比较高,但多次加载几乎没有什么花费,代价只是进行几次字典检索而已。即使模块名超出了作用域,模块在 sys.modules 中也是可用的。

为什么对象之间会共享默认值? ¶

新手程序员常常中招这类 Bug。请看以下函数:

第一次调用此函数时, mydict 中只有一个数据项。第二次调用 mydict 则会包含两个数据项,因为 foo() 开始执行时, mydict 中已经带有一个数据项了。

大家往往希望,函数调用会为默认值创建新的对象。但事实并非如此。默认值只会在函数定义时创建一次。如果对象发生改变,就如上例中的字典那样,则后续调用该函数时将会引用这个改动的对象。

按照定义,不可变对象改动起来是安全的,诸如数字、字符串、元组和 None 之类。而可变对象的改动则可能引起困惑,例如字典、列表和类实例等。

因此,不把可变对象用作默认值是一种良好的编程做法。而应采用 None 作为默认值,然后在函数中检查参数是否为 None 并新建列表、字典或其他对象。例如,代码不应如下所示:

参数默认值的特性有时会很有用处。 如果有个函数的计算过程会比较耗时,有一种常见技巧是将每次函数调用的参数和结果缓存起来,并在同样的值被再次请求时返回缓存的值。这种技巧被称为“memoize”,实现代码可如下所示:

也可以不用参数默认值来实现,而是采用全局的字典变量;这取决于个人偏好。

如何将可选参数或关键字参数从一个函数传递到另一个函数? ¶

请利用函数参数列表中的标识符 * 和 ** 归集实参;结果会是元组形式的位置实参和字典形式的关键字实参。然后就可利用 * 和 ** 在调用其他函数时传入这些实参:

引數 (arguments) 和參數 (parameters) 有什麼區別? ¶

形参 是由出现在函数定义中的名称来定义的,而 参数 则是在调用函数时实际传入的值。 形参定义了一个函数能接受什么 参数种类 。 例如,对于以下函数定义:

foo 、 bar 和 kwargs 是 func 的參數。然而,當呼叫 func 時,例如:

42 、 314 和 somevar 是引數。

為什麼更改 list 'y' 也會更改 list 'x'? ¶

如果你寫了像這樣的程式碼:

你可能想知道為什麼將一個元素附加到 y 時也會改變 x 。

產生這個結果的原因有兩個:

变量只是指向对象的一个名称。执行 y = x 并不会创建列表的副本——而只是创建了一个新变量 y ,并指向 x 所指的同一对象。这就意味着只存在一个列表对象, x 和 y 都是对它的引用。

list 是 mutable ,這意味著你可以變更它們的內容。

在调用 append() 之后,该可变对象的内容由 [] 变为 [10] 。 由于两个变量引用了同一对象,因此用其中任意一个名称所访问到的都是修改后的值 [10] 。

如果把赋给 x 的对象换成一个不可变对象:

可见这时 x 和 y 就不再相等了。因为整数是 immutable 对象,在执行 x = x + 1 时,并不会修改整数对象 5 ,给它加上 1;而是创建了一个新的对象(整数对象 6 )并将其赋给 x (也就是改变了 x 所指向的对象)。在赋值完成后,就有了两个对象(整数对象 6 和 5 )和分别指向他俩的两个变量( x 现在指向 6 而 y 仍然指向 5 )。

某些操作 (例如 y.append(10) 和 y.sort() ) 是改变原对象,而看上去相似的另一些操作 (例如 y = y + [10] 和 sorted(y) <sorted>) 则是创建新对象。 通常在 Python 中 (以及在标准库的所有代码中) 会改变原对象的方法将返回 ``None`() 以帮助避免混淆这两种不同类型的操作。 因此如果你错误地使用了 y.sort() 并期望它将返回一个经过排序的 y 的副本,你得到的结果将会是 None ,这将导致你的程序产生一个容易诊断的错误。

不过还存在一类操作,用不同的类型执行相同的操作有时会发生不同的行为:即增量赋值运算符。例如, += 会修改列表,但不会修改元组或整数( a_list += [1, 2, 3] 与 a_list.extend([1, 2, 3]) 同样都会改变 a_list ,而 some_tuple += (1, 2, 3) 和 some_int += 1 则会创建新的对象)。

对于一个可变对象( list 、 dict 、 set 等等),可以利用某些特定的操作进行修改,所有引用它的变量都会反映出改动情况。

对于一个不可变对象( str 、 int 、 tuple 等),所有引用它的变量都会给出相同的值,但所有改变其值的操作都将返回一个新的对象。

如要知道两个变量是否指向同一个对象,可以利用 is 运算符或内置函数 id() 。

如何编写带有输出参数的函数(按照引用调用)? ¶

请记住,Python 中的实参是通过赋值传递的。由于赋值只是创建了对象的引用,所以调用方和被调用方的参数名都不存在别名,本质上也就不存在按引用调用的方式。通过以下几种方式,可以得到所需的效果。

这差不多是最明晰的解决方案了。

使用全局变量。这不是线程安全的方案,不推荐使用。

传递一个可变(即可原地修改的) 对象:

传入一个接收可变对象的字典:

或者把值用类实例封装起来:

没有什么理由要把问题搞得这么复杂。

最佳选择就是返回一个包含多个结果值的元组。

如何在 Python 中创建高阶函数? ¶

有两种选择:嵌套作用域、可调用对象。假定需要定义 linear(a,b) ,其返回结果是一个计算出 a*x+b 的函数 f(x) 。 采用嵌套作用域的方案如下:

都会得到一个可调用对象,可实现 taxes(10e6) == 0.3 * 10e6 + 2 。

可调用对象的方案有个缺点,就是速度稍慢且生成的代码略长。不过值得注意的是,同一组可调用对象能够通过继承来共享签名(类声明):

物件可以封裝多個方法的狀態:

這裡的 inc() 、 dec() 和 reset() 就像共享相同計數變數的函式一樣。

如何在 Python 中複製物件? ¶

一般情况下,用 copy.copy() 或 copy.deepcopy() 基本就可以了。并不是所有对象都支持复制,但多数是可以的。

某些对象可以用更简便的方法进行复制。比如字典对象就提供了 copy() 方法:

序列可以透過切片 (slicing) 複製:

如何找到物件的方法或屬性? ¶

对于一个用户定义类的实例 x , dir(x) 将返回一个按字母顺序排列的名称列表,其中包含实例属性及由类定义的方法和属性。

我的程式碼如何發現物件的名稱? ¶

一般而言这是无法实现的,因为对象并不存在真正的名称。赋值本质上是把某个名称绑定到某个值上; def 和 class 语句同样如此,只是值换成了某个可调用对象。比如以下代码:

可以不太严谨地说上述类有一个名称:即使它绑定了两个名称并通过名称 B 发起调用所创建的实例仍将被报告为类 A 的实例。 但是,没有办法肯定地说实例的名称是 a 还是 b ,因为这两个名称都被绑定到同一个值上了。

代码一般没有必要去“知晓”某个值的名称。通常这种需求预示着还是改变方案为好,除非真的是要编写内审程序。

在 comp.lang.python 中,Fredrik Lundh 曾針對這個問題給出了一個極好的比喻:

就像你在門廊上發現的那隻貓的名字一樣:貓(物件)本身不能告訴你它的名字,它也不關心 - 所以找出它叫什麼的唯一方法是詢問所有鄰居(命名空間)是否是他們的貓(物件)... ....如果你發現它有很多名字,或者根本沒有名字,請不要感到驚訝!

逗号运算符的优先级是什么? ¶

逗号不是 Python 的运算符。 请看以下例子:

由于逗号不是运算符,而只是表达式之间的分隔符,因此上述代码就相当于:

对于各种赋值运算符( = 、 += 等)来说同样如此。他们并不是真正的运算符,而只是赋值语句中的语法分隔符。

是否有等效於 C 的 "?:" 三元運算子? ¶

在 Python 2.5 引入上述语法之前,通常的做法是使用逻辑运算符:

然而这种做法并不保险,因为当 on_true 为布尔值“假”时,结果将会出错。所以肯定还是采用 ... if ... else ... 形式为妙。

是否可以用 Python 编写让人眼晕的单行程序? ¶

可以。 这一般是通过在 lambda 中嵌套 lambda 来实现的。 请参阅以下三个示例,它们是基于 Ulf Bartelt 的代码改写的:

孩子們,不要在家裡嘗試這個!

函数形参列表中的斜杠(/)是什么意思? ¶

函数参数列表中的斜杠表示在它之前的形参都是仅限位置形参。 仅限位置形参没有可供外部使用的名称。 在调用接受仅限位置形参的函数时,参数将只根据其位置被映射到形参上。 例如, divmod() 就是一个接受仅限位置形参的函数。 它的文档说明是这样的:

形参列表尾部的斜杠说明,两个形参都是仅限位置形参。因此,用关键字参数调用 divmod() 将会引发错误:

如何指定十六進位和八進位整數? ¶

要给出八进制数,需在八进制数值前面加上一个零和一个小写或大写字母 "o" 作为前缀。例如,要将变量 "a" 设为八进制的 "10" (十进制的 8),写法如下:

十六进制数也很简单。只要在十六进制数前面加上一个零和一个小写或大写的字母 "x"。十六进制数中的字母可以为大写或小写。比如在 Python 解释器中输入:

為什麼 -22 // 10 回傳 -3? ¶

这主要是为了让 i % j 的正负与 j 一致,如果期望如此,且期望如下等式成立:

那麼整數除法必須回傳向下取整的結果。 C 還要求保留​​該識別性,然後截斷 i // j 的編譯器需要使 i % j 具有與 i 相同的符號。

对于 i % j 来说 j 为负值的应用场景实际上是非常少的。 而 j 为正值的情况则非常多,并且实际上在所有情况下让 i % j 的结果为 >= 0 会更有用处。 如果现在时间为 10 时,那么 200 小时前应是几时? -190 % 12 == 2 是有用处的; -190 % 12 == -10 则是会导致意外的漏洞。

我如何获得 int 字面属性而不是 SyntaxError ? ¶

尝试以正式方式查找一个 int 字面值属性会发生 SyntaxError 因为句点会被当作是小数点:

解决办法是用空格或括号将字词与句号分开。

如何將字串轉換為數字? ¶

对于整数,可使用内置的 int() 类型构造器,例如 int('144') == 144 。 类似地,可使用 float() 转换为浮点数,例如 float('144') == 144.0 。

默认情况下,这些操作会将数字按十进制来解读,因此 int('0144') == 144 为真值,而 int('0x144') 会引发 ValueError 。 int(string, base) 接受第二个可选参数指定转换的基数,例如 int( '0x144', 16) == 324 。 如果指定基数为 0,则按 Python 规则解读数字:前缀 '0o' 表示八进制,而 '0x' 表示十六进制。

如果只是想把字符串转为数字,请不要使用内置函数 eval() 。 eval() 的速度慢很多且存在安全风险:别人可能会传入带有不良副作用的 Python 表达式。比如可能会传入 __import__('os').system("rm -rf $HOME") ,这会把 home 目录给删了。

eval() 还有把数字解析为 Python 表达式的后果,因此如 eval('09') 将会导致语法错误,因为 Python 不允许十进制数带有前导 '0'('0' 除外)。

如何將數字轉換為字串? ¶

例如,要把数字 144 转换为字符串 '144' ,可使用内置类型构造器 str() 。 如果你需要十六进制或八进制表示形式,可使用内置函数 hex() 或 oct() 。 更复杂的格式化方式,请参阅 f-string(f 字串) 和 格式化文字語法 等章节,例如 "{:04d}".format(144) 将产生 '0144' 而 "{:.3f}".format(1.0/3.0) 将产生 '0.333' 。

无法修改,因为字符串是不可变对象。 在大多数情况下,只要将各个部分组合起来构造出一个新字符串即可。如果需要一个能原地修改 Unicode 数据的对象,可以试试 io.StringIO 对象或 array 模块:

如何使用字符串调用函数/方法? ¶

最好的做法是采用一个字典,将字符串映射为函数。其主要优势就是字符串不必与函数名一样。这也是用来模拟 case 结构的主要技巧:

利用内置函数 getattr() :

请注意 getattr() 可用于任何对象,包括类、类实例、模块等等。

标准库就多次使用了这个技巧,例如:

用 locals() 解析出函数名:

是否有与Perl 的chomp() 等效的方法,用于从字符串中删除尾随换行符? ¶

可以使用 S.rstrip("\r\n") 从字符串 S 的末尾删除所有的换行符,而不删除其他尾随空格。如果字符串 S 表示多行,且末尾有几个空行,则将删除所有空行的换行符:

由于通常只在一次读取一行文本时才需要这样做,所以使用 S.rstrip() 这种方式工作得很好。

是否有 scanf() 或 sscanf() 的等价函数? ¶

对于简单的输入解析,最容易的做法通常是用字符串对象的 split() 方法将一行内容按空白分隔符拆分为多个单词再用 int() 或 float() 将十进制数值字符串转换为数值。 split() 支持可选的 "sep" 形参,适用于分隔符不是空白符的情况。

对于更复杂的输入解析,正则表达式相比 C 的 sscanf 更为强大也更为适合。

'UnicodeDecodeError' 或 'UnicodeEncodeErro' 錯誤是什麼意思? ¶

請參閱 Unicode 指南 。

我能以奇数个反斜杠来结束一个原始字符串吗? ¶

以奇数个反斜杠结尾的原始字符串将会转义用于标记字符串的引号:

有几种绕过此问题的办法。 其中之一是使用常规字符串以及双反斜杠:

另一种办法是将一个包含被转义反斜杠的常规字符串拼接到原始字符串上:

在 Windows 上还可以使用 os.path.join() 来添加反斜杠:

请注意虽然在确定原始字符串的结束位置时反斜杠会对引号进行“转义“,但在解析原始字符串的值时并不会发生转义。 也就是说,反斜杠会被保留在原始字符串的值中:

另请参阅 语言参考 中的规范说明。

我的程序太慢了。该如何加快速度? ¶

总的来说,这是个棘手的问题。在进一步讨论之前,首先应该记住以下几件事:

不同的 Python 实现具有不同的性能特点。 本 FAQ 着重解答的是 CPython 。

不同操作系统可能会有不同表现,尤其是涉及 I/O 和多线程时。

在尝试优化代码 之前 ,务必要先找出程序中的热点(请参阅 profile 模块)。

编写基准测试脚本,在寻求性能提升的过程中就能实现快速迭代(请参阅 timeit 模块)。

强烈建议首先要保证足够高的代码测试覆盖率(通过单元测试或其他技术),因为复杂的优化有可能会导致代码回退。

话虽如此,Python 代码的提速还是有很多技巧的。以下列出了一些普适性的原则,对于让性能达到可接受的水平会有很大帮助:

相较于试图对全部代码铺开做微观优化,优化算法(或换用更快的算法)可以产出更大的收益。

使用正确的数据结构。参考 內建型別 和 collections 模块的文档。

如果标准库已为某些操作提供了基础函数,则可能(当然不能保证)比所有自编的函数都要快。对于用 C 语言编写的基础函数则更是如此,比如内置函数和一些扩展类型。例如,一定要用内置方法 list.sort() 或 sorted() 函数进行排序(某些高级用法的示例请参阅 排序技法 )。

抽象往往会造成中间层,并会迫使解释器执行更多的操作。如果抽象出来的中间层级太多,工作量超过了要完成的有效任务,那么程序就会被拖慢。应该避免过度的抽象,而且往往也会对可读性产生不利影响,特别是当函数或方法比较小的时候。

如果你已经达到纯 Python 允许的限制,那么有一些工具可以让你走得更远。 例如, Cython 可以将稍加修改的 Python 代码版本编译为 C 扩展,并能在许多不同的平台上使用。 Cython 可以利用编译(和可选的类型标注)来让你的代码显著快于解释运行时的速度。 如果你对自己的 C 编程技能有信心,还可以自行 编写 C 扩展模块 。

有個 wiki 頁面專門介紹 效能改進小提示 。

将多个字符串连接在一起的最有效方法是什么? ¶

str 和 bytes 对象是不可变的,因此连接多个字符串的效率会很低,因为每次连接都会创建一个新的对象。一般情况下,总耗时与字符串总长是二次方的关系。

如果要连接多个 str 对象,通常推荐的方案是先全部放入列表,最后再调用 str.join() :

(还有一种合理高效的习惯做法,就是利用 io.StringIO )

如果要连接多个 bytes 对象,推荐做法是用 bytearray 对象的原地连接操作( += 运算符)追加数据:

序列(元组/列表) ¶

如何在元组和列表之间进行转换? ¶.

类型构造器 tuple(seq) 可将任意序列(实际上是任意可迭代对象)转换为数据项和顺序均不变的元组。

例如, tuple([1, 2, 3]) 会生成 (1, 2, 3) , tuple('abc') 则会生成 ('a', 'b', 'c') 。 如果参数就是元组,则不会创建副本而是返回同一对象,因此如果无法确定某个对象是否为元组时,直接调用 tuple() 也没什么代价。

类型构造器 list(seq) 可将任意序列或可迭代对象转换为数据项和顺序均不变的列表。例如, list((1, 2, 3)) 会生成 [1, 2, 3] 而 list('abc') 则会生成 ['a', 'b', 'c'] 。如果参数即为列表,则会像 seq[:] 那样创建一个副本。

Python 序列的索引可以是正数或负数。索引为正数时,0 是第一个索引值, 1 为第二个,依此类推。索引为负数时,-1 为倒数第一个索引值,-2 为倒数第二个,依此类推。可以认为 seq[-n] 就相当于 seq[len(seq)-n] 。

使用负数序号有时会很方便。 例如 S[:-1] 就是原字符串去掉最后一个字符,这可以用来移除某个字符串末尾的换行符。

序列如何以逆序遍历? ¶

使用内置函数 reversed() :

原序列不会变化,而是构建一个逆序的新副本以供遍历。

如何从列表中删除重复项? ¶

许多完成此操作的的详细介绍,可参阅 Python Cookbook:

https://code.activestate.com/recipes/52560/

如果列表允许重新排序,不妨先对其排序,然后从列表末尾开始扫描,依次删除重复项:

如果列表的所有元素都能用作集合的键(即都是 hashable ),以下做法速度往往更快:

以上操作会将列表转换为集合,从而删除重复项,然后返回成列表。

如何从列表中删除多个项? ¶

类似于删除重复项,一种做法是反向遍历并根据条件删除。不过更简单快速的做法就是切片替换操作,采用隐式或显式的正向迭代遍历。以下是三种变体写法:

列表推导式可能是最快的。

如何在 Python 中创建数组? ¶

列表在时间复杂度方面相当于 C 或 Pascal 的数组;主要区别在于,Python 列表可以包含多种不同类型的对象。

array 模块也提供了一些创建具有紧凑表示形式的固定类型数据的方法,但其索引速度要比列表慢。 还可关注 NumPy 和其他一些第三方包也定义了一些各具特色的数组类结构体。

要获得 Lisp 风格的列表,可以使用元组来模拟 cons 单元 :

如果需要可变特性,你可以用列表来代替元组。 在这里模拟 Lisp car 的是 lisp_list[0] 而模拟 cdr 的是 lisp_list[1] 。 只有在你确定真有需要时才这样做,因为这通常会比使用 Python 列表要慢上许多。

如何创建多维列表? ¶

多维数组或许会用以下方式建立:

但如果给某一项赋值,结果会同时在多个位置体现出来:

原因在于用 * 对列表执行重复操作并不会创建副本,而只是创建现有对象的引用。 *3 创建的是包含 3 个引用的列表,每个引用指向的是同一个长度为 2 的列表。1 处改动会体现在所有地方,这一定不是应有的方案。

推荐做法是先创建一个所需长度的列表,然后将每个元素都填充为一个新建列表。

以上生成了一个包含 3 个列表的列表,每个子列表的长度为 2。也可以采用列表推导式:

或者,你也可以使用提供矩阵数据类型的扩展;其中最著名的是 NumPy 。

我如何将一个方法或函数应用于由对象组成的序列? ¶

要调用一个方法或函数并将返回值累积到一个列表中, list comprehension 是一种优雅的解决方案:

如果只需运行方法或函数而不保存返回值,那么一个简单的 for 循环就足够了:

为什么 a_tuple[i] += ['item'] 会引发异常? ¶

这是由两个因素共同导致的,一是增强赋值运算符属于 赋值 运算符,二是 Python 可变和不可变对象之间的差别。

只要元组的元素指向可变对象,这时对元素进行增强赋值,那么这里介绍的内容都是适用的。在此只以 list 和 += 举例。

触发异常的原因显而易见: 1 会与指向( 1 )的对象 a_tuple[0] 相加,生成结果对象 2 ,但在试图将运算结果 2 赋值给元组的 0 号元素时就会报错,因为元组元素的指向无法更改。

其实在幕后,上述增强赋值语句的执行过程大致如下:

由于元组是不可变的,因此赋值这步会引发错误。

这时触发异常会令人略感惊讶,更让人吃惊的是虽有报错,但加法操作却生效了:

要明白为什么会这样,你需要知道 (a) 如果一个对象实现了 __iadd__() 魔术方法,那么它就会在执行 += 增强赋值时被调用,并且其返回值将在赋值语句中被使用;(b) 对于列表而言, __iadd__() 等价于在列表上调用 extend() 并返回该列表。 所以对于列表我们可以这样说, += 就是 list.extend() 的“快捷方式”:

a_list 所引用的对象已被修改,而引用被修改对象的指针又重新被赋值给 a_list 。 赋值的最终结果没有变化,因为它是引用 a_list 之前所引用的同一对象的指针,但仍然发生了赋值操作。

因此,在此元组示例中,发生的事情等同于:

__iadd__() 执行成功,因此列表得到了扩充,但是即使 result 是指向 a_tuple[0] 所指向的同一个对象,最后的赋值仍然会导致错误,因为元组是不可变的。

我想做一个复杂的排序:能用 Python 进行施瓦茨变换吗? ¶

归功于 Perl 社区的 Randal Schwartz,该技术根据度量值对列表进行排序,该度量值将每个元素映射为“顺序值”。在 Python 中,请利用 list.sort() 方法的 key 参数:

如何根据另一个列表的值对某列表进行排序? ¶

将它们合并到元组的迭代器中,对结果列表进行排序,然后选择所需的元素。

什麼是類別 (class)? ¶

类是通过执行 class 语句创建的某种对象的类型。创建实例对象时,用 Class 对象作为模板,实例对象既包含了数据(属性),又包含了数据类型特有的代码(方法)。

类可以基于一个或多个其他类(称之为基类)进行创建。基类的属性和方法都得以继承。这样对象模型就可以通过继承不断地进行细化。比如通用的 Mailbox 类提供了邮箱的基本访问方法.,它的子类 MboxMailbox 、 MaildirMailbox 、 OutlookMailbox 则能够处理各种特定的邮箱格式。

什麼是方法 (method)? ¶

方法是属于对象的函数,对于对象 x ,通常以 x.name(arguments...) 的形式调用。方法以函数的形式给出定义,位于类的定义内:

什么是 self ? ¶

Self 只是方法的第一个参数的习惯性名称。假定某个类中有个方法定义为 meth(self, a, b, c) ,则其实例 x 应以 x.meth(a, b, c) 的形式进行调用;而被调用的方法则应视其为做了 meth(x, a, b, c) 形式的调用。

另請參閱 為何「self」在方法 (method) 定義和呼叫時一定要明確使用? 。

如何检查对象是否为给定类或其子类的一个实例? ¶

使用内置函数 isinstance(obj, cls) 。 你可以检测对象是否属于多个类中的某一个的实例,只要提供一个元组而非单个类即可,如 isinstance(obj, (class1, class2, ...)) ,还可以检测对象是否属于 Python 的某个内置类型,如 isinstance(obj, str) 或 isinstance(obj, (int, float, complex)) 。

请注意 isinstance() 还会检测派生自 abstract base class 的虚继承。 因此对于已注册的类,即便没有直接或间接继承自抽象基类,对抽象基类的检测都将返回 True 。要想检测“真正的继承”,请扫描类的 MRO :

请注意,大多数程序不会经常用 isinstance() 对用户自定义类进行检测。 如果是自已开发的类,更合适的面向对象编程风格应该是在类中定义多种方法,以封装特定的行为,而不是检查对象属于什么类再据此干不同的事。假定有如下执行某些操作的函数:

更好的方法是在所有类上定义一个 search() 方法,然后调用它:

委托是一种面向对象的技术(也称为设计模式)。假设对象 x 已经存在,现在想要改变其某个方法的行为。可以创建一个新类,其中提供了所需修改方法的新实现,而将所有其他方法都委托给 x 的对应方法。

Python 程序员可以轻松实现委托。比如以下实现了一个类似于文件的类,只是会把所有写入的数据转换为大写:

这里 UpperOut 类重新定义了 write() 方法,在调用下层的 self._outfile.write() 方法之前将参数字符串转换为大写形式。 所有其他方法都被委托给下层的 self._outfile 对象。 委托是通过 __getattr__() 方法完成的;请参阅 语言参考 了解有关控制属性访问的更多信息。

请注意在更一般的情况下委托可能会变得比较棘手。 当属性即需要被设置又需要被提取时,类还必须定义 __setattr__() 方法,而这样做必须十分小心。 __setattr__() 的基本实现大致如下所示:

大多数 __setattr__() 实现都必须修改 self.__dict__ 来为自身保存局部状态而不至于造成无限递归。

如何在扩展基类的派生类中调用基类中定义的方法? ¶

使用内置的 super() 函数:

在下面的例子中, super() 将自动根据它的调用方 ( self 值) 来确定实例对象,使用 type(self).__mro__ 查找 method resolution order (MRO),并返回 MRO 中位于 Derived 之后的项: Base 。

如何让代码更容易对基类进行修改? ¶

可以为基类赋一个别名并基于该别名进行派生。这样只要修改赋给该别名的值即可。顺便提一下,如要动态地确定(例如根据可用的资源)该使用哪个基类,这个技巧也非常方便。例如:

如何创建静态类数据和静态类方法? ¶

Python 支持静态数据和静态方法(以 C++ 或 Java 的定义而言)。

静态数据只需定义一个类属性即可。若要为属性赋新值,则必须在赋值时显式使用类名:

对于所有符合 isinstance(c, C) 的 c , c.count 也同样指向 C.count ,除非被 c 自身或者被从 c.__class__ 回溯到基类 C 的搜索路径上的某个类所覆盖。

注意:在 C 的某个方法内部,像 self.count = 42 这样的赋值将在 self 自身的字典中新建一个名为 "count" 的不相关实例。 想要重新绑定类静态数据名称就必须总是指明类名,无论是在方法内部还是外部:

Python 支持静态方法:

不过为了获得静态方法的效果,还有一种做法直接得多,也即使用模块级函数即可:

如果代码的结构化比较充分,每个模块只定义了一个类(或者多个类的层次关系密切相关),那就具备了应有的封装。

在 Python 中如何重载构造函数(或方法)? ¶

这个答案实际上适用于所有方法,但问题通常首先出现于构造函数的应用场景中。

在 C++ 中,代码会如下所示:

在 Python 中,只能编写一个构造函数,并用默认参数捕获所有情况。例如:

这不完全等同,但在实践中足够接近。

也可以试试采用变长参数列表,例如:

上述做法同样适用于所有方法定义。

在用 __spam 的时候得到一个类似 _SomeClassName__spam 的错误信息。 ¶

以双下划线打头的变量名会被“破坏”,以便以一种简单高效的方式定义类私有变量。任何形式为 __spam 的标识符(至少前缀两个下划线,至多后缀一个下划线)文本均会被替换为 _classname__spam ,其中 classname 为去除了全部前缀下划线的当前类名称。

这并不能保证私密性:外部用户仍然可以访问 "_classname__spam" 属性,私有变量值也在对象的 __dict__ 中可见。 许多 Python 程序员根本不操心要去使用私有变量名。

类定义了 __del__ 方法,但是删除对象时没有调用它。 ¶

del 语句不一定要调用 __del__() -- 它只是减少对象的引用计数,如果计数达到零才会调用 __del__() 。

如果你的数据结构包含循环链接(如树每个子节点都带有父节点的引用,而每个父节点也带有子节点的列表),引用计数永远不会回零。 尽管 Python 偶尔会用某种算法检测这种循环引用,但在数据结构的最后一条引用消失之后,垃圾收集器可能还要过段时间才会运行,因此 __del__() 方法可能会在不方便或随机的时刻被调用。 这对于重现一个问题是非常不方便的。 更糟糕的是,各个对象的 __del__() 方法是以随机顺序执行的。 虽然你可以运行 gc.collect() 来强制执行垃圾回收操作,但 仍会存在 一些对象永远不会被回收的失控情况。

尽管有垃圾回收器,但当对象使用完毕时在要调用的对象上定义显式的 close() 方法仍然是个好主意。 close() 方法可以随后移除引用子对象的属性。 请不要直接调用 __del__() -- __del__() 应当调用 close() 并且 close() 应当确保被可以被同一对象多次调用。

另一种避免循环引用的做法是利用 weakref 模块,该模块允许指向对象但不增加其引用计数。例如,树状数据结构应该对父节点和同级节点使用弱引用(如果真要用的话!)

最后,如果你的 __del__() 方法引发了异常,会将警告消息打印到 sys.stderr 。

如何获取给定类的所有实例的列表? ¶

Python 不会记录类(或内置类型)的实例。可以在类的构造函数中编写代码,通过保留每个实例的弱引用列表来跟踪所有实例。

为什么 id() 的结果看起来不是唯一的? ¶

id() 返回一个整数,该整数在对象的生命周期内保证是唯一的。 因为在 CPython 中,这是对象的内存地址,所以经常发生在从内存中删除对象之后,下一个新创建的对象被分配在内存中的相同位置。 这个例子说明了这一点:

这两个 id 属于不同的整数对象,之前先创建了对象,执行 id() 调用后又立即被删除了。若要确保检测 id 时的对象仍处于活动状态,请再创建一个对该对象的引用:

我什麼時候可以依靠 is 運算子進行識別性測試? ¶

is 運算子測試物件識別性。測試 a is b 等同於 id(a) == id(b) 。

識別性測試最重要的屬性是物件始終與自身相同, a is a 總是回傳 True 。識別性測試通常比相等性測試更快。與相等性測試不同,識別性測試保證回傳布林值 True 或 False 。

然而,* 只有* 當物件識別性得到保證時,識別性測試才能代替相等性測試。一般來說,保證識別性的情況有以下三種:

1) Assignments create new names but do not change object identity. After the assignment new = old , it is guaranteed that new is old .

2) Putting an object in a container that stores object references does not change object identity. After the list assignment s[0] = x , it is guaranteed that s[0] is x .

3) 单例对象,也即该对象只能存在一个实例。在赋值操作 a = None 和 b = None 之后,可以保证 a is b ,因为 None 是单例对象。

在大多數其他情況下,識別性測試是不可取的,相等性測試是首選。特別是,識別性測試不應用於檢查常數,例如不能保證是單例的 int 和 str :

同样地,可变容器的新实例,对象身份一定不同:

在標準函式庫程式碼中,你將看到幾種正確使用識別性測試的常見模式:

1) As recommended by PEP 8 , an identity test is the preferred way to check for None . This reads like plain English in code and avoids confusion with other objects that may have boolean values that evaluate to false.

2) Detecting optional arguments can be tricky when None is a valid input value. In those situations, you can create a singleton sentinel object guaranteed to be distinct from other objects. For example, here is how to implement a method that behaves like dict.pop() :

3) Container implementations sometimes need to augment equality tests with identity tests. This prevents the code from being confused by objects such as float('NaN') that are not equal to themselves.

例如,以下是 collections.abc.Sequence.__contains__() 的實作:

子類別如何控制不可變實例中存儲的資料? ¶

当子类化一个不可变类型时,请重写 __new__() 方法而不是 __init__() 方法。 后者只在一个实例被创建 之后 运行,这对于改变不可变实例中的数据来说太晚了。

所有这些不可变的类都有一个与它们的父类不同的签名:

這些類別可以像這樣使用:

我该如何缓存方法调用? ¶

缓存方法的两个主要工具是 functools.cached_property() 和 functools.lru_cache() 。 前者在实例层级上存储结果而后者在类层级上存储结果。

cached_property 方式仅适用于不接受任何参数的方法。 它不会创建对实例的引用。 被缓存的方法结果将仅在实例的生存其内被保留。

其优点是,当一个实例不再被使用时,缓存的方法结果将被立即释放。缺点是,如果实例累积起来,累积的方法结果也会增加。它们可以无限制地增长。

lru_cache 方法適用於具有 可雜湊 引數的方法。除非特別努力傳遞弱引用,否則它會建立對實例的引用。

最少近期使用算法的优点是缓存会受指定的 maxsize 限制。 它的缺点是实例会保持存活,直到其达到生存期或者缓存被清空。

这个例子演示了几种不同的方式:

上面的例子假定 station_id 从不改变。 如果相关实例属性是可变对象,则 cached_property 方式就不再适用,因为它无法检测到属性的改变。

要让 lru_cache 方式在 station_id 可变时仍然适用,类需要定义 __eq__() 和 __hash__() 方法以便缓存能检测到相关属性的更新:

如何创建 .pyc 文件? ¶

当首次导入模块时(或当前已编译文件创建之后源文件发生了改动),在 .py 文件所在目录的 __pycache__ 子目录下会创建一个包含已编译代码的 .pyc 文件。该 .pyc 文件的名称开头部分将与 .py 文件名相同,并以 .pyc 为后缀,中间部分则依据创建它的 python 版本而各不相同。(详见 PEP 3147 。)

.pyc 文件有可能会无法创建,原因之一是源码文件所在的目录存在权限问题,这样就无法创建 __pycache__ 子目录。假如以某个用户开发程序而以另一用户运行程序,就有可能发生权限问题,测试 Web 服务器就属于这种情况。

除非设置了 PYTHONDONTWRITEBYTECODE 环境变量,否则导入模块并且 Python 能够创建 __pycache__ 子目录并把已编译模块写入该子目录(权限、存储空间等等)时,.pyc 文件就将自动创建。

在最高层级运行的 Python 脚本不会被视为经过了导入操作,因此不会创建 .pyc 文件。假定有一个最高层级的模块文件 foo.py ,它导入了另一个模块 xyz.py ,当运行 foo 模块(通过输入 shell 命令 python foo.py ),则会为 xyz 创建一个 .pyc ,因为 xyz 是被导入的,但不会为 foo 创建 .pyc 文件,因为 foo.py 不是被导入的。

若要为 foo 创建 .pyc 文件 —— 即为未做导入的模块创建 .pyc 文件 —— 可以利用 py_compile 和 compileall 模块。

py_compile 模块能够手动编译任意模块。 一种做法是交互式地使用该模块中的 compile() 函数:

这将会将 .pyc 文件写入与 foo.py 相同位置下的 __pycache__ 子目录(或者你也可以通过可选参数 cfile 来重写该行为)。

还可以用 compileall 模块自动编译一个或多个目录下的所有文件。只要在命令行提示符中运行 compileall.py 并给出要编译的 Python 文件所在目录路径即可:

如何找到当前模块名称? ¶

模块可以查看预定义的全局变量 __name__ 获悉自己的名称。如其值为 '__main__' ,程序将作为脚本运行。通常,许多通过导入使用的模块同时也提供命令行接口或自检代码,这些代码只在检测到处于 __name__ 之后才会执行:

如何让模块相互导入? ¶

问题是解释器将执行以下步骤:

为 foo 创建空的全局变量

编译 foo 并开始执行

为 bar 创建空的全局变量

bar 已被編譯並開始執行

bar 导入 foo (该步骤无操作,因为已经有一个名为 foo 的模块)。

导入机制尝试从 foo_var 全局变量读取 foo ,用来设置 bar.foo_var = foo.foo_var

最后一步失败了,因为 Python 还没有完成对 foo 的解释,foo 的全局符号字典仍然是空的。

当你使用 import foo ,然后尝试在全局代码中访问 foo.foo_var 时,会发生同样的事情。

此問題有(至少)三種可能的解決方法。

Guido van Rossum 建议完全避免使用 from <module> import ... ,并将所有代码放在函数中。全局变量和类变量的初始化只应使用常量或内置函数。这意味着导入模块中的所有内容都以 <module>.<name> 的形式引用。

Jim Roskind 建議在每個模組中按以下順序執行各個步驟:

导出(全局变量、函数和不需要导入基类的类)

活躍程式碼(包括從引入值初始化的全域變數)。

Van Rossum 不太喜欢这种方法,因为import出现在一个奇怪的地方,但它确实有效。

Matthias Urlichs 建議重構你的程式碼,以便打從一開始就不需要遞迴引入。

__import__('x.y.z') 回傳 <module 'x'>,那我怎麼得到 z? ¶

不妨考虑换用 importlib 中的函数 import_module() :

當我編輯需要引入的模組並重新引入它時,更動沒有反應出來。為什麼會這樣? ¶

出于效率和一致性的原因,Python 仅在第一次导入模块时读取模块文件。否则,在一个多模块的程序中,每个模块都会导入相同的基础模块,那么基础模块将会被一而再、再而三地解析。如果要强行重新读取已更改的模块,请执行以下操作:

警告:这种技术并非万无一失。尤其是模块包含了以下语句时:

仍将继续使用前一版的导入对象。如果模块包含了类的定义,并 不会 用新的类定义更新现有的类实例。这样可能会导致以下矛盾的行为:

如果印出類別物件的「識別性」,問題的本質就很清楚了:

一般的 Python 常見問答集

IMAGES

  1. Python eval()

    python assignment in eval

  2. Python eval()

    python assignment in eval

  3. Python eval()

    python assignment in eval

  4. Python eval() -- How to Dynamically Evaluate a Code Expression in Python

    python assignment in eval

  5. Python eval() function

    python assignment in eval

  6. Advanced Python (GCSE Level)

    python assignment in eval

VIDEO

  1. Python-джедай #14

  2. eval function In python

  3. List in Python(Part2)

  4. Solving String Expression in Python Using eval Function #pythonprogramming

  5. Python #11

  6. ASSIGNMENT OPERATORS IN PYTHON #python #iit

COMMENTS

  1. How can I assign the value of a variable using eval in python?

    You can't, since variable assignment is a statement, not an expression, and eval can only eval expressions. Use exec instead. Better yet, don't use either and tell us what you're really trying to do so that we can come up with a safe and sane solution.

  2. Python eval(): Evaluate Expressions Dynamically

    Python's eval() allows you to evaluate arbitrary Python expressions from a string-based or compiled-code-based input. This function can be handy when you're trying to dynamically evaluate Python expressions from any input that comes as a string or a compiled code object.. Although Python's eval() is an incredibly useful tool, the function has some important security implications that you ...

  3. python

    Python's eval function evaluates expressions. It doesn't execute statements. Assignment is a statement, not an expression. That explains the problem you're having. In general. making a global change using eval is A Really Bad Idea. -

  4. Python's Assignment Operator: Write Robust Assignments

    Here, variable represents a generic Python variable, while expression represents any Python object that you can provide as a concrete value—also known as a literal—or an expression that evaluates to a value. To execute an assignment statement like the above, Python runs the following steps: Evaluate the right-hand expression to produce a concrete value or object.

  5. eval in Python

    Output: x*(x+1)*(x+2) 60. Evaluate Boolean Expressions in Python. Here the eval statement x == 4 will evaluate to False because the value of x is 5, which is not equal to 4. In the second eval statement, x is None will evaluate to True because the value of x is None, and is None checks for object identity, not value equality.

  6. Python eval() Function with Examples

    This function returns the result on evaluating the input expression. Let us see some examples of using the eval () function. Example of eval () function: eval('3*8') Output: 24. In this example, the expression is 3*8 which is 24. So, the output is 24. We can also give sequence and variables as the inputs to this function.

  7. eval() in Python

    How to Use eval() in Python. Example 1: The eval() function parses the expression argument and evaluates it as a Python expression. eval('3 + 5 * 2') Example 2: It can also evaluate expressions with variables defined in the local scope. x = 10.

  8. Python eval()

    The eval () function takes three parameters: expression - the string parsed and evaluated as a Python expression. globals (optional) - a dictionary. locals (optional)- a mapping object. Dictionary is the standard and commonly used mapping type in Python. The use of globals and locals will be discussed later in this article.

  9. Python eval() function

    Python eval() function converts and computes the expressions passed to it. NOTE: Use this method only for testing purposes. The eval() function does not sanitize the expressions passed to it. ... If the python expression turns out to be an assignment expression, inplace decides to perform the operation and mutate the data frame object. If FALSE ...

  10. Evaluate Expressions Dynamically With Python eval() (Overview)

    The built-in Python function eval() is used to evaluate Python expressions. You can pass a string containing Python, or a pre-compiled object into eval() and it will run the code and return the result.. Although Python's eval() is an incredibly useful tool, the function has some important security implications that you should consider before using it. . In this course, you'll learn how ...

  11. Python eval() Function

    The eval() function evaluates/executes an expression passed as a string, or as a code object generated by the compile function.. The function evaluates the input expression and returns the yielded value.

  12. Python

    The eval() function returns the value of a Python expression passed as a string.. Security Concerns. While eval() can be useful, care must be taken to understand the security implications of this function. If eval() is used with user-generated strings, a malicious user could execute arbitrary code through the function. Good programming practice generally advises against using eval().

  13. How to Assign the Result of eval() to a Python Variable?

    Related Tutorial: Python's eval() built-in function. Without further ado, let's learn how you can store the result of the eval() function in a Python variable:. Method 1: Simple Assignment. The most straightforward way to store the result of an eval() expression in a Python variable is to as s ign the whole return value to the variable. For example, the expression my_result = eval('2+2 ...

  14. Python Eval Function

    The eval in Python is a built-in function that evaluates a string as a Python expression and returns the result. It takes a single parameter which is a string containing a Python expression or statement to be evaluated. The expression can include any valid Python code, such as arithmetic operations, function calls, and control structures.

  15. Python eval() Function

    W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

  16. Assignment Expressions: The Walrus Operator

    The Python 3.8 documentation also includes some good examples of assignment expressions. Here are a few resources for more info on using bpython, the REPL (Read-Eval-Print Loop) tool used in most of these videos: Discover bpython: A Python REPL With IDE-Like Features; A better Python REPL: bpython vs python; bpython Homepage; bpython Docs

  17. 7. Simple statements

    Simple statements — Python 3.12.3 documentation. 7. Simple statements ¶. A simple statement is comprised within a single logical line. Several simple statements may occur on a single line separated by semicolons. The syntax for simple statements is: simple_stmt ::= expression_stmt. | assert_stmt.

  18. PEP 572

    Unparenthesized assignment expressions are prohibited for the value of a keyword argument in a call. Example: foo(x = y := f(x)) # INVALID foo(x=(y := f(x))) # Valid, though probably confusing. This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

  19. High-Performance Pandas: eval() and query()

    The @ character here marks a variable name rather than a column name, and lets you efficiently evaluate expressions involving the two "namespaces": the namespace of columns, and the namespace of Python objects.Notice that this @ character is only supported by the DataFrame.eval() method, not by the pandas.eval() function, because the pandas.eval() function only has access to the one (Python ...

  20. Evaluate Expressions Dynamically With Python eval() (Summary)

    00:00 In the previous lesson, I showed you how to build a quick little command line calculator. In this lesson, I'll summarize the course. 00:08 This course has been about the built-in function eval() and how to use it inside of Python to evaluate expressions. Expressions are a subset of the Python language and do not include statements. 00:22 Generally, expressions are things that evaluate ...

  21. python assignment and logical eval one-liner

    Python assignment to conditional LHS. 2 Python eval and logical operators. 0 Python 3- Multiple Assignment in a single statement. 1 Assignment operators using logical operators in Python. 0 Python assigning variables with an OR on assignment, multiple statements in one line? ...

  22. 程式開發常見問答集

    目錄: 程式開發常見問答集- 常見問題- 是否有可以使用在程式碼階段,具有中斷點,步驟執行等功能的除錯器?, 有沒有工具能夠幫忙找 bug 或執行靜態分析?, 如何從 Python 腳本建立獨立的二進位檔案?, Python 程式碼是否有編碼標準或風格指南?., 核心語言- 為什麼當變數有值時,我仍得到錯誤訊息 ...