Here are some Python techniques, tricks, and tricks that are useful for everyday programming.
We have confirmed the operation with Python 3.8.0
.
1 == 2 == 3 # -> False
1 < 2 < 3 < 4 # -> True
Flexible comparisons are possible thanks to the magic method.
Reference: [Python] Allow comparison operations with your own class
from datetime import date
feb1 = date(2020, 2, 1)
feb2 = date(2020, 2, 2)
feb3 = date(2020, 2, 3)
feb1 < feb2 <= feb2 < feb3 # -> True
from datetime import date
#I intentionally reverse the order
dates = [
date(2020, 2, 3),
date(2020, 2, 2),
date(2020, 2, 1),
]
min(dates) # -> datetime.date(2020, 2, 1)
max(dates) # -> datetime.date(2020, 2, 3)
# Input
from datetime import datetime
start = datetime(2020, 2, 1, 10)
goal = datetime(2020, 2, 3, 12)
t = goal - start
print(f'Your record is{t.days}With the day{t.seconds}Seconds')
# Output
'Your record is 2 days and 7200 seconds'
This is useful when performing date and time-based aggregation.
# Input
from datetime import date
counts = {
date(2020, 2, 1): 0,
date(2020, 3, 1): 0,
}
counts[date(2020, 2, 1)] += 1
counts[date(2020, 2, 1)] += 1
counts[date(2020, 3, 1)] += 1
print(counts)
# Output
{datetime.date(2020, 2, 1): 2, datetime.date(2020, 3, 1): 1}
d = {
'foo': 1,
'bar': 2,
'baz': 3,
}
print('foo' in d) # -> True
d = {
'foo': 1,
'bar': 2,
'baz': 3,
}
print(list(d)) # -> ['foo', 'bar', 'baz']
d = {
'foo': 1,
'bar': 2,
'baz': 3,
}
print(list(d.values())) # -> [1, 2, 3]
d = {
'foo': 1,
'bar': 2,
'baz': 3,
}
for key, value in d.items():
print(key, value)
# Output
foo 1
bar 2
baz 3
# Input
l = [
['Yamada', 'baseball'],
['Tanaka', 'soccer'],
['Sato', 'tennis'],
]
dict(l)
# Output
{'Yamada': 'baseball', 'Tanaka': 'soccer', 'Sato': 'tennis'}
# Input
rows = [
['yamada', 20],
['tanala', 18],
['sato', 18],
]
for name, age in rows:
print(f'{name}Is{age}I'm old')
else:
print('End of introduction')
# Output
'yamada is 20 years old'
'tanala is 18 years old'
'sato is 18 years old'
'End of introduction'
# Input
l = [
['Yamada', 'Taro', 20, 'baseball'],
['Tanaka', 'Jiro', 18, 'circle'],
]
#Extract the beginning
for last_name, *others in l:
print(last_name, others)
print()
#Extract the end
for *others, circle in l:
print(circle, others)
print()
#Extract the first two elements
# (If you don't need other elements, it's Python style to specify a double underscore.)
for last_name, first_name, *__ in l:
print(last_name, first_name)
# Output
Yamada ['Taro', 20, 'baseball']
Tanaka ['Jiro', 18, 'circle']
baseball ['Yamada', 'Taro', 20]
circle ['Tanaka', 'Jiro', 18]
Yamada Taro
Tanaka Jiro
You can also do something like this.
# Input
l = [
['a', 'b', 'c', ['d', 'e', 'f']],
]
for one, *__, (*__, two) in l:
print(one, two)
# Output
a f
# Input
rows = [
['Yamada', 20],
['Tanaka', 18],
['Sato', 16],
]
for i, (name, age) in enumerate(rows, start=1):
print(f'{i}Line:Full name={name},age={age}')
# Output
'The first line:Full name=Yamada,age=20'
'2nd line:Full name=Tanaka,age=18'
'3rd line:Full name=Sato,age=16'
You don't have to write ʻif'key' in dict` every time.
d = {
'Yamada': 20,
'Tanaka': 18
}
d.get('Yamada') # -> 20
d.get('Sato') # -> None
d.get('Sato', 'No age') # -> No age
# Input
def func(a, b, c=None, d=None):
print(a)
print(b)
print(c)
print(d)
l = ['aaa', 'bbb']
d = {'c': 'ccc', 'd': 'ddd'}
func(*l, **d)
# Output
aaa
bbb
ccc
ddd
If all the elements of the array can be evaluated as True, it will return True.
l = [
True,
1,
"foo",
]
all(l) # -> True
l = [
True,
1,
"",
]
all(l) # -> False
If any one of the elements of the array can be evaluated as True, it will return True.
l = [
False,
0,
"foo",
]
any(l) # -> True
l = [
False,
0,
"",
]
any(l) # -> False
In the example below, the computationally expensive process (heavy_task
) is wasted three times.
# Input
def heavy_task(ret):
print(ret)
return ret
if any([heavy_task(True), heavy_task(False), heavy_task(False)]):
print('Complete')
# Output
True
False
False
Complete
In this case it is more efficient to use if.
# Input
def heavy_task(ret):
print(ret)
return ret
if heavy_task(True) or heavy_task(False) or heavy_task(False):
print('Complete')
# Output
True
Complete
# Input
l = ['yamada', 'tanaka', 'yamada', 'sato']
print(set(l))
# Output
{'sato', 'tanaka', 'yamada'}
# Input
l1 = ['yamada', 'tanaka', 'yamada', 'sato']
l2 = ['tanaka']
print(set(l1) & set(l2))
# Output
{'tanaka'}
# Input
l1 = ['yamada', 'tanaka']
l2 = ['yamada', 'sato']
print(set(l1) | set(l2))
# Output
{'sato', 'tanaka', 'yamada'}
# Input
l1 = ['yamada', 'tanaka']
l2 = ['tanaka']
print(set(l1) - set(l2))
# Output
{'yamada'}
The collections
and ʻitertools` packages are useful when you say" This loop processing can be done if you write it honestly, but it is troublesome ... ".
collections.Counter It counts the number of occurrences of elements and sorts them in descending order.
# Input
import collections
l = ['a', 'b', 'c', 'a', 'a', 'c']
c = collections.Counter(l)
print(c.most_common())
# Output
[('a', 3), ('c', 2), ('b', 1)]
collections.defaultdict You can execute processing on an associative array with or without a key.
I don't know what you're talking about, so check out the code example.
# Input
import json
import collections
# defaultdict()Function in the argument of(callable)You can give anything
groups = collections.defaultdict(list)
#If it is an ordinary associative array"There is no key called baseball"Error occurs
groups['baseball'].append('yamada')
groups['tennis'].append('tanaka')
groups['baseball'].append('sato')
print(json.dumps(groups))
# Output
{"baseball": ["yamada", "sato"], "tennis": ["tanaka"]}
The defaultdict is especially useful when creating some sort of aggregation process. The process is simple because you don't have to check the existence of each key.
# Input
import collections
products = ['Note', 'Pencil', 'eraser']
sales = [
['Note', 1],
['eraser', 2],
['eraser', 1],
]
aggregates = collections.defaultdict(int)
for product, cnt in sales:
aggregates[product] += cnt
print('---Today's sales performance---')
for product in products:
print('%s : %d pieces' % (product, aggregates[product]))
# Output
---Today's sales performance---
Note:1 piece
Pencil:0 pieces
eraser:Three
Multiple associative arrays can also be implemented simply by taking advantage of the property that any function (callable) can be passed
.
# Input
import json
from collections import defaultdict
nested = defaultdict(lambda: defaultdict(int))
nested['a']['a'] += 1
nested['a']['a'] += 1
nested['a']['b'] += 1
nested['b']['c'] += 1
print(json.dumps(nested))
# Output
{"a": {"a": 2, "b": 1}, "b": {"c": 1}}
itertools.product It comprehensively generates "combinations" from two or more arrays.
# Input
import itertools
a = ['a1', 'a2']
b = ['b1', 'b2', 'b3']
c = ['c1']
list(itertools.product(a, b, c))
# Output
[('a1', 'b1', 'c1'),
('a1', 'b2', 'c1'),
('a1', 'b3', 'c1'),
('a2', 'b1', 'c1'),
('a2', 'b2', 'c1'),
('a2', 'b3', 'c1')]
itertools.chain.from_iterable It transforms a 2D array into a 1D array (flatten).
# Input
import itertools
l = [
['a1', 'a2'],
['b1', 'b2', 'b3'],
]
list(itertools.chain.from_iterable(l))
# Output
['a1', 'a2', 'b1', 'b2', 'b3']
It provides a virtual object that can be treated like a file.
Useful when writing tests.
# Input
import io
def writer(f, text):
f.write(text)
def printer(f):
print(f.read())
sio = io.StringIO()
writer(sio, 'foo\n')
writer(sio, 'bar\n')
writer(sio, 'baz\n')
sio.seek(0)
printer(sio)
# Output
foo
bar
baz
Tuples
are similar to arrays, but they are immutable and cannot be reassigned.
Because it is immutable, it can be used as an associative array key.
yamada = ('Yamada', 'Taro') #This is a tuple
tanaka = ('Tanaka', 'Jiro') #This is also a tuple
print(yamada[0]) # -> Yamada
yamada[0] = 'Tanaka' # TypeError: 'tuple' object does not support item assignment
ages = {
yamada: 20,
tanaka: 18,
}
print(ages[tanaka]) # -> 18
This characteristic can be used to efficiently group similar data.
# Input
from collections import defaultdict
data = [
{'circle': 'baseball', 'name': 'yamada', 'age': 10},
{'circle': 'baseball', 'name': 'sato', 'age': 10},
{'circle': 'baseball', 'name': 'suzuki', 'age': 11},
{'circle': 'tennis', 'name': 'tanaka', 'age': 10},
]
per_circle_age = defaultdict(list)
for v in data:
k = (v['circle'], v['age']) # (Circle name,age)Generate a tuple called
per_circle_age[k].append(v['name']) #Aggregate using tuples as a key
for (circle, age), members in per_circle_age.items():
print(f'{circle}Belonging to{age}Year-old member:{members}')
# Output
"10-year-old member of baseball:['yamada', 'sato']"
"11-year-old member of baseball:['suzuki']"
"10-year-old member of tennis:['tanaka']"
This is a function that can be used from Python 3.7.
It is convenient because you do not have to write assignment processing such as self.name = name
in the constructor.
import dataclasses
# frozen=True is invariant(immutable)Can be treated as an object
@dataclasses.dataclass(frozen=True)
class User:
last_name: str
first_name: str
def full_name(self):
return f'{self.last_name} {self.first_name}'
yamada = User(last_name='Yamada', first_name='Taro')
tanaka = User(last_name='Tanaka', first_name='Jiro')
yamada.full_name() # -> Yamada Taro
#Can be easily converted to an associative array
dataclasses.asdict(yamada) # -> {'last_name': 'Yamada', 'first_name': 'Taro'}
#Comparison is possible
yamada2 = User(last_name='Yamada', first_name='Taro')
yamada == yamada2 # -> True
yamada == tanaka # -> False
yamada in [yamada2] # -> True
# "frozen=True"If you do, you cannot reassign the value.
yamada.last_name = 'Sato' # -> FrozenInstanceError: cannot assign to field 'last_name'
#Since it is immutable, it can be used as an associative array key.
d = {yamada: 'foo', tanaka: 'bar'}
#Set arithmetic(Set type)Is also possible
{yamada, tanaka} & {yamada2} # -> {User(last_name='Yamada', first_name='Taro')}
Recommended Posts