There are many articles written Python Many cool features in , For example, unpacking variables 、 Partial function 、 Enumerate iteratable objects , But what about Python There are still many topics to be discussed , So in this paper , I will try to show you something I know and use , But features rarely mentioned in other articles . Let's start .
1、 For the input string “ disinfect ”
User input “ disinfect ”, This question applies to almost all programs you write . It's usually enough to convert characters to lowercase or uppercase , Sometimes you can use regular expressions to do the job , But for complex situations , There's a better way :
user_input = "This\nstring has\tsome whitespaces...\r\n"
character_map = {
ord('\n') : ' ',
ord('\t') : ' ',
ord('\r') : None
}
user_input.translate(character_map) # This string has some whitespaces... "
In this example , You can see the space character “ \n” and “ \t” Replaced by a single space , and “ \r” Is completely deleted . This is a simple example , But we can go further , Use unicodedata Library and its combining() function , To generate a larger remapping table (remapping table), And use it to remove all accents from the string .
2、 Slice iterators
If you try slicing iterators directly , You will get TypeError , The prompt says that the object does not have a subscript (not subscriptable), But there is a simple solution :
import itertools
s = itertools.islice(range(50), 10, 20) # <itertools.islice object at 0x7f70fab88138>
for val in s:
...
Use itertools.islice, We can create one islice object , The object is an iterator , Can generate the content we need . But here's an important reminder , That is, it consumes pre slicing and slicing objects islice All elements in .
3、 Skip the start of an iteratable object
Sometimes you have to deal with certain files , They take a variable number of unwanted rows ( For example, note ) Start with .itertools Once again, it provides a simple solution :
string_from_file = """
// Author: ...
// License: ...
//
// Date: ...
Actual content...
"""
import itertools
for line in itertools.dropwhile(lambda line:line.startswith("//"), string_from_file.split("\n")):
print(line)
This code will only print the content after the initial comment section . If we just want to discard the beginning of the iterator ( In this case, the comment ), And I don't know how much , So this method is very useful .
4、 Only keyword parameters are supported (kwargs) Function of
When you need a function to provide ( mandatory ) Clearer parameters , Create a function that only supports keyword parameters , It might be useful :
def test(*, a, b):
pass
test("value for a", "value for b") # TypeError: test() takes 0 positional arguments...
test(a="value", b="value 2") # Works...
As you can see , Before the keyword parameter , Place a single
Parameter to easily solve this problem . If we put the position parameter in
Before the parameters , Obviously, there can also be position parameters .
5、 Create support with Object of statement
We all know how to use with sentence , For example, open a file or acquire a lock , But can we realize our own ? Yes , We can use __enter__ and __exit__ Method to implement the context manager protocol :
class Connection:
def __init__(self):
...
def __enter__(self):
# Initialize connection...
def __exit__(self, type, value, traceback):
# Close connection...
with Connection() as c:
# __enter__() executes
...
# conn.__exit__() executes
This is Python The most common way to implement context management in , But there's a simpler way :
from contextlib import contextmanager
@contextmanager
def tag(name):
print(f"<{name}>")
yield
print(f"</{name}>")
with tag("h1"):
print("This is Title.")
The above code segment uses contextmanager Decorators implement the content management protocol .tag The first part of the function (yield Before ) Will be entering with Statement is executed , And then execute with Code block for , In the end tag The rest of the function .
5、 use __slots__ Save memory
If you have ever written a program , This program creates a large number of instances of a class , Then you may have noticed that your program suddenly needs a lot of memory . That's because Python Use dictionaries to represent properties of class instances , This makes it faster , But memory is not very efficient . Usually this is not a problem , however , If your program encounters problems , You can try it __slots__ :
class Person:
__slots__ = ["first_name", "last_name", "phone"]
def __init__(self, first_name, last_name, phone):
self.first_name = first_name
self.last_name = last_name
self.phone = phone
What's going on here is , When we define __slots__ Attribute ,Python Use small arrays of fixed size , Not a dictionary , This greatly reduces the memory required for each instance . Use __slots__ There are also some shortcomings —— We cannot declare any new properties , And can only be used in __slots__ Properties in . Again , with __slots__ Class of cannot use multiple inheritance .
6、 Limit CPU And memory usage
If you don't want to optimize program memory or CPU Usage rate , Instead, I want to limit it to a fixed number , that Python There is also a library that can do :
import signal
import resource
import os
# To Limit CPU time
def time_exceeded(signo, frame):
print("CPU exceeded...")
raise SystemExit(1)
def set_max_runtime(seconds):
# Install the signal handler and set a resource limit
soft, hard = resource.getrlimit(resource.RLIMIT_CPU)
resource.setrlimit(resource.RLIMIT_CPU, (seconds, hard))
signal.signal(signal.SIGXCPU, time_exceeded)
# To limit memory usage
def set_max_memory(size):
soft, hard = resource.getrlimit(resource.RLIMIT_AS)
resource.setrlimit(resource.RLIMIT_AS, (size, hard))
ad locum , We can see two options , You can set the maximum CPU Maximum run time and memory usage . about CPU Limit , We first get this particular resource (RLIMIT_CPU) The soft and hard limits of , Then set it by the number of seconds specified by the parameter and the previously obtained hard limit . Last , If exceeded CPU Time , We will register the signal to exit the system . As for memory , We get soft limits and hard limits again , And use with size Parametric setrlimit And get the hard limit to set it .
8、 Control can import The content of
Some languages have very obvious for exporting Members ( Variable 、 Method 、 Interface ) The mechanism of , for example Golang, It only exports members that start with capital letters . On the other hand , stay Python in , Everything will be exported , Unless we use __all__ :
def foo():
pass
def bar():
pass
__all__ = ["bar"]
Use the code snippet above , We can limit from some_module import * Contents that can be imported during use . For the above example , Only... Will be imported during general configuration import bar. Besides , We can __all__ Set to null , Make it impossible to export anything , And when you import from this module using wildcards , Will lead to AttributeError.
9、 A simple way to compare operators
Implementing all comparison operators for a class can be annoying , Because there are many comparison operators ——__lt__、__le__、__gt__ or __ge__. however , If there is a simpler way ?functools.total_ordering Salvable site :
from functools import total_ordering
@total_ordering
class Number:
def __init__(self, value):
self.value = value
def __lt__(self, other):
return self.value < other.value
def __eq__(self, other):
return self.value == other.value
print(Number(20) > Number(3))
print(Number(1) < Number(5))
print(Number(15) >= Number(15))
print(Number(10) <= Number(2))
How does this work ?total_ordering Decorators are used to simplify the sorting process for our class instances . Just define __lt__ and __eq__, This is the minimum requirement , The decorator will map the remaining operations —— It fills the gap for us .
10、 Use slice Function name slice
Using a large number of hard coded index values can quickly confuse maintainability and readability . One approach is to use constants for all index values , But we can do better :
# ID First Name Last Name
line_record = "2 John Smith"
ID = slice(0, 8)
FIRST_NAME = slice(9, 21)
LAST_NAME = slice(22, 27)
name = f"{line_record[FIRST_NAME].strip()} {line_record[LAST_NAME].strip()}"
# name == "John Smith"
In this case , We can avoid the mysterious index , The way is to use slice Function names them , And then use them . You can also pass .start、.stop and .stop attribute , To get to know slice More information about the object .
11、 Prompt the user for a password at run time
Many command-line tools or scripts require a user name and password to operate . therefore , If you happen to write such a program , You might notice getpass Modules are very useful :
import getpass
user = getpass.getuser()
password = getpass.getpass()
# Do Stuff...
This very simple package extracts the login name of the current user , You can prompt the user for a password . But be careful , Not every system supports hidden passwords .Python Will try to warn you , So remember to read the warning message on the command line .
12、 Find words / Close matching of strings
Now? , About Python Some obscure features in the standard library . If you find yourself needing to use Levenshtein distance 【2】 Things like that , To find similar words in some input strings , that Python Of difflib Will support you .
import difflib
difflib.get_close_matches('appel', ['ape', 'apple', 'peach', 'puppy'], n=2)
# returns ['apple', 'ape']
difflib.get_close_matches Will find the best “ Good enough. ” The matching of . ad locum , The first parameter matches the second parameter . We can also provide optional parameters n , This parameter specifies the maximum matching results to return . Another optional keyword parameter cutoff ( The default value is 0.6), You can set the threshold of string matching score .
13、 Use IP Address
If you have to use Python Do network development , You might notice ipaddress Modules are very useful . One scenario is from CIDR( Classless inter domain routing Classless Inter-Domain Routing) Generate a series of IP Address :
import ipaddress
net = ipaddress.ip_network('74.125.227.0/29') # Works for IPv6 too
# IPv4Network('74.125.227.0/29')
for addr in net:
print(addr)
# 74.125.227.0
# 74.125.227.1
# 74.125.227.2
# 74.125.227.3
# ...
Another nice feature is to check IP Network membership for addresses :
ip = ipaddress.ip_address("74.125.227.3")
ip in net
# True
ip = ipaddress.ip_address("74.125.227.12")
ip in net
# False
There are many interesting features , ad locum 【3】 Can find , I won't go back to . But notice ,ipaddress There is only limited interoperability between the module and other network related modules . for example , You can't put IPv4Network The instance is treated as an address string —— You need to use it first str Convert them .
14、 stay Shell Debugger crash in
If you are one who refuses to use IDE, And in Vim or Emacs People who code in , Then you may encounter such a situation : Owned in IDE A debugger like the one in would be useful .
You know what? ? You have one —— Just use python3.8 -i Run your program —— Once your program terminates , -i Will start interactive shell, There you can view all variables and call functions . Clean and tidy , But use the actual debugger (pdb ) How will? ? Let's use the following procedure (script.py ):
def func():
return 0 / 0
func()
And use python3.8 -i script.py Run script :
# Script crashes...
Traceback (most recent call last):
File "script.py", line 4, in <module>
func()
File "script.py", line 2, in func
return 0 / 0
ZeroDivisionError: division by zero
>>> import pdb
>>> pdb.pm() # Post-mortem debugger
> script.py(2)func()
-> return 0 / 0
(Pdb)
We saw the place of collapse , Now let's set a breakpoint :
def func():
breakpoint() # import pdb; pdb.set_trace()
return 0 / 0
func()
Now run it again :
script.py(3)func()
-> return 0 / 0
(Pdb) # we start here
(Pdb) step
ZeroDivisionError: division by zero
> script.py(3)func()
-> return 0 / 0
(Pdb)
Most of the time , Printing statements and error messages is enough for debugging , But sometimes , You need to grope around , To understand what is happening inside the program . In these cases , You can set breakpoints , Then the program will stop at the breakpoint as it executes , You can check the program , For example, list function parameters 、 Expression evaluation 、 List variables 、 Or as shown above, only one step is performed .
pdb It's fully functional Python shell, In theory you can do anything , But you also need some debugging commands , Here 【4】 find .
15、 Define multiple constructors in a class
Function overloading is a programming language ( Not included Python) Very common features in . Even if you can't overload normal functions , You can still use class methods to overload constructors :
import datetime
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
@classmethod
def today(cls):
t = datetime.datetime.now()
return cls(t.year, t.month, t.day)
d = Date.today()
print(f"{d.day}/{d.month}/{d.year}")
# 14/9/2019
You might prefer to put all the logic that replaces the constructor into __init__, And use
args 、
*kwargs And a bunch of if sentence , Instead of using class methods to solve . That might work , But it becomes difficult to read and maintain .
therefore , I suggest putting very little logic into __init__, And in a separate way / Constructor to perform all operations . such , For maintainers and users of classes , All you get is clean code .
16、 Use decorator to cache function calls
Have you ever written a function , It performs expensive I/O Operation or some fairly slow recursion , And the function may benefit from caching its results ( Storage )? If you have , So there is a simple solution , That is to use functools Of lru_cache :
from functools import lru_cache
import requests
@lru_cache(maxsize=32)
def get_with_cache(url):
try:
r = requests.get(url)
return r.text
except:
return "Not Found"
for url in ["https://google.com/",
"https://martinheinz.dev/",
"https://reddit.com/",
"https://google.com/",
"https://dev.to/martinheinz",
"https://google.com/"]:
get_with_cache(url)
print(get_with_cache.cache_info())
# CacheInfo(hits=2, misses=4, maxsize=32, currsize=4)
In this case , We used cacheable GET request ( most 32 Cached results ). You can also see , We can use cache_info Method to check the cache information of a function . The decorator also provides clear_cache Method , Used to invalidate cached results .
I would also like to point out that , This function should not be used with functions that have side effects , Or with functions that create mutable objects every time they are called .
17、 Find the most frequent element in an iteratible object
Finding the most common elements in a list is a very common task , You can use for Loops and dictionaries (map), But this is not necessary , because collections There is Counter class :
from collections import Counter
cheese = ["gouda", "brie", "feta", "cream cheese", "feta", "cheddar",
"parmesan", "parmesan", "cheddar", "mozzarella", "cheddar", "gouda",
"parmesan", "camembert", "emmental", "camembert", "parmesan"]
cheese_count = Counter(cheese)
print(cheese_count.most_common(3))
# Prints: [('parmesan', 4), ('cheddar', 3), ('gouda', 2)]
actually ,Counter Just a dictionary , Map elements to occurrences , So you can use it as a general dictionary :
python print(cheese_count["mozzarella"]) ¨K40K cheese_count["mozzarella"] += 1 print(cheese_count["mozzarella"]) ¨K41K
besides , You can still use it update(more_words) Method to easily add more elements .Counter Another cool feature of is that you can use mathematical operations ( Add and subtract ) To combine and subtract Counter Example .
Summary
In daily life Python Programming , Not all of these features are essential and useful , But some of these features may come in handy from time to time , And they can also simplify tasks , This could have been tedious and annoying .
I would also like to point out that , All of these features are Python Part of the standard library , Although in my opinion , Some of these features are very much like non-standard content in the standard library . therefore , Whenever you want to be in Python When some functions are implemented in , First, you can view it in the standard library , If you can't find it , Then you may not have looked carefully enough ( If it does not exist , So it must be in some third-party libraries ).
If you use Python, So I think most of the techniques shared here will be useful almost every day , So I hope they will come in handy . in addition , If you're right Python Tips and tricks have any idea , Or if you know a better way to solve the above problems , Please tell me !
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing