Want a #Python datetime? Just invoke datetime.datetime:
dt = datetime.datetime(2026, 4, 1, 13, 18, 20)
str(dt) # '2026-04-01 13:18:20'
Omitted time units are 0:
dt = datetime.datetime(2026, 4, 1, 13)
str(dt) # '2026-04-01 13:00:00'
Latest Posts by Reuven M. Lerner
Do you love analyzing data with #Python and #Pandas?
And have you been following NASA's Artemis II mission?
Then you'll really enjoy tomorrow's Bamboo Weekly!
More info: buff.ly/e6EJcee
Want to compare two #Python datetimes? Just subtract, getting a timedelta:
import datetime
start = datetime.datetime.now()
end = datetime.datetime.now()
delta = end - start
str(delta) # '0:00:04.170916'
delta.seconds # 4
delta.microseconds # 170916
Need the current date and time in #Python?
import datetime
dt = datetime.datetime.now()
str(dt) # "2026-04-05 12:56:22.366545"
dt.year # 2026
dt.date() # datetime.date value
dt.time() # datetime.time value
How much of the world's fertilizer normally passes through the Strait of Hormuz?
And what countries import the most fertilizer from the Persian Gulf?
Check out Bamboo Weekly, with data-analysis challenges using #Python and #Pandas based on current events.
Check it out at buff.ly/e6EJcee
Generate a #Python #Pandas DatetimeIndex of datetime values, specifying the frequency, by passing freq and a code:
pd.date_range(start='2026-03-01', end='2026-05-01', freq='8h')
This returns a 184-element DatetimeIndex with evenly-spaced datetime values in that period.
Generate a #Python #Pandas DatetimeIndex of datetime values with pd.date_range:
pd.date_range(start='2026-03-01', end='2026-05-01', periods=10)
This returns a 10-element series with evenly-spaced datetime values in that period.
The Strait of Hormuz is closed — which, we know, is stopping oil exports.
But a lot of the world's fertilizer also comes from there.
How much? And which countries depend on it?
That's what we analyze, with #Python #Pandas, in the latest Bamboo Weekly!
Check it out: buff.ly/e6EJcee
Have a #Python #Pandas series with datetime values, and want all those until now? Compare with pd.Timestamp.now():
df.loc[ pd.col('when') < pd.Timestamp.now() ]
This returns the rows from df where the "when" column is before now.
Want to check whether a #Python #Pandas series contains another string? Use .str.contains:
df['x'].str.contains('a')
This returns a boolean series, whose index matches that of df.
Keep only those rows containing 'a':
df.loc[ pd.col('x').str.contains('a') ] # Pandas 3 syntax
Keyword-only parameters in a #Python function can have a default:
def myfunc(*, a, b=10):
return f'{a=}, {b=}'
Now call it:
myfunc(a=5) # use the default
myfunc(a=5, b=6) # override the default
Remember: parameters with defaults come *after* those without.
Any #Python function parameters after *args are keyword-only:
def myfunc(*args, k):
return f'{args=}, {k=}'
Want to give k a value? Use a keyword argument:
myfunc(10, 20, 30, k=100)
Don't need *args? Just use *, and k is keyword only:
def myfunc(*, k):
return f'{k=}'
The most important skill when working with AI? Arguing. You'll confirm that the answer is true *and* deepen your understanding:
• Ask follow-ups
• Say "but what about", giving counter examples
• Summarize in your own words — ask if you're right
• Say, "How do you know?"
How to annotate *args in #Python? Just set the elements' type; we know it's a tuple:
def mysum(*args:int) -> int:
total = 0
for n in args:
total += n
return total
Normally, tuples contain different types. In args, we assume all values have the same type.
Classic use of #Python's *args:
def mysum(*args):
total = 0
for n in args:
total += n
return total
Invoke it with separate int arguments:
mysum(10, 20, 30, 40, 50)
and *not* with a list containing ints:
mysum([10, 20, 30, 40, 50]) # Error!
Want your #Python function to take any number of positional args? Use *args:
- Can be any name, but args is traditional
- The * is only in the function definition
- It's a tuple
- Don't grab elements by index; iterate over them
- It might be empty
- Pronounce it "splat args"
Changing your clocks this weekend? Or did you do so a few weeks ago? Or maybe you never do?
In the latest Bamboo Weekly, we use #Python #Pandas to see which countries observe DST, and for how long each year.
Check it out: buff.ly/xH221g4
How are arguments assigned to parameters when calling a #Python function? There are two ways:
- Positional, based on order
- Keyword, i.e., name=value, assigned by name
Want to mix and match? Fine, but all positional must come before all keyword:
myfunc(10, 20, c=30)
To stop people from doing this, lazy import won't be allowed inside functions.
Every import in #Python executes the module, from start to finish.
Meaning? Big modules slow down your program's startup time.
Coming in Python 3.15 this October: "lazy import", which delays the load until a name is used:
lazy import MODULE
lazy from MODULE import NAME
Mutable builtins in #Python cannot be dict keys. But your (mutable) classes can!
class C:
def __init__(self, x):
self.x = x
c = C(10)
d = {c:10} # No error!
print(d[c]) # prints 10
You can't use a list as a #Python dict key:
mylist = ['a', 'b']
d = {mylist: 10} # TypeError!
Why not? Dicts run "hash" on a key to choose a pair's storage location. To avoid pairs getting lost, mutable builtins (list, set, dict) cannot be used as dict keys.
A #Python #Pandas column contains comma-separated values. How can you get the first of those?
First, break each string into a list:
df['x'].str.split(',')
Then use .str[0] to grab the first element from the resulting list:
df['x'].str.split(',').str[0]
Want to check whether a #Python #Pandas string series only contains digits? Use str.isdigit:
df['x'].str.isdigit()
This returns a boolean series, with df's index. You can then convert the digit-containing strings to integers:
df.loc[pd.col('x').str.isdigit(), 'x'].astype(int)
Want to retrieve a slice from a string column in your #Python #Pandas data frame? Use .str.slice:
df['a'].str.slice(1, 10) # or .str[1:10]
df['a'].str.slice(1, 10, 2) # or .str[1:10:2]
df['a'].str.slice(None, 10) # or .str[:10]
df['a'].str.slice(1, None) # or .str[1:]
Want to retrieve from a string column in your #Python #Pandas data frame? Use .str.get:
df['a'].str.get(0) # one character
df['a'].str.get(i) # using an index variable
But wait: You can use [], in place of .get:
df['a'].str[0] # alt syntax!
A recent paper finds that when new albums drop, streaming traffic increases — and so do traffic fatalities. 🤯
In today's Bamboo Weekly, we investigate this data with #Python #Pandas, using a variety of data-analysis techniques — grouping, joins, and datetime values.
Check it out: buff.ly/ZtkMamY
Your #Python #Pandas data frame has a multi-index, and you want to remove one part — not return it to be a regular column? Add drop=True:
df.reset_index(level=1) # index level 1 becomes a column in df
df.reset_index(level=1, drop=True) # index level 1 is removed
Your #Python #Pandas data frame has a multi-index? Return selected parts to columns with the "level" keyword argument:
df.reset_index(level=1) # one column
df.reset_index(level=[0, 2]) # two columns
df.reset_index(level='y') # one column, if named
Yesterday's hands-on Claude+#Python workshop was great!
We built a shell utility, a FastAPI app, and a Discord bot. We discussed generating maintainable code, AI+human interactions, and subagents.
Join my Claude+#Pandas class on March 23 — or ask about doing this at your company: buff.ly/F8fwOC8