Planet Python
Last update: June 09, 2023 09:42 PM UTC
June 09, 2023
Daniel Roy Greenfeld
Converting from bleach to nh3
Bleach is deprecated, here's how to come close to replicating bleach.clean()
using the nh3 version of .clean()
.
import nh3
def clean_string(string: str) -> str:
# The arguments below being passed to `nh3.clean()` are
# the default values of the `bleach.clean()` function.
return nh3.clean(
string,
tags={
"a",
"abbr",
"acronym",
"b",
"blockquote",
"code",
"em",
"i",
"li",
"ol",
"strong",
"ul",
},
attributes={
"a": {"href", "title"},
"abbr": {"title"},
"acronym": {"title"},
},
url_schemes={"http", "https", "mailto"},
link_rel=None,
)
The big difference is unlike the safing of HTML done by bleach, nh3 removes the offending tags altogether. Read the comments below to see what this means.
Results:
>>> input_from_user = """<b>
<img src="">
I\'m not trying to XSS you <a href="https://example.com">Link</a>
</b>"""
>>>
>>> # By default, bleach version safes the HTML
>>> # rather than remove the tags altogether.
>>> bleach.clean(input_from_user)
'<b><img src="">I\'m not trying to XSS you <a href="https://example.com">Link</a></b>'
>>>
>>> # In contrast, nh3 removes the offending tags entirely
>>> # while also preserving whitespace.
>>> clean_string(input_from_user)
'<b>\n\nI\'m not trying to XSS you <a href="https://example.com">Link</a>\n</b>'
I think the advantages of switching to nh3 approach:
- nh3 is actively maintained, bleach is officially deprecated.
- The nh3 technique of stripping tags rather than allowing safing is more secure. The idea of safing is great, but I've always wondered if a creative attacker could find a way to exploit it. I think it is better to remove the offending tags altogether.
- The preservation of whitespace is really useful for preserving content submitted in a textarea. This is especially true for Markdown content.
- nh3 is a binding to the rust-ammonia project. They claim a 15x speed increase over bleach's binding to the html5lib project. Even if that is a 3x exaggeration, that's still a 5x speed increase.
Python Engineering at Microsoft
Python in Visual Studio Code – June 2023 Release
We’re excited to announce that the June 2023 release of the Python and Jupyter extensions for Visual Studio Code are now available!
This release includes the following announcements:
- Test Discovery and Execution Rewrite
- Run Python File in Dedicated Terminal
- Preview: Intellisense support for overloaded operators
- Configurable indexing limits with Pylance
If you’re interested, you can check the full list of improvements in our changelogs for the Python, Jupyter and Pylance extensions.
Test Discovery and Execution Rewrite
This month, we are beginning the roll out of our testing rewrite behind an experimental feature. This rewrite redesigns the architecture behind test discovery and execution for both unittest and pytest in the extension. While it does not provide any additional functionality exposed to the user, it provides a faster and more stable experience, and opens up new functionality opportunities moving forward.
The rewrite will be rolled out behind the experimental "pythonTestAdapter"
flag, which you can opt into with "python.experiments.optInto"
in your settings.json
.
Eventually, we plan to remove the setting and adopt this new architecture. If you have any comments or suggestions regarding this experiment or rewrite, please share them in the vscode-python repo.
Run Python File in Dedicated Terminal
The Python extension will now create a new terminal for each file you run using the run button in the top right corner of the editor or the Python: Run Python File in Terminal command. This also means the Python extension will keep using this file’s “dedicated” terminal every time you re-run the file.
Any time you wish to run the same file in a separate terminal, you can run select Python: Run Python File in Dedicated Terminal under the run button menu.
Preview: IntelliSense support for overloaded operators with Pylance
Overloaded operators allow you to redefine the behavior of built-in operators for your custom objects or data types. When using the latest pre-release version of the Pylance extension, you are now able to use IntelliSense to explore and utilize overloaded operators with ease and efficiency.
This functionality provides code completion, parameter information, and signature help for overloaded operators, whether you’re working with mathematical vectors, complex numbers, or any other custom classes.
Configurable indexing limits with Pylance
There’s a new Pylance setting that allows you to configure the file count limit for indexing: "python.analysis.userFileIndexingLimit"
, which is set to 2000 by default. This setting can be particularly helpful when you’re working with very large projects and are willing to compromise performance for an enhanced IntelliSense experience.
Other Changes and Enhancements
We have also added small enhancements and fixed issues requested by users that should improve your experience working with Python and Jupyter Notebooks in Visual Studio Code. Some notable changes include:
- New experimental
createEnvironment.contentButton
setting to disable the Create Environment button in dependency files (vscode-python#21212) - Detect installed packages in the selected environment (vscode-python#21231)
- New
python.analysis.inlayHints.callArgumentNames
setting to enable inlay hints for call argument names with Pylance
We would also like to extend special thanks to this month’s contributors:
- @PeterjClaw Disable “snippers” expansion in Jedi LSP (vscode-python#21194)
- @JonathanRayner Add option for pyenv interpreters when creating environments with venv (vscode-python#21219)
- @cpinamtz Fix typo in a type declaration of MultiStepInput module (vscode-python#21156)
- @cpinamtz Insert debug configuration function on every quick pick item (vscode-python#21165)
- @cpinamtz Add more coverage to utils function (vscode-python#21026)
- @cpinamtz Remove IS_WINDOWS constant in favor of PlatformService (vscode-python#21157)
Try out these new improvements by downloading the Python extension and the Jupyter extension from the Marketplace, or install them directly from the extensions view in Visual Studio Code (Ctrl + Shift + X or ⌘ + ⇧ + X). You can learn more about Python support in Visual Studio Code in the documentation. If you run into any problems or have suggestions, please file an issue on the Python VS Code GitHub page.
The post Python in Visual Studio Code – June 2023 Release appeared first on Python.
Mike Driscoll
The Python Show Podcast Now on YouTube
The Python Show Podcast now has a YouTube channel too. You can find the first episode of The Python Show there now:
If you prefer to listen to The Python Show, you can stream it on the following websites:
The post The Python Show Podcast Now on YouTube appeared first on Mouse Vs Python.
Real Python
The Real Python Podcast – Episode #159: Volunteering, Organizing, and Finding a Python Community
Have you thought about getting more involved in the Python community? Are you interested in volunteering for an event or becoming an organizer? This week on the show, we speak with organizers from this year's PyCascades conference about making connections, learning new skills, and rationing your time.
[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
June 08, 2023
Wing Tips
Source Assistant in Wing Pro
This Wing Tip introduces the Source Assistant tool in Wing Pro, which provides context-sensitive at-your-fingertips code intelligence and documentation as you navigate through or write Python code.
The Source Assistant is where Wing Pro shows details about the type of a symbol, including documentation, call signature, and information about object inheritance and overridden methods. For builtin types and the standard library, this includes also links into Python documentation.
The Source Assistant is integrated with every part of Wing IDE, so it shows information for the current selection in the editor, auto-completer, Python Shell, Source Browser, Project manager, and Debug Console. It continuously updates as you move through your code or write new code.
Here are some examples of the Source Assistant in action in the editor, auto-completer, and Source Browser:

Shown above: Moving through code in the editor, the auto-completer, and Source Browser to view type signature, documentation, and other code intelligence in Wing Pro's Source Assistant tool.
See the Source Assistant documentation for details.
That's it for now! We'll be back soon with more Wing Tips for Wing Python IDE.
As always, please don't hesitate to email support@wingware.com if you run into problems or have any questions.
Live Interactive Python Coding in Wing Pro
This Wing Tip describes how to use the debugger in Wing Pro to write new Python code with direct access to the runtime state that the code is intended for, so you can immediately try out the code that you write. This is a far more efficient way to write most code, compared with working offline.
The key to working interactively in Wing is to run the debugger to a breakpoint in the
code that you are working on. Once this is done, the auto-completer and other code
intelligence features in Wing use both static analysis and runtime type analysis in
code that is active on the debug process stack. The source of a symbol in the completer is
indicated with the cog "runtime" icon.
In this context, you can immediately try out newly written code, and retry it as often as needed after correcting errors, by executing it in Wing Pro's Debug Console tool. You do need to be mindful of what the (possibly incorrect) code that you try does to the runtime state and restart the debugger if it becomes invalid. But in most cases it is possible to re-run corrected code and work iteratively without restarting your code.
Here is an example of live interactive coding in Wing Pro after running to a breakpoint in the editor:

Shown above: Entering code while the debugger is at a breakpoint, with auto-completion and auto-editing features that inspect the live runtime state of the debug process, then trying out an invocation in the Debug Console.
Notice that the above example uses a conditional breakpoint, as described in the previous Wing Tip. These are a great way to select the specific runtime case for which you want to write new code, for example to fix a bug that occurs only in a particular scenario.
Active Ranges
The above example simply copied and pasted code into the Debug Console in order to try it out. In many cases it's easier to select a range of lines that you are working on and mark those as the "active range", so that they can be executed and re-executed repeatedly as needed.
This is done by selecting the lines in the editor and pressing the active
range icon in the top right of the Debug Console. Once an active range is set, the
icon in the Debug Console will execute it in the current debug stack frame.
See the Interactive Debug Console documentation for details.
That's it for now! We'll be back soon with more Wing Tips for Wing Python IDE.
As always, please don't hesitate to email support@wingware.com if you run into problems or have any questions.
Auto Completion in Wing Pro
In this issue of Wing Tips we introduce Wing Pro's auto-completer, which can be used to find and more quickly enter symbols, imports, and snippets into Python code.
By default, Wing shows the auto-completer as you type in the editor, populating the completer with whatever code symbols and snippets are relevant to the particular context you are working in. The arrow keys can be used to move up and down the completion list and a completion is selected by pressing Tab or other completion key configured with the Editor > Auto-completion > Completion Keys preference in Wing. The same preferences group lets you specify whether to show the completer immediately or only after a certain number of characters or elapsed time, how to place the completion, and various other options.
Here is what the completer looks like in action:

Shown above: Using the auto-completer to enter new Python code in Wing Pro.
Notice that the auto-completer contains two columns of icons like
and
that indicate the origin and type of the symbol.
These are described in detail in Auto-completion Icons.
Auto-Import
In Wing 9.1 and later the auto-completer also contains suggestions for modules you may want to import for the code that you are writing. When these completions are selected, Wing enters the symbol for the selected import at the current position in the editor and also adds the necessary import statement at the top of your file:

Shown above: Using the auto-completer to enter code and new import statements simultaneously.
The Editor > Auto-completion > Python Auto-Imports preference controls whether to always show auto-imports, show them only on request, or to hide them entirely from the completer. See also the Imports tool.
Snippets
The completer also offers code snippets appropriate for the current context. These are
indicated with the scissors icon. The default set of snippets that come with
Wing Pro may be viewed and altered in the Snippets tool in the Tools menu.
Here is an example of entering snippets with the auto-completer, using the Tab key to move between and fill out fields in the snippets:

Shown above: Using the auto-completer to enter code snippets for a class, a method, and a nested definition, showing how snippets can take different forms depending on their context in the code.
See the Code Snippets documentation for more information.
That's it for now! We'll be back next week with more Wing Tips for Wing Python IDE.
Spyder IDE
Spyder gets CZI grant to add remote development features, and a new job opening!
During the last few years, Spyder has positioned itself as a popular data science IDE by combining interactive computing and ease of use with robust programming tools. However, limited remote development support compared to some other IDEs has hindered adoption, as many users would like to work with data and code on high performance computing (HPC) clusters or cloud providers like AWS, GCP or DigitalOcean while developing on their personal computers. Adding such features would open up many new research possibilities by enabling the scientific community to tackle data and compute-intensive programming tasks from the ease and efficiency of their local development environments. Thanks to a two-year grant from the Chan Zuckerberg Initiative, we will be now able to address this shortcoming.
Right now, users have two main options to work remotely using a local IDE (aside from a purely web browser-based approach, which is sometimes not available or desirable): They can either edit and execute their files in a terminal, which is not user-friendly; or start their IDE on the server and display it locally, which is typically slow, resource-intensive and difficult to set up. Furthermore, scientists typically find it difficult to sync remote files to the local machine and version control their code on the remote one, so remote changes are often lost, out of sync or difficult to integrate with code developed locally.
To address this situation, we will add and enhance support for local Spyder installations to run code and sync files on remote servers and clusters. The first step in that direction is to enhance the existing remote code execution features in Spyder, as the current workflow is error-prone and quite cumbersome. It requires users to install the Spyder-Kernels package on the remote machine, manually start a kernel on it and provide the kernel connection file to the local machine.
Since Spyder does not currently have a way to identify and store state changes, users currently have to repeat this costly setup process if there are any configuration modifications on the remote machine. Our plan is to fully automate this procedure so that Spyder can start and connect to a remote kernel automatically, with the user only needing to provide their SSH credentials and specify the Python environment they want to use.
After that is implemented, we will add support to create and manage remote Python environments, explore the remote filesystem in the Files pane, and edit remote files in the Editor. This will make most of the core Spyder functionality work when developing code remotely. In addition, users will be able to easily start system shells connected to the server once we implement that capability in Spyder-Terminal. This will allow the remote execution of any operating system-level command or program, such as Git commit and push instructions.
Finally, we want to announce that we're hiring for this project! We are looking for a Python developer with solid networking knowledge to help us implement the backend infrastructure that will power the features described above. This is a part time position to work as a contractor through NumFOCUS; it does not require experience with PyQt (although some would be beneficial) and it lasts until the end of the year, with the possibility to renew the contract for the next. Interested? Contact me to talk more about it!
We hope you will be as thrilled as we are by this fantastic news, and are looking forward to sharing more with you on this project in the near future!
June 07, 2023
Anwesha Das
Meeting community at PyCon Italy, 2023
The PyCon Italy, 2023 discussion started in PyCon Sweden 2022, when Valerio invited me for the keynote. From disbelief (since my talk at PyCon Sweden was not good) to believing, from searching for talk topics to preparation and multiple rounds of rehearsals and feedback sessions, I was finally ready for the talk.
The day before the travel
And it was one of the bustiest days on my calendar. I did two Ansible releases (7.6.0 and 8.0.0rc1), attended an event on Inner Source, participated (and got elected) in the board meeting of the Python Sweden Board, last minute prep of the talk, not forget the never-ending packing and finally the day arrived for the travel.
Arrival at Florance
After a 10-hour + journey, we reached Florence. It is a beautiful city. There was history everywhere, in every corner. Fun fact, when checking out from the first hotel to the conference venue, we figured out the hotel was only 500+ years old.
Meeting the community
PyCons always gives me the feeling of meeting family. It was my time to meet my friends whom I am never met post-pandemic. I met many friends from online first time in real life during the conference. And, of course, like always meeting and making new friends.
Meeting Audrey
In PyCon 2017, when I met Carol, she once said, "Anwesha, I would really like you to meet Jessica and Audrey. I believe you will be able to connect." I longed for this to happen for so long. This time I finally got to meet Audrey and how Carol was right about us connecting :). I look up to her for all her work in and for the Python and broader open-source community. More than anything, her work in setting up PyLadies has been the catalyst to change the direction of my life. But now I got know what a wonderful human being she is. Thank you, Audrey, for being you, just you :).
Py, the youngest volunteer
My kid has always been a conference child. She started attending conferences when she was ten months old and volunteering as a toddler. But what I noticed this time was how dutiful and serious she had become. She used to get up every day on time (no matter how tired she was from the last day) and report to her duty at the Registration desk. It felt good when she did my registration :).
Day 0 of the leading conference
It started with a bang with a great opening session by Valerio and Ester. This is one of the best conference opening presentations I have ever seen. It was well-crafted presentation. It is informative, fun, and even explains the Pacman rule. It established the tone of the conference to the community-first approach.
Then was the time for Carlton&aposs keynote "Open Source for the long-haul." It should be a must-watch list for anyone who wants a sustainable career and life in the Open Source ecosystem. It depicts the true picture of our world.
The day of the keynote
My talk was on the first day of the main conference, ending the keynote. I had a rehearsal of my talk with Carol. She gave me two vital pieces of advice "Take a deep breath every time you start." The second is, &aposAs a keynote speaker, you are just expected to concentrate on your talk and nothing else.&apos I followed them religiously. Generally, during the conferences, I run around, meet new people, talk to everyone, and throw myself into some or other voluntary work. But this time, for the first two days&apos conference, till my talk was done, I was away saving my energy and practicing. My biggest worry was if I could finish it within time and the technology should not fail me. And finally, the time came for me to go up on stage. It was nerve-racking (and it is so visible from how I was dancing on the stage before the talk :). I ticked all the major boxes in the talk. Never froze during the talk, saying all the things which I wanted to and finish the on time. Only one thing I could not do was to wear my Red Hat during the talk. It seems I have become to Scandinavian to wear it during the spring in Italy. Everything ended well with a standing ovation at the end :).
I could only deliver the talk with help from my friends. Tom who made me believe that my journey is inspiring and worth giving a keynote about, others wise I was thinking of talking about legal stuff. Saptak for his help with the slides and for answering my random 2 am calls and requests for the last couple of months. Brett, Carol , Andrea, and Kushal for helping me to stick to the idea, for sitting with me for rehearsal sessions and listing to my unfiltered blabbering, And not forgetting Py for sitting with Mummy for days, and pointing out to my mistakes. I could mention one line she requested, but quoting her here, "Not all the flowers are to be treated equally, so should not be the lawyers and developers." This is to elaborate on the difference between law and technology.
And day 0 ended for me with a glass of wine :).
Day 1 of the main conference
Day 1 started with the keynote by Marlene, "Transcendence: The Power of Representation". It had his life lessons, the state of the community, and how we can make things better in the community. Thank you, Marlene, for echoing many of our thoughts. Then it was my time to mingle with the community. I was trying to meet new people from different parts of the world and to know what happens in the part of the community there. I met several Ansible Users, so Python and PyCon Italia allowed me to meet the global Ansible community. A surprise awaited me in the second half of the day. I got to meet Tyler for the first time. It was unexpected, I did not know she is coming. It was a nice surprise. From Red Hat to community we had a good conversation :).
Day 1 ended with a fantastic conference dinner, a local band performance, and some great conversations with friends.
Day 2 of the main conference
On day 2 Emily, in her keynote on "Stay Curious: Reflections on Passion, Risk-Taking, and Re-Invention", shared the importance of self-care, time out, and prioritization for a sustainable career. She further shared how to silence "the hum" of being there or doing things. My gratitude to Emily for stressing the point that burnout is genuine.
I fixed meetings for the last day on the first two days of the main conference. So my day two was filled with meetings regarding several different things, starting with feedback on the Ansible Project and Community with some users, then discussions on Python Community, including PyLadies and Pycon Sweden Organization and state of Trademark at PSF.
PyCon Italia 2023 came to an end with an ending talk by Ernesto. I was surprised to know a few statistics, especially that people from 42 countries attended the conference. The best moment of the day was when Py went up on stage as part of the volunteering team :).
Thank you PyCon Italia team for giving us such a great conference. I hope to meet the community again at PyCon Italia 2024, cheers to that.
PyCharm
PyCharm 2023.2 EAP 3 Is Out!
The third EAP build brings improvements for working with Docker compose and an update to the pytest support.
To catch up on all of the new features PyCharm 2023.2 will bring, check out our previous EAP blog posts.
The Toolbox App is the easiest way to get the EAP builds and keep both your stable and EAP versions up to date. You can also manually download the EAP builds from our website.

Important! PyCharm EAP builds are not fully tested and might be unstable.
Below you can find the most interesting improvements available in PyCharm 2023.2 EAP 3. Please try them out and share your feedback in the comments below or by using our issue tracker.
User experience
Light theme with light header in the new UI
For PyCharm 2023.2, we’ve refined the user experience with the Light theme by introducing the alternate Light with Light Header option, featuring matching light colors for window headers, tooltips, and notification balloons.

Single-click navigation between project directories
In the Project view, there’s a new Open Directories with Single Click option that makes expanding and collapsing the project folders quicker and more responsive. The option is available from the drop-down menu once you click on the three dots icon.

Improved main toolbar customization
We’ve expanded the customization options for the new UI’s main toolbar. You can now use a dropdown menu to quickly choose actions that you want to add to the toolbar. To do so, right-click on any widget, select Add to Main Toolbar, and explore the available options.

Setting to create a project name for the Docker Compose-based interpreter
In PyCharm 2023.2 when setting up a Docker Compose-based interpreter, you will now be able to choose a separate name for the compose cluster. Now, clusters and projects can be assigned their own unique name, preventing any issues associated with the default naming of the folder where the docker configuration file is located.
To choose a name use the new field “Project name” on the first step of the Setup Wizard. By default, this field is empty, but it shows the name of the project that is going to be used during the execution of docker-compose. You can set up a cluster name for the existing Docker Compose interpreter by following the same steps.

According to the Docker documentation, project names must contain only lowercase letters, decimal digits, dashes, and underscores, and must begin with a lowercase letter or decimal digit. PyCharm will return an error if the naming requirements aren’t met.
Refactoring and navigation for the fixture inside the usefixture
decorator in pytest
PyCharm 2023.2 will recognize the fixture inside pytest’s usefixture
marker. This means that you will be able to refactor the fixture, navigate directly to its declaration from the @pytest.mark.usefixtures
decorator, and use code insight and quick documentation options for it.

Suggested plugins in Settings/Preferences
To make it easier to configure the IDE for your specific projects and extend its functionality with plugins, we have updated the UI for the Settings/Preferences | Plugins section. It now includes a set of suggested plugins that is automatically defined based on your project specifics and appears at the top of the list.
These are the most notable highlights of the PyCharm 2023.2 EAP 3 build. To see the full list of changes in this EAP build, please refer to the release notes.
Try out these new features and let us know what you think in the comments below or on Twitter. If you encounter any bugs, please report them via our issue tracker.
PyBites
Veterans in the workplace, challenges and tips
Welcome back to the Pybites podcast!
Watch here:
Or listen here:
In this podcast episode, Julian interviews Isaac Smit, a former member of the US Navy and current program manager at Amazon.
He discusses the challenges faced by veterans in the workplace and how we can support them better.
Isaac highlights two main difficulties veterans encounter: dealing with ambiguity and managing invisible disabilities like post-traumatic stress disorder (PTSD).
The transition from a highly structured military environment to a more ambiguous corporate setting can be challenging for veterans.
Additionally, the invisible disabilities that many veterans have may affect their cognitive abilities, including memory, and it’s important for us as colleagues and managers to provide understanding and support.
Throughout the podcast, it becomes apparent that building trust with veterans and understanding them is crucial. It’s important to offer assistance, be patient, and create an inclusive environment where veterans feel comfortable.
As employers and colleagues, we can be more supportive by acknowledging the sacrifices veterans have made, expressing gratitude for their service, and being open to conversations about their experiences (although not triggering them explicitly).
Moreover, as managers, we should be aware of the potential performance challenges veterans may face due to their disabilities and provide necessary support while respecting their privacy.
Expect a special, thought provoking episode and we are grateful for Isaac sharing openly about his experience and giving valuable tips.
As always there are wins and interesting books as well …
Connect with Isaac on LinkedIn.
Books mentioned:
– The Untethered Soul
– The Art of War
Chapters:
00:00 Intro episode
02:44 Intro guest + topic
03:22 Wins
05:10 Isaac’s background + leadership development work
09:00 Veterans moving into the corporate world
14:00 Effects of PTSD
17:40 Challenges for veteran family members
22:00 Civil job interview challenges for veterans
24:22 Tips for supporting veterans in the workplace
25:10 Provide structure for the work
26:20 Have empathy (e.g. for veterans with PTSD)
29:33 How can managers help?
32:34 Patience and acknowledgement of sacrifice
38:00 Watch out for triggers
41:10 Books (The Untethered Soul / The Art of War)
45:30 Wrap up and thanks
47:17 Outro
Thanks for listening and we’ll be back next week.
Real Python
What's the Zen of Python?
If you’ve been learning Python long enough, then you’ve likely seen or heard about the Zen of Python. Experienced Pythonistas often refer to it as a source of wisdom and guidance, especially when they want to settle an argument about certain design decisions in a piece of code. Others take these principles even more seriously by considering them a sort of Pythonic decalogue.
In this tutorial, you’ll learn where to find the Zen of Python, how it came into existence, and how to interpret its mysterious aphorisms. You don’t need to be a Python master to understand the Zen of Python! But you do need to answer an important question: What exactly is the Zen of Python?
Free Bonus: Click here to download your Easter egg hunt to discover what’s hidden inside Python!
In Short: It’s a Humorous Poem Listing Python Philosophies
According to the Python glossary, which contains definitions of popular terms related to this programming language, the Zen of Python is a:
Listing of Python design principles and philosophies that are helpful in understanding and using the language. The listing can be found by typing “
import this
” at the interactive prompt. (Source)
Indeed, when you type the indicated import
statement into an interactive Python REPL, then you’ll be presented with the nineteen aphorisms that make up the Zen of Python:
>>> import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
The byline reveals the poem’s author, Tim Peters, who’s a renowned software engineer and a long-standing CPython core developer best known for inventing the Timsort sorting algorithm. He also authored the doctest
and timeit
modules in the Python standard library, along with making many other contributions.
Take your time to read through the Zen of Python and contemplate its wisdom. But don’t take the aphorisms literally, as they’re more of a guiding set of principles rather than strict instructions. You’ll learn about their humorous origins in the next section.
How Did the Zen of Python Originate?
The idea of formulating a single document that would encapsulate Python’s fundamental philosophies emerged among the core developers in June 1999. As more and more people began coming to Python from other programming languages, they’d often bring their preconceived notions of software design that weren’t necessarily Pythonic. To help them follow the spirit of the language, a set of recommendations for writing idiomatic Python was needed.
The initial discussion about creating such a document took place on the Python mailing list under the subject The Python Way. Today, you can find this conversation in the official Python-list archive. If you look closely at the first message from Tim Peters in that thread, then you’ll notice that he clearly outlined the Zen of Python as a joke. That original form has stuck around until this day:
Clearly a job for Guido alone – although I doubt it’s one he’ll take on (fwiw, I wish he would too!). Here’s the outline he would start from, though <wink>:
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren’t special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one– and preferably only one –obvious way to do it.
Although that way may not be obvious at first unless you’re Dutch.
Now is better than never.
Although never is often better than right now.
If the implementation is hard to explain, it’s a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea – let’s do more of those!There you go: 20 Pythonic Fec^H^H^HTheses on the nose, counting the one I’m leaving for Guido to fill in. If the answer to any Python design issue isn’t obvious after reading those – well, I just give up <wink>. (Source)
The wink and the playful way of self-censoring some toilet humor are clear giveaways that Tim Peters didn’t want anyone to take his comment too seriously.
Note: In case you didn’t get the joke, he started to write something like Feces but then used ^H
—which represents a Backspace in older text editors like Vim—to delete the last three letters and make the word Theses. Therefore, the intended phrase is 20 Pythonic Theses.
Eventually, these nearly twenty theses got a proper name and were formally codified in a Python Enhancement Proposal document. Each PEP document receives a number. For example, you might have stumbled on PEP 8, which is the style guide for writing readable Python code. Perhaps as an inside joke, the Zen of Python received the number PEP 20 to signify the incomplete number of aphorisms in it.
To win your next argument about what makes good Python code, you can back up your claims with the Zen of Python. If you’d like to refer to a specific aphorism instead of the entire poem, then consider visiting pep20.org, which provides convenient clickable links to each principle.
And, in case you want to learn the poem by heart while having some fun, you can now listen to a song with the Zen of Python as its lyrics. Barry Warsaw, another core developer involved with Python since its early days, composed and performed this musical rendition. The song became the closing track on a special vinyl record entitled The Zen Side of the Moon, which was auctioned at PyCon US 2023.
Okay. Now that you have a rough idea of what the Zen of Python is and how it came about, you might be asking yourself whether you should really follow it.
Should You Obey the Zen of Python?
Read the full article at https://realpython.com/zen-of-python/ »
[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Python Software Foundation
Affirming your PSF Membership voting status
Every PSF Voting Member (Supporting, Managing, Contributing, and Fellow) needs to affirm their membership in order to vote in this year’s election.
Why you are being asked to do this:
The PSF has not enforced this in the past, because it was technically challenging to do so. Now that our voting membership has been completely consolidated into psfmember.org, we are able to do so.
Our motivation is to ensure that our elections can meet quorum as required by Section 3.9 of our bylaws. As our membership has grown we have seen that and increasing number of Contributing, Managing, and Fellow members with indefinite membership do not engage with our annual election, making quorum difficult to reach.
You can see your membership record and status on psfmember.org (note you must be logged in to view that page). If you are a voting-eligible member and do not already have a login there, please sign up and then email psf-donations@python.org so we can link your membership to your account. You can click the emailed link to re-certify without signing in. But please create your account and ensure it is linked to your membership so that we can ensure we have the most up-to-date contact information for you in the future.
What happens next? You’ll get an email from OpaVote with a ballot on or before June 20th and then you can vote!
Learn more about membership here or if you have questions about membership or nominations please email psf-elections@python.org In addition to Slack you are welcome to join the discussion about the PSF Board election on our forum.
Stack Abuse
Get Keys and Values from a Dictionary in Python
Introduction
A dictionary in Python is an essential and robust built-in data structure that allows efficient retrieval of data by establishing a relationship between keys and values. It is an unordered collection of key-value pairs, where the values are stored under a specific key rather than in a particular order.
In this article, we will take a look at different approaches for accessing keys and values in dictionaries. We will review illustrative examples and discuss the appropriate contexts for each approach.
A Brief Anatomy of a Dictionary
What Is a Dictionary in Python?
You can visualize a Python dictionary by thinking about traditional physical dictionaries. The dictionary's key
is similar to a word that we would like to search for, and the value
is like the corresponding definition of the word in the dictionary. In terms of Python's data structures, dictionaries are containers that can hold other objects. Unlike ordered or indexed sequences (such as lists), dictionaries are mappings that assign a distinct name or key
to each element.
Building Blocks of a Dictionary
A key in a dictionary serves as a unique identifier that allows us to locate specific information. Keys can be of any immutable type (e.g., strings, numbers, tuples). The data associated with each key is called a value
, and can be mutable.
Any data type, such as a string, number, list, or even another dictionary, is an acceptable value
. The combination of these key-value pairs is represented in the form of tuples, known as dictionary items
. Together, these keys, values, and items collectively form the core structure of a dictionary. Let's explore how we can retrieve these elements.
To illustrate this, let's first construct a simple address book dictionary. The keys represent names of individuals, and the corresponding values contain their associated shipping addresses. We can construct it as below:
address_book = {
"Alicia Johnson": "123 Main Street, Cityville",
"Jerry Smith": "456 Corner Avenue, Townsville",
"Michael Jonas": "789 End Lane, Villageville"
}
We can visualize the structure of our simple dictionary as below:
Get Keys in a Dictionary
Key Retrieval Using the keys() Method
The keys()
method of a dictionary returns a list-like object containing all the keys of the dictionary. We can call this method on our address_book
as below:
address_keys = address_book.keys()
print(address_keys)
This gives us:
dict_keys(['Alicia Johnson', 'Jerry Smith', 'Michael Jonas'])
The output returned above is a dict_keys
object containing the keys of the address_book
dictionary. The advantage of this method is that we can further iterate over the dict_keys
object, convert it into a list, or use it in any other manner to access the individual keys. For example, let's utilize the keys we've extracted to find the first name of each person:
for k in address_keys:
print(k.split()[0]) # Split by space separator and return only the first string
And we get:
Alicia
Jerry
Michael
Key Retrieval Using the in
Operator
Dictionaries in Python support iteration, which means that we can loop over their elements and test membership using the in
operator. This versatile approach returns each key individually, rather than in a list-like object.
Let's use a simple for-loop
and the in
operator as an alternative way to return the keys of the dictionary:
for k in address_book:
print(k)
We get a similar output as above:
Alicia Johnson
Jerry Smith
Michael Jonas
Here, the expression k in address_book
searches for a key in the dictionary, not an index or a value. Note that dictionaries don't preserve the order of the pairs, so don't rely on item order when looping over dictionaries.
How to Get Values in a Dictionary
Now that we've seen how to retrieve dictionary keys, let's see some of the different approaches to get the corresponding values from our dictionary.
Retrieve Value by Key Using Square Brackets
Values in a dictionary are directly accessible by their respective keys. Since each key relates to exactly one value, we can access values using the square-brackets operator on the dictionary object.
For instance, let's try to find Jerry Smith's address:
print(address_book['Jerry Smith'])
We get their address as below:
456 Corner Avenue, Townsville
Retrieve Value Using get() Method
A major drawback of the square brackets operator we used above is that it returns a KeyError
when we try to access an item not present in the dictionary. For example, let's look for the non-existent customer "Brita Philips":
print(address_book['Brita Philips'])
We receive an error as below:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
print(address_book['Brita Philips'])
KeyError: 'Brita Philips'
To avoid this, we can use the get()
method, which returns the value if it exists in the dictionary, and a default value otherwise. Let's try:
print(address_book.get('Brita Philips'))
The output is cleaner now, returning None
instead of a KeyError
:
None
If you'd like to return any other default value instead of None
, you can specify your own:
print(address_book.get('Brita Philips', 'Not a person'))
And we get:
Not a person
Value Retrieval Using the values() Method
The values()
method returns a list-like object which contains the values of the dictionary. For instance:
print(address_book.values())
This gives us:
dict_values(['123 Main Street, Cityville', '456 Corner Avenue, Townsville', '789 End Lane, Villageville'])
As you may have already guessed, it is possible to further iterate over the returned dict_values
object. You may also have noticed that there is no convenient method for getting the key from a value. This is because it is entirely possible to have duplicate values, whereas keys must be unique within a dictionary.
Get Key-Value Pairs from a Dictionary Simultaneously
We often need to retrieve the complete key-value pair (called item
) from a dictionary. There are a few different ways to do so.
Key-Value Retrieval Using the items() Method
The items()
method returns a list-like iterable object which yields each key-value pair as a tuple. Each returned item is of the form (key, value)
.
In our example, this is as below:
print(address_book.items())
This gives us:
dict_items([('Alicia Johnson', '123 Main Street, Cityville'), ('Jerry Smith', '456 Corner Avenue, Townsville'), ('Michael Jonas', '789 End Lane, Villageville')])
Using a For Loop with the items() Method
The items()
method gave us a dict_items
object in the above example. We can further unpack each pair using a for
statement as below:
for key, value in address_book.items():
print(key, "=>", value)
This yields:
Alicia Johnson => 123 Main Street, Cityville
Jerry Smith => 456 Corner Avenue, Townsville
Michael Jonas => 789 End Lane, Villageville
List Comprehension with Tuple Unpacking for Dictionary Items
Using list comprehension is an efficient way to return both the key and the value together in a single operation without the need to look up the key separately.
For example:
addresses = [key + " => " + value for key, value in address_book.items()]
print(addresses)
We get:
['Alicia Johnson => 123 Main Street, Cityville', 'Jerry Smith => 456 Corner Avenue, Townsville', 'Michael Jonas => 789 End Lane, Villageville']
To learn more about dictionary comprehension, you can read our guide to dictionary comprehension in Python.
### Conclusion
Retrieving keys and values from Python dictionaries is a widely-used and fundamental operation in data handling. We have seen that dictionaries are an incredibly efficient and versatile way of checking for key membership. This article has provided an overview of different methods to extract keys, values, and pairs from dictionaries.
Python Bytes
#339 Actual Technical People
<a href='https://www.youtube.com/watch?v=gFuCamgrqIQ' style='font-weight: bold;'>Watch on YouTube</a><br> <br> <p><strong>About the show</strong></p> <p>Sponsored by <a href="https://pythonbytes.fm/influxdata"><strong>InfluxDB</strong></a> from Influxdata.</p> <p><strong>Connect with the hosts</strong></p> <ul> <li>Michael: <a href="https://fosstodon.org/@mkennedy"><strong>@mkennedy@fosstodon.org</strong></a></li> <li>Brian: <a href="https://fosstodon.org/@brianokken"><strong>@brianokken@fosstodon.org</strong></a></li> <li>Show: <a href="https://fosstodon.org/@pythonbytes"><strong>@pythonbytes@fosstodon.org</strong></a></li> </ul> <p>Join us on YouTube at <a href="https://pythonbytes.fm/stream/live"><strong>pythonbytes.fm/live</strong></a> to be part of the audience. Usually Tuesdays at 11am PT. Older video versions available there too.</p> <p><strong>Michael #1:</strong> <a href="https://github.com/bloomberg/pystack"><strong>pystack</strong></a></p> <ul> <li>PyStack is a tool that uses forbidden magic to let you inspect the stack frames of a running Python process or a Python core dump, helping you quickly and easily learn what it's doing.</li> <li>PyStack has the following amazing features: <ul> <li>💻 Works with both running processes and core dump files.</li> <li>🧵 Shows if each thread currently holds the Python GIL, is waiting to acquire it, or is currently dropping it.</li> <li>🗑️ Shows if a thread is running a garbage collection cycle.</li> <li>🐍 Optionally shows native function calls, as well as Python ones. In this mode, PyStack prints the native stack trace (C/C++/Rust function calls), except that the calls to Python callables are replaced with frames showing the Python code being executed, instead of showing the internal C code the interpreter used to make the call.</li> <li>🔍 Automatically demangles symbols shown in the native stack.</li> <li>📈 Includes calls to inlined functions in the native stack whenever enough debug information is available.</li> <li>🔍 Optionally shows the values of local variables and function arguments in Python stack frames.</li> <li>🔒 Safe to use on running processes. PyStack does not modify any memory or execute any code in a process that is running. It simply attaches just long enough to read some of the process's memory.</li> <li>⚡ Optionally, it can perform a Python stack analysis without pausing the process at all. This minimizes impact to the debugged process, at the cost of potentially failing due to data races.</li> <li>🚀 Super fast! It can analyze core files 10x faster than general-purpose tools like GDB.</li> <li>🎯 Even works with aggressively optimized Python interpreter binaries.</li> <li>🔍 Even works with Python interpreters' binaries that do not have symbols or debug information (Python stack only).</li> <li>💥 Tolerates memory corruption well. Even if the process crashed due to memory corruption, PyStack can usually reconstruct the stack.</li> <li>💼 Self-contained: it does not depend on external tools or programs other than the Python interpreter used to run PyStack itself.</li> </ul></li> </ul> <p><strong>Brian #2:</strong> <a href="https://blog.pypi.org/posts/2023-05-25-securing-pypi-with-2fa/"><strong>Securing PyPI accounts via Two-Factor Authentication</strong></a></p> <ul> <li>Donald Stufft</li> <li>“… <em>every</em> account that maintains any project or organization on PyPI will be required to enable 2FA on their account by the end of 2023.”</li> <li>“One of the key security promises that PyPI makes is that when you're downloading something, that only the people associated with that project are going to be able to upload, delete, or otherwise modify a project. That when you look at that project and see that it is owned by someone that you trust, that you can be assured that nobody else is making changes to that package on PyPI.”</li> <li>If you maintain a package on PyPI to a point where you are uploading to PyPI or plan to soon, enable 2FA on you account.</li> <li>May as well do it sooner than later. But officially, you have the rest of the year.</li> <li>This has already been a requirement for “critical projects” since last summer. (top 1% of downloads, about 3,500 projects.) See <a href="https://pythonbytes.fm/episodes/show/293/and-if-i-pull-this-open-source-jenga-block">episode 293</a>.</li> <li>Now it’s going to be for everyone.</li> </ul> <p><strong>Michael #3:</strong> <a href="https://github.com/Lancetnik/Propan"><strong>Propan - a declarative Python MQ framework</strong></a></p> <ul> <li>Propan is a powerful and easy-to-use Python framework for building asynchronous web services that interact with any MQ Broker.</li> <li>It's following by <a href="https://fastapi.tiangolo.com/ru/"><em>fastapi</em></a>, simplify Message Brokers around code writing and provides a helpful development toolkit, which existed only in HTTP-frameworks world until now.</li> <li>It is a modern, high-level framework on top of popular specific Python brokers libraries, based on <a href="https://docs.pydantic.dev/"><em>pydantic</em></a> and <a href="https://fastapi.tiangolo.com/ru/"><em>fastapi</em></a>, <a href="https://docs.pytest.org/en/latest/"><em>pytest</em></a> concepts.</li> <li><strong>The key features are</strong> <ul> <li><strong>Simple</strong>: Designed to be easy to use and learn.</li> <li><strong>Intuitive</strong>: Great editor support. Autocompletion everywhere.</li> <li><a href="https://github.com/Lancetnik/Propan#dependencies"><strong>Dependencies management</strong></a>: Minimization of code duplication. Access to dependencies at any level of the call stack.</li> <li><a href="https://github.com/Lancetnik/Propan#http-frameworks-integrations"><strong>Integrations</strong></a>: <strong>Propan</strong> is fully compatible with <a href="https://lancetnik.github.io/Propan/integrations/1_integrations-index/">any HTTP framework</a> you want</li> <li><strong>MQ independent</strong>: Single interface to popular MQ: <ul> <li><strong>Redis</strong> (based on <a href="https://redis.readthedocs.io/en/stable/index.html">redis-py</a>)</li> <li><strong>RabbitMQ</strong> (based on <a href="https://aio-pika.readthedocs.io/en/latest/">aio-pika</a>)</li> <li><strong>Kafka</strong> (based on <a href="https://aiokafka.readthedocs.io/en/stable/">aiokafka</a>)</li> <li><strong>SQS</strong> (based on <a href="https://aiobotocore.readthedocs.io/en/latest/">aiobotocore</a>)</li> <li><strong>Nats</strong> (based on <a href="https://github.com/nats-io/nats.py">nats-py</a>)</li> </ul></li> <li><a href="https://lancetnik.github.io/Propan/getting_started/4_broker/5_rpc/"><strong>RPC</strong></a>: The framework supports RPC requests over MQ, which will allow performing long operations on remote services asynchronously.</li> <li><a href="https://github.com/Lancetnik/Propan#cli-power"><strong>Great to develop</strong></a>: CLI tool provides great development experience: <ul> <li>framework-independent way to manage the project environment</li> <li>application code <em>hot reload</em></li> <li>robust application templates</li> </ul></li> <li><a href="https://lancetnik.github.io/Propan/getting_started/7_testing"><strong>Testability</strong></a>: <strong>Propan</strong> allows you to test your app without external dependencies: you do not have to set up a Message Broker, you can use a virtual one!</li> </ul></li> </ul> <p><strong>Brian #4:</strong> <a href="https://ricardoanderegg.com/posts/makefile-python-project-tricks/"><strong>Makefile tricks for Python projects</strong></a></p> <ul> <li>Ricardo Ander-Egg</li> <li>A pretty short basic starter template Makefile for Python projects with some cool snippets.</li> <li>Some default settings to have make behave sanely <ul> <li>exit on error, warn about undefined variables, disable built-in rules</li> <li>set up working directory correctly if called from a different dir</li> </ul></li> <li>A <code>$(py)</code> definition that picks up the virtual environment if it’s there.</li> <li>Also <code>$(pip)</code> from the virtual env.</li> <li>Default goal and help message <ul> <li>cool trick so that <code>make</code> with no arguments just prints the help</li> <li>And also picks up target comments as help text for the target. Neat.</li> </ul></li> <li>Injecting paths into PYTHONPATH, and an example on how that works if you need it.</li> <li>A <code>.venv</code> target <ul> <li>create a virtual environment, update setuptools, wheel, build, and install requirments</li> </ul></li> </ul> <p><strong>Extras</strong> </p> <p>Michael:</p> <ul> <li><a href="https://2023.pycon.pt/talks/cfp/">PyCon Portugal CFP</a></li> <li><a href="https://2024.djangocon.eu">DjangoCon 2024</a></li> <li><a href="https://www.apple.com/apple-vision-pro/">Apple Vision Pro</a></li> <li><a href="https://www.duetdisplay.com">Duet App</a></li> </ul> <p><strong>Joke:</strong> <a href="https://www.reddit.com/r/programminghumor/comments/1428piy/new_headsets_announced/">Actual technical people</a></p>
Python Insider
Python 3.11.4, 3.10.12, 3.9.17, 3.8.17, 3.7.17, and 3.12.0 beta 2 are now available
Greetings! Time for another combined release of six separate versions of Python!
Before you scroll away to the download links
Please test the 3.12 beta! Downloading it and trying it out helps us a lot in ensuring Python 3.12.0 will be as polished as possible.
We welcome 3.10 to the prestigious club of security-only releases.
It’s officially an old version of Python now! If you haven’t rewritten
all your if:elif:else:
s with pattern matching yet, are you even still writing Python?
At the same time, it looks like 3.7 is reaching end-of-life. Unless another security release happens in June, 3.7.17 will be the final release of Python 3.7. I mean, now that I typed it out for all you to read, I’m sure I jinxed it. But in case I didn’t, I would like to thank Ned Deily for serving as the release manager of Python 3.6 and Python 3.7. He was my mentor as Release Manager, and continues serving Python as the provider of Mac installers for new releases. Thank you, Ned!
Speaking of installers, Steve Dower used to be the sole provider of
Windows installers for Python releases for years now. His secret was a
well-automated Azure pipeline that let him build, sign, and publish
releases with minimal manual effort. Now he extended the power to press
the blue “Run pipeline” button to more members of the team. Thank you,
Steve! This is an important bus factor increment. In fact, the Windows
installers for both 3.12.0b2 and 3.11.4 were made by me initiated by me. If there’s anything wrong with them, well, I guess that means I pressed the button wrong.
Security fixes in today’s releases
Updating is recommended due to security content:
- 3.7 - 3.12: gh-103142: The version of OpenSSL used in Windows and Mac installers has been upgraded to 1.1.1u to address CVE-2023-2650, CVE-2023-0465, CVE-2023-0466, CVE-2023-0464, as well as CVE-2023-0286, CVE-2022-4303, and CVE-2022-4303 fixed previously in 1.1.1t (gh-101727).
- 3.7 - 3.11: gh-102153:
urllib.parse.urlsplit()
now strips leading C0 control and space characters following the specification for URLs defined by WHATWG in response to CVE-2023-24329. - 3.7 - 3.11: gh-99889: Fixed a security in flaw in
uu.decode()
that could allow for directory traversal based on the input if noout_file
was specified. - 3.7 - 3.11: gh-104049: Do not expose the local on-disk location in directory indexes produced by
http.client.SimpleHTTPRequestHandler
. - 3.7 - 3.11: gh-101283:
subprocess.Popen
now uses a safer approach to findcmd.exe
when launching withshell=True
. - 3.8 - 3.11: gh-103935:
trace.__main__
now usesio.open_code()
for files to be executed instead of rawopen()
. - 3.8 - 3.11: gh-102953: The extraction methods in
tarfile
, andshutil.unpack_archive()
, have a newfilter
argument that allows limitingtar
features than may be surprising or dangerous, such as creating files outside the destination directory. See Extraction filters for details. - 3.9: gh-102126: Fixed a deadlock at shutdown when clearing thread states if any finalizer tries to acquire the runtime head lock.
- 3.9: gh-100892: Fixed a crash due to a race while iterating over thread states in clearing
threading.local
.
Python 3.12.0 beta 2
Get it here: 3.12.0b2
116 new commits since 3.12.0 beta 1.
Python 3.11.4
Get it here: 3.11.4
233 new commits.
Python 3.10.12
Get it here: 3.10.12
Security-only release with no binaries. 20 new commits.
Python 3.9.17
Get it here: 3.9.17
Security-only release with no binaries. 26 commits.
Python 3.8.17
Get it here: 3.8.17
Security-only release with no binaries. 24 commits.
Python 3.7.17
Get it here as it might be the last release of 3.7 ever:
3.7.17
Security-only release with no binaries. 21 commits.
We hope you enjoy the new releases!
Thanks to all of the many volunteers who help make Python Development and these releases possible! Please consider supporting our efforts by volunteering yourself or through organization contributions to the Python Software Foundation.
–
Łukasz Langa @ambv
on behalf of your friendly release team,
Ned Deily @nad
Steve Dower @steve.dower
Pablo Galindo Salgado @pablogsal
Łukasz Langa @ambv
Thomas Wouters @thomas
Python⇒Speed
Understanding CPUs can help speed up Numba and NumPy code
When you need to speed up your NumPy processing—or just reduce your memory usage—the Numba just-in-time compiler is a great tool. It lets you write Python code that gets compiled at runtime to machine code, allowing you to get the kind of speed improvements you’d get from languages like C, Fortran, or Rust.
Or at least, that’s the theory. In practice, your initial Numba code may be no faster than the NumPy equivalent.
But you can do better, once you have a better understanding of how CPUs work. And this knowledge will help you more broadly with any compiled language.
In this article we’ll:
- Consider a simple image-processing problem.
- Try, and initially fail, to speed it up with Numba.
- We’ll review just a little bit how modern CPUs are so fast, and the limits of compilers.
- Based on our new understanding, we’ll then show how we can tweak our code to run 25× faster than our original version.
June 06, 2023
PyCoder’s Weekly
Issue #580 (June 6, 2023)
#580 – JUNE 6, 2023
View in Browser »
Build Your Own Face Recognition Tool With Python
In this tutorial, you’ll build your own face recognition command-line tool with Python. You’ll learn how to use face detection to identify faces in an image and label them using face recognition. With this knowledge, you can create your own face recognition tool from start to finish!
REAL PYTHON
Securing PyPI Accounts via Two-Factor Authentication
PyPI has already added two-factor authentication for high volume projects, but now they’ve announced that all package maintainers must upgrade to 2FA by the end of 2023. This post talks about why the decision was made and what your 2FA options are.
PYPI.ORG
Companies like GitLab, Snowflake, and Slack Scan Their Code for Vulnerabilities Using Semgrep
Scan your code and dependencies for security vulnerabilities for free with Semgrep - the trusted OSS tool used by top companies like GitLab, Snowflake, and Slack. No security expertise needed, simply add your project and let Semgrep do the work in just minutes →
SEMGREP sponsor
Using Kivy for GUI Development
Kivy is an open source Python library for developing desktop and mobile GUI development. It is supported on Windows, Linux, macOS, Android, and iOS. This article introduces you to Kivy and teaches you how to build your first GUI with it.
FRANCIS ALI
Discussions
Articles & Tutorials
Getting Normally Distributed Random Numbers With NumPy
In this tutorial, you’ll learn how you can use NumPy to generate normally distributed random numbers. The normal distribution is one of the most important probability distributions. With NumPy and Matplotlib, you can both draw from the distribution and visualize your samples.
REAL PYTHON
Python 3.13 Removes 20 Stdlib Modules
Core developers are busy working on PEP 594, removing dead batteries from Python 3.13. This long post in the discussion forum highlights what work has been completed so far.
VICTOR STINNER
Write Code as if Failure Doesn’t Exist
Temporal is an open source programming model that can simplify your code, make your applications more reliable, and allow you to deliver more features faster. Check out the Temporal Python SDK Developer’s Guide to learn more and get started →
TEMPORAL sponsor
The Many Problems With Celery
“Celery is the de facto solution for background workers and cron jobs in the Python ecosystem, but it’s full of footguns.” This article describes the problems and offers some solutions.
STEVE DIGNAM
Making the Global Interpreter Lock Optional
Sam Gross has outlined in the past on how to make the GIL optional in CPython. He presented at the Python Language Summit, updating on his progress and future plans in the project.
PYTHON SOFTWARE FOUNDATION
Makefile Tricks for Python Projects
Richard likes using Makefiles. They work great both as simple task runners as well as build systems for medium-size projects. This is his starter template for Python projects.
RICARDO ANDER-EGG AGUILAR
Using pyproject.toml
in Your Django Project
A quick tutorial on how to use a pyproject.toml file inside of your Django projects to specify dependencies.
PETER BAUMGARTNER
Interacting With Kubernetes Using Python
Discover the power of Kubernetes combined with Python! This guide delves into using the Python SDK for interacting with Kubernetes deployments and services.
FAIZANBASHIR.ME • Shared by Faizan Bashir
All of Your Data, from Python or Any Other Application, in Real-Time
Connect, Integrate & Automate your data from any other application or tool in real-time, on-premise or cloud, with simple data access to more than 250 cloud applications and data sources. Learn more at cdata.com
CDATA SOFTWARE sponsor
What Is the Standard Library For?
This posting summarizes a conversation at the Python Language Summit proposing that guidelines be defined for when something should be added to the standard library.
PYTHON SOFTWARE FOUNDATION
Django REST Framework Authentication
Details how to add authentication endpoints to Django REST Framework with django-allauth and dj-rest-auth.
NIK TOMAZIC • Shared by Michael Herman
Projects & Code
Events
LambdaConf, Estes Park, CO
September 16-19, 2023
LAMBDACONF.US • Shared by Agata
STL Python
June 7, 2023
MEETUP.COM
Python Meeting Düsseldorf
June 7, 2023
PYDDF.DE
Python Atlanta
June 8, 2023
MEETUP.COM
PyDay La Paz 2023
June 10 to June 11, 2023
PYLAPAZ.ORG
Happy Pythoning!
This was PyCoder’s Weekly Issue #580.
View in Browser »
[ Subscribe to 🐍 PyCoder’s Weekly 💌 – Get the best Python news, articles, and tutorials delivered to your inbox once a week >> Click here to learn more ]
Real Python
Mazes in Python Part 1: Building and Visualizing
If you’re up for a little challenge and would like to take your programming skills to the next level, then you’ve come to the right place! In this hands-on video course, you’ll practice object-oriented programming, among several other good practices, while building a cool maze solver project in Python.
This is the first part in a two-part series. Throughout the series, you’ll go step by step through the guided process of building a complete and working project. This will include reading a maze from a binary file, visualizing it using scalable vector graphics (SVG), and finding the shortest path from the entrance to the exit.
In part one of the series, you’ll learn how to:
- Use an object-oriented approach to represent the maze in memory
- Visualize the maze and its solution using scalable vector graphics (SVG)
In the next part of the series, you’ll complete the project by creating a binary storage format for mazes and solving mazes using NetworkX.
[ Improve Your Python With 🐍 Python Tricks 💌 – Get a short & sweet Python Trick delivered to your inbox every couple of days. >> Click here to learn more and see examples ]
Mike Driscoll
Announcing The Python Show Podcast
The Python Show Podcast is something that I have thought about creating for several years. I have had several people tell me or ask me if I would do a podcast.
Of course, the problem with creating a podcast is choosing your niche. I don’t want to sound like everyone else. On the other hand, my blog, Mouse vs Python, has been popular and different enough that many people from around the world have found it helpful.
So I decided that I was overthinking things. My passion has been and will continue to be around Python programming. It makes sense for my podcast to also be about Python.
The post Announcing The Python Show Podcast appeared first on Mouse Vs Python.
Stack Abuse
Finding Numbers in Various Data Types in Python
Introduction
When working with Python, we often have to deal with data in the form of numbers or words. Sometimes, words and numbers are stored together, and our needs compel us to separate numbers from words.
In this article, we'll explain how to define words and numbers in Python. Then, we'll see how to separate numbers from words, in case they're stored together, using different methods and in various situations.
Strings, Integers, and Floats in Python
In Python, strings, integers, and floats are fundamental data types used to represent different kinds of values in a program.
Integers represent whole numbers without any decimal part and can be positive or negative. Here's how to define an integer in Python:
# Create a variable expressing an integer number
age = 15
We've created a variable called age
and assigned it the value of 15. To verify the type of a variable in Python, we can use the built-in function type()
. This is how it works:
# Show the type
type(age)
And we get:
int
So, we pass the variable age
to the built-in function type()
and it tells us that this is an integer, as we expected.
To express numbers, we can also use the float type. A float, which is short for floating-point numbers, represents real numbers with decimal points. They are generally suitable for scientific calculations, but not only. Here's how we define a float in Python:
# Create a variable expressing a float number
pi = 3.14
And again, to check the type of our variable:
# Show the type
type(pi)
And we get:
float
Strings are a sequence of characters enclosed in double quotes or single quotes. They are used to store text or, more generally, any kind of characters. This means that a string can even contain numbers, which is the focus of this article. So, for example, a string can be:
# Create a string with my name
my_name = "Federico"
# Show the type
type(my_name)
And we get:
str
But it can also be:
# Create a variable with text and number
federico_car = 'Federico has 1 car'
Finally, pay attention: we said that a string in Python is any character enclosed in quotes. This means that the type of the following:
# Create a string variable expressing a number
age = '15'
is str
.
Now, with this overview in mind, let's see some methods to intercept numbers inside strings.
Methods to Find Numbers in Strings
Let's see an overview of some methods we can use to check if a string contains numbers.
The int() and float() Methods
The easiest ways to transform a string into a number are through the int()
and float()
methods. Let's see how we can use them.
Suppose we expressed our age as a string, but we want it as an integer. We can do it like so:
# Create a string variable expressing an integer number
age = '30'
# Transform string into integer type
age_int = int(age)
# Show type
type(age_int)
And we have:
int
So, we've defined the variable age
as a string. Then, we passed it as the argument of the method int()
and it transformed the string into an integer.
Now, suppose we have expressed a price as a string, but we want to convert it to a float. We can do it like so:
# Create a string variable expressing a decimal number
price = "34.99"
# Transform string to float type
price_float = float(price)
# Show type
type(price_float)
And we have:
float
Similarly, as before, we pass a string to the method float()
and it transforms it into a float.
Now, these methods are easy to use but have a significant limitation: they can convert strings into numbers only if the value inside the quotes is a number. So, to get an understanding, consider the following example:
# Create a string with text and numbers
apples = "21 apples"
# Transform string to integer
apples_converted = int(apples)
# Show type
type(apples_converted)
And we get:
ValueError: invalid literal for int() with base 10: '21 apples'
This error means that we're trying to convert a string to an integer, but the string cannot be parsed as a valid integer. Of course, the same issue occurs if we parse a string containing only text or if we use the float()
method.
Now, a question may arise: what if the text in the string expresses an integer and we want to convert it to a float? And how about vice-versa? Let's examine both scenarios:
# Create a string expressing a decimal
price = "30.5"
# Transform string into an integer
price_int = int(price)
# Show type
type(price_int)
And we get:
ValueError: invalid literal for int() with base 10
So, we have expressed the price of an object as a decimal number (although the type is a string!) and tried to convert it into an integer. This is not possible, as the error indicates.
Now, let's see the other case:
# Create a string expressing an integer
price = "30"
# Transform string into a float
price_float = float(price)
# Show type
type(price_float)
And we get:
float
So, we can convert a string that expresses a whole number into a float. In fact, if we want to see how Python expresses this number as a float, we can print it:
# Print transformed variable
print(price_float)
And, as we might expect, we get:
30.0
Now, these two methods are very basic and have some limitations, as we've seen. This is why we need to learn other methods to solve our problem in more general situations.
The isdigit() Method
The isdigit()
method checks if all the characters in a string are digits (0-9). It returns True
if the string contains only digits, and False
otherwise. So, let's see a couple of examples:
# Create string with text and numbers
letters_and_numbers = "Hello123"
# Create string with only text
letters = "Hello World"
# Create string with only numbers
numbers = "123456"
Now, let's use the isdigit()
method:
# Apply isdigit() method and print
print(letters_and_numbers.isdigit())
print(letters.isdigit())
print(numbers.isdigit())
And we get:
False
False
True
So, to use this method, we write the name of the variable we're verifying and we add .isdigit()
. As we expected, the results show that only the variable numbers
contains characters that are all digits.
This method is good, but we can do better in Python. Listing all the printed values, in fact, may become difficult to read. So, we can improve the above code like so:
# Apply isdigit() method and print, showing variables and results
print(f"Is {letters_and_numbers} an only digit string? {letters_and_numbers.isdigit()}")
print(f"Is {letters} an only digit string? {letters.isdigit()}")
print(f"Is {numbers} an only digit string? {numbers.isdigit()}")
And we get:
Is Hello123 an only digit string? False
Is Hello World an only digit string? False
Is 123456 an only digit string? True
So, inside print()
, we can use f
before the double quotes to insert the variables inside the curly brackets {}
. This allows Python to return the actual value of the variable passed through the curly brackets. Then, knowing that the isdigit()
method returns a boolean (True
or False
), the above code provides more readable results.
Now, it would be beneficial if this method could detect numbers in strings containing both digits and other characters. To achieve this, we can create a function like so:
# Create a function that detects digits in strings
def contains_number(string: str) -> bool:
return any(char.isdigit() for char in string)
Next, we pass the letters_and_numbers
variable to the contains_number()
function and observe the result:
# Invoke the function, passing 'letters_and_numbers' as an argument
contains_number(letters_and_numbers)
And we get:
True
Exactly as we wanted: We were able to intercept digits in a variable that contains different kinds of characters. Now, let's explain this function step by step:
-
def contains_number(string: str) -> bool
means that we are defining a function calledcontains_number()
where we expect the argument, which we generically calledstring
, to be a string (:str
). Then, we know that the function will return a boolean (->bool
). Note that this notation, called "Type Hints", is available from Python 3 onwards, and it is not mandatory. We could have writtendef contains_number(string):
and the function would work correctly. Type Hints are just a useful way to inform the user on what types to expect when dealing with functions (and classes), so it's a kind of "a facilitator". -
Now, let's explain
any(char.isdigit() for char in string)
which is what the function returns. First, we have created a generator expression (a generator is a special type of object in Python that allows us to generate a sequence of values dynamically, without needing to store all the values in memory at once) withchar.isdigit() for char in string
. This generates a sequence of Boolean values, indicating whether each character in the string is a digit. In particular,for char in string
iterates over each characterchar
in the argumentstring
, passed to the function. Then,char.isdigit()
checks if the characterchar
is a digit. Finally, theany()
function is a built-in Python function that takes an iterable as an argument and returnsTrue
if at least one element in the iterable isTrue
. It returnsFalse
if all elements areFalse
. So, in conclusion,any(char.isdigit() for char in string)
evaluates toTrue
if at least one character in the string is a digit, andFalse
otherwise.
Now, let's see other methods.
Using Regular Expressions
Another method we can use to find if a string contains a number is through regular expressions (also called "regex"). Regular expressions are a sequence of characters that help us match or find patterns in text. Here's how we can use this Python module for our purposes:
import re
# Create strings
letters_and_numbers = "Hello123 0.3"
letters = "Hello World"
numbers = "1 2 3 4 5 6 0.5"
# Use regex to intercept numbers and print results
print(bool(re.search(r'\d', letters_and_numbers)))
print(bool(re.search(r'\d', letters)))
print(bool(re.search(r'\d', numbers)))
And we get:
True
False
True
So, first we need to import the re
module to use regular expressions. Then, we can use the re.search()
method for each variable to check for any digits. In regular expressions, \d
represents any digit character. Next, we apply the bool()
method, which returns a boolean value. If there are any digits in the string we are checking, we get True
.
Note that, compared to the previous method, this one identifies numbers without using a function. This method also detects the decimal number in the string letters_and_numbers
, unlike the previous method that only detects digits (numbers from 0 to 9). We'll explain more about this in the next paragraph.
Now, let's examine the last method.
The isnumeric() Method
The isnumeric()
method works exactly like the isdigit()
method: it returns True
if all characters in the string are numbers. The difference between the two is that isnumeric()
can identify a wider range of numbers, such as floats, fractions, superscripts, subscripts, and more. So, if we're aware we're searching for numbers that can be in different forms, then isnumeric()
should be preferred.
On the coding side, we use it similarly to the isdigit()
method. Let's see a simple example:
# Create strings
letters_and_numbers = "Hello123"
letters = "Hello World"
numbers = "1 2 3 4 5 6 0.5"
# Apply isnumeric() method and print results
print(letters_and_numbers.isnumeric())
print(letters.isnumeric())
print(numbers.isnumeric())
And we get:
False
False
True
Now, let's see some more advanced examples we may encounter while programming in Python.
Advanced Manipulation Examples
Now we want to show how we can use the methods we've seen above to intercept numbers in strings in more practical situations, for example when analyzing lists, dictionaries, and data frames.
Finding Numbers in Strings in Lists
Consider we have a list where we have stored some strings containing both numbers and text. We could extract the numbers with regular expressions like so:
import re
# Create a list with strings expressing text and numbers
data = ['I have 10 apples', 'There are 5 bananas', 'I will buy one apple']
# Create a function to retrieve numbers in strings
def extract_numbers(string):
return re.findall(r'\d+', string)
# Iterate over the list, extract numbers, and print results
for string in data:
numbers = extract_numbers(string)
print(f"Numbers in string: {string} - {numbers}")
And we get:
Numbers in string: I have 10 apples - ['10']
Numbers in string: There are 5 bananas - ['5']
Numbers in string: I will buy one apple - []
So, here we report the number associated with the string, if present. The only differences between the previous example on regular expressions are:
- We used
re.findall()
. This method takes two arguments:pattern
andstring
. It searches for all occurrences of thepattern
within thestring
and returns a list of all matched substrings. - In this case, the
pattern
is represented by\d+
, which matches one or more consecutive digits in the string using regex.
So, we have stored numbers and text in some strings in a list called data
. We have created a function called extract_numbers()
that intercepts all the consecutive digits in the string through the method re.findall()
, thanks to regex. We then iterate through the list with a for loop
and invoke the function extract_numbers()
so that all the strings in the list are checked. Then, the code prints the strings themselves and the numbers intercepted (if any).
Finding Numbers in Strings in Dictionaries
Now, suppose we have a shopping list stored in a dictionary where we report some fruit and their respective prices. We want to see if the price is expressed as a number. We can do it like so:
# Create function to intercept numbers in strings
def contains_number(string: str) -> bool:
return any(char.isnumeric() for char in string)
# Create a dictionary
shopping_list = {
'Banana': '1',
'Apple': 'Five',
'Strawberry': '3.5',
'Pear': '3',
}
# Iterate over dictionary and print results
for key, value in shopping_list.items():
if contains_number(value):
print(f"Value for '{key}' contains a number: {value}")
else:
print(f"Value for '{key}' does not contain a number: {value}")
And we get:
Value for 'Banana' contains a number: 1
Value for 'Apple' does not contain a number: Five
Value for 'Strawberry' contains a number: 3.5
Value for 'Pear' contains a number: 3
So, we have created a function contains_number()
as we have seen before, but here we've used the isnumeric()
method (we have a decimal). We then store the prices of some fruits in a dictionary called shopping_list
. With shopping_list.items()
, we access the keys and values of the dictionary, and check if the values are numeric by invoking the function contains_number()
. Finally, thanks to an if
statement, we can separate the strings containing numbers from those containing only text, and print the results.
Finding Numbers in Strings in Pandas Data Frames
In Python, we can store data in data frames, which are collections of columns and rows (similar to Excel sheets, for simplicity). Data frames can be manipulated with a library called pandas
in Python.
Suppose we want to create a column (we call a single column of a data frame a "Pandas series") where we have stored the price of an object from different suppliers on Amazon:
import pandas as pd
# Create dictionary
data = {'Amazon_prices': ['10', '8', '9.2', 'eleven', 'seven']}
# Transform dictionary into data frame
df = pd.DataFrame(data)
# Print data frame
print(df)
And we have:
Amazon_prices
0 10
1 8
2 9.2
3 eleven
4 seven
So, we have stored some data in a dictionary called data
. Then, with the pd.DataFrame()
method, we've converted the dictionary into a Pandas data frame called df
.
At this point, we can use the str.contains()
method from the Pandas library, which is useful for checking patterns in strings. We can use regex to define the pattern like so:
# Intercept numbers in column
numeric_values = df['Amazon_prices'].str.contains(r'\d+', regex=True)
With the above code, we are checking if the column Amazon_prices
contains numbers, thanks to regex. With df['Amazon_prices']
, we are selecting the column of the data frame. Then, the .str.contains()
method checks if we have at least one number in the strings, thanks to regex, as seen before. Finally, the regex=True
activates the use of regex.
We can then create a new column to add to our data frame with the resulting booleans like so:
# Create a new column for data frame
df['IsNumeric'] = numeric_values
So, IsNumeric
is the new column of our data frame, containing the booleans. We can now print the modified data frame with print(df)
and we get:
Amazon_prices IsNumeric
0 10 True
1 8 True
2 9.2 True
3 eleven False
4 seven False
And then, we have a complete overview of the data frame.
Conclusions
In this article, we've seen various methods to determine if there are any numbers in strings, in different cases and situations. We've also demonstrated that there is no one-size-fits-all method; depending on the situation, we have to choose the one that best suits the specific problem we're facing.
Nicola Iarocci
Python `decimal.getcontext` does not work with bpython
I have been working on a side project for which I’m using bpython, a “fancy interface to the Python interpreter.” If you use the Python REPL often, you should check it out. It offers unique features like in-line syntax highlighting, readline-like autocomplete, a “rewind” function to pop the last line of code from memory, auto-indentation and more. Anyway, today I found a bug in bpython, and that’s that Python’s decimal.getcontext() does not work with it.
ListenData
Transformers Agent: AI Tool That Automates Everything
We have a new AI tool in the market called Transformers Agent
which is so powerful that it can automate just about any task you can think of. It can generate and edit images, video, audio, answer questions about documents, convert speech to text and do a lot of other things.
Hugging Face, a well-known name in the open-source AI world, released Transformers Agent that provides a natural language API on top of transformers. The API is designed to be easy to use. With a single line code, it provides a variety of tools for performing natural language tasks, such as question answering, image generation, video generation, text to speech, text classification, and summarization.
READ MORE »June 05, 2023
Ned Batchelder
Multi-syntax configuration examples
Coverage.py reads settings from a number of different files, in either INI-file or TOML syntax, with different section headings depending on the file. This could be confusing: the docs showed the syntax needed for .coveragerc, but if you were using one of the other files, you had to mentally convert from one syntax to another.
To make it easier, I updated the documentation to show all the syntax possibilities when showing examples of configuration files. I used sphinx-code-tabs to create tabbed code sections.
The result looks like this: a three-tabbed code box. The tabs have the names of configuration files. Selecting a tab shows the syntax you need for that particular file:
Originally I wanted to write the settings just once, and use cog to run Python code to convert from INI syntax to TOML.
If you haven’t seen cog before, it lets you insert small chunks of Python into static files. The Python code is executed to generate more static content that appears alongside the Python code. It’s a simple tool that works well when you have a mostly static file, but you want part of it to be computed.
But I sensed that converting between syntaxes be difficult, especially since some of my examples (as the ones above) have comments in them.
So I went with a simpler approach: the Python snippets in the doc files have both INI and TOML chunks. The INI chunk is lightly massaged to make two of the tabs, since they only differ in the section names. To ensure the two input chunks are in sync, the code reads the configuration examples, and checks that the INI and TOML chunks create the same settings values.
This guarantees that the different syntaxes are all valid, both as generic INI or TOML, but also as coverage.py settings. And it guarantees that the two chunks show the same settings, differing only in syntax.
It’s a little bulky in the resulting .rst files, but it provides the reader with the information they need, and it keeps me from making mistakes.
If you want to see the code, the cog code is in cog_helpers.py, and a small example of how it’s used in the documentation is in context.rst.
Stack Abuse
How to Check if a String is Empty or None in Python
Introduction
In Python, it's often important to check whether a string is empty or None
before performing operations on it. This can prevent unexpected errors and make your code more robust. But what is the most efficient and Pythonic way to do this? And what potential pitfalls should you watch out for?
In this article, we'll explore these questions, demonstrating how to correctly check if a string is empty or
None
in Python, as well as discussing some best practices to make your code more reliable and maintainable.
Boolean Evaluation in Python
In Python, values are considered "truthy" or "falsy" based on whether they evaluate to True
or False
in a boolean context. This concept plays a crucial role when checking conditions in code.
For strings, an empty string (""
) is considered "falsy" — it evaluates to False
in a boolean context. On the other hand, a non-empty string is "truthy" — it evaluates to True
. The special value None
is also considered "falsy", as shown in the following code snippet:
s1 = ""
s2 = "Hello"
s3 = None
print(bool(s1)) # False
print(bool(s2)) # True
print(bool(s3)) # False
This property of strings and None
is extremely useful when you want to check if a string is empty or None
. As we'll see in the next sections, you can use simple if statements to make these checks, leveraging the "falsiness" of an empty string and None
.
Checking if a String is Empty
When checking if a string is empty in Python, we can take advantage of the fact that an empty string is "falsy". You can use either the ==
operator or the not
operator to perform this check.
Method 1: Using the ==
Operator
s = ""
if s == "":
print("String is empty")
else:
print("String is not empty")
Method 2: Using the not
Operator
s = ""
if not s:
print("String is empty")
else:
print("String is not empty")
In both of these methods, the if
statement will print "String is empty"
if the string s
is empty. The not
operator in the second example negates the "truthiness" or "falsiness" of the string, making the code slightly more concise. This is a common Pythonic way to check for empty strings.
Checking if a String is None
In Python, to check if a string is None
, it's best practice to use the is
operator rather than the ==
operator. This is because is
checks if both operands are the same object, not just equivalent.
Advice: Read more about the differences between the is
and the ==
operators in our article "'is' vs '==' in Python - Object Comparison".
Let's take a look at the practical use-case of the is
operator for checking if a string is None
":
s = None
if s is None:
print("String is None")
else:
print("String is not None")
As expected, the if
statement will print "String is None"
if the variable s
is None
.
Remember, None
is a singleton in Python, which means there is only ever one instance of None
. Thus, using is
is more appropriate and can be more efficient when checking for None
.
Checking if a String is Empty or None
To check if a string is either empty or None
in Python, we'll combine the techniques we discussed in the previous sections. We'll use an or
operator to check both conditions at once:
s = "" # Try also with s = None
if s is None or s == "":
print("String is empty or None")
else:
print("String is not empty and not None")
Advice: Find out more about the or
operator in Python by reading our "Guide to the Python or Operator".
In this example, the if
statement checks two conditions: if s
is None
and if s
is an empty string. If either condition is true, it will print "String is empty or None"
. If both conditions are false (meaning the string is not None
and it's not empty), it will print "String is not empty and not None"
.
Tips and Advice
Don't use ==
Instead of is
to Check for None
Python has two equality operators, ==
and is
. While they sometimes work the same, they are not identical. The ==
operator checks for value equality, while is
checks for identity, meaning that it checks whether the operands are the same object.
None
is a singleton in Python - there's only one instance of None
. Therefore, it's more appropriate and slightly more efficient to use is
when checking for None
.
s = None
# Recommended
if s is None:
print("s is None")
# Not recommended
if s == None:
print("s is None")
Take Advantage of Python's "Truthiness"
Python's treatment of different values as "truthy" or "falsy" in boolean contexts can simplify your code. Rather than explicitly comparing a string to an empty string (""
), you can use the not
keyword to check if a string is empty:
s = ""
# Recommended
if not s:
print("String is empty")
# Not recommended
if s == "":
print("String is empty")
Handle None
When Performing Operations on Strings
If there's any chance a string could be None
, always check before performing operations on it. Neglecting to do so can result in a TypeError
:
s = None
# Results in TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
print(s + " more text")
To prevent such errors, you can check if the string is None
before performing the operation:
if s is not None:
print(s + " more text")
else:
print("String is None, cannot perform operation")
Conclusion
We've seen that Python provides straightforward and efficient ways to perform these checks, leveraging the "truthiness" and "falsiness" of different values in boolean contexts. We've also discussed some potential pitfalls to avoid and best practices to follow when performing these checks, such as using the is
operator to check for None
and the not
operator to check for an empty string.