@treyhunner@mastodon.social
@treyhunner@mastodon.social avatar

treyhunner

@treyhunner@mastodon.social

#Python & #Django educator & team trainer

I help folks sharpen their Python skills with https://PythonMorsels.com🐍🍪

#pythonoddity

Also a #humanist #YIMBY who is attempting more ethical eating (#vegetarian, not yet #vegan) and thinks #economics is highly underrated, but I don't post about those topics very often.

he/him

This profile is from a federated server and may be incomplete. Browse more on the original instance.

treyhunner, to python
@treyhunner@mastodon.social avatar

So lambda expressions allows us to write shorter code by defining a function on the same line that we pass that function to sorted.

Read the full article: What are lambda expressions?
https://trey.io/uuFX1k

treyhunner,
@treyhunner@mastodon.social avatar

@philbetts everything in Python is an object, including functions: https://pym.dev/everything-is-an-object/

There's only one thing we tend to do with function objects (call them).

Though, like any object, we can point variables to functions, including passing them into functions: https://pym.dev/passing-functions-arguments-other-functions/

So all functions can be passed around and all functions only execute when they're called.

That misconception about lambda is one I should probably address in the article. Thanks for nothing it!

treyhunner, to random
@treyhunner@mastodon.social avatar

You know you've been adulting too much when you realize you have strong opinions about the best and worst pieces of hold music. 😬☎️

treyhunner,
@treyhunner@mastodon.social avatar

@sonicrocketman ooh I don't think I've heard that anywhere yet

treyhunner,
@treyhunner@mastodon.social avatar

The worst hold music? CVS pharmacy. It's an unpleasant earworm.

The best hold music? Opus No 1 by Tim Carleton. Yes... I looked up what the music was.

It's apparently the default hold music on Cisco phone systems and was made by a teenager decades ago.

🔊 https://spotify.link/0MSkS51u3Db
📺 https://youtu.be/N7xn5zeJ4D4

treyhunner,
@treyhunner@mastodon.social avatar

@chrisjrn nice! It seems like this episode is the reason the world now knows the source of this hold music.

I don't like this music as much as Dick does in that episode but I do enjoy it much more than most other hold music I've heard.

BajoranEngineer, to random
@BajoranEngineer@mastodon.online avatar

Do yall buy trip insurance?

treyhunner,
@treyhunner@mastodon.social avatar

@sabderemane @BajoranEngineer just echoing to check whether you have travel insurance from your credit card. I didn't realize mine included this until a friend told me.

Chase Sapphire cards, AMEX platinum, and various credit cards from airlines and hotels all include travel insurance.

treyhunner, to python
@treyhunner@mastodon.social avatar

Need to merge two dictionaries together in ?

>>> user = {'name': "Trey", 'website': "https://treyhunner.com/"}
>>> defaults = {'name': "Anonymous User", 'page_name': "Profile Page"}

You'll sometimes see this hack in old code:

>>> merged = dict(defaults, **user)

But that only works if the keys are all strings.

This works (added in Python 3.5):

>>> merged = {**defaults, **user}

But on Python 3.9 and above, this works too!

>>> merged = defaults | user

https://treyhunner.com/2016/02/how-to-merge-dictionaries-in-python/

treyhunner,
@treyhunner@mastodon.social avatar

@JoeP I often need to either:

  1. make a new merged dict because modifying the original dict would globally update configurations of some sort (bad news!)
  2. make a new dict because the original dict is immutable (common with Django QueryDict objects for example).

I agree that using multiple lines isn't bad. But I find this:

merged = defaults | user

A bit more readable than this:

merged = defaults.copy()
merged.update(user)

Readability is in the eye of the beholder though! 👁✨

treyhunner, to python
@treyhunner@mastodon.social avatar

Flattening a list-of-lists (or iterable-of-iterables) in ?

Take your pick.

1️⃣ nested loops

names = []
for g in groups:
for n in g:
names.append(n)

2️⃣ extend in a loop

names = []
for g in groups:
names.extend(g)

or +=:
names += g

3️⃣ comprehension or generator:

names = [
n
for g in groups
for n in g
]

4️⃣ chain.from_iterable

from itertools import chain
names = chain.from_iterable(groups)

More details plus one "bad" way: https://pym.dev/flatten-a-list-in-python/

treyhunner,
@treyhunner@mastodon.social avatar

FYI your question resulted in a "today I learned" moment for me (regarding that append method lookup optimization being irrelevant in Python 3.11+).

Thanks for asking that question @Ollivdb!

https://mastodon.social/@treyhunner/111253097393391216

treyhunner,
@treyhunner@mastodon.social avatar

@Ollivdb @charlotte comprehensions are a bit faster than loops because they're optimized specifically for constructing new lists.

Though that performance difference is likely not very noticeable, even on large amounts of data.

Here's a script to compare loops and comprehensions (ignore the "optimization" for append as it seems to be no faster on newer Python versions): https://pym.dev/p/2wkbs/

treyhunner,
@treyhunner@mastodon.social avatar

@Ollivdb @charlotte If you're really worried about speed, it's usually fastest to use tools with more machinery that's implemented in C.

For example, itertools.chain.from_iterable is a bit faster than a comprehension because it's optimized specifically for flattening:

https://pym.dev/p/2hwud/

treyhunner,
@treyhunner@mastodon.social avatar

@charlotte it can definitely get gnarly.

I always write them over multiple lines because there's no way a double loop comprehension could ever be readable crammed into one line!

treyhunner,
@treyhunner@mastodon.social avatar

@scottmiller42 There's a Python Morsels exercise for that 😊

You're right that a recursive function would do the trick, though you'll need to consider what types of structures you want to flatten and which you don't (e.g. strings are infinitely recursive iterables, so don't try flattening them!)

https://www.pythonmorsels.com/exercises/05fe60de17824ef3ae77d93a3be2e98b/

AlSweigart, to random
@AlSweigart@mastodon.social avatar

deleted_by_author

  • Loading...
  • treyhunner,
    @treyhunner@mastodon.social avatar

    @AlSweigart I have all my curriculum websites setup with CI systems to check for 200 HTTP responses on every URL I reference. At least I'm able to update those URLs when they error (which is frequent).

    If you're publishing a URL in a non-web thing, like a book, you could use a URL shortener that allows URL editing years after the fact, so that you can retroactively update the URL to point to the web archive when the URL breaks.

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Some Morsels exercises were inspired by real problems. 🏗️

    Some help me teach:

    • countdown: a timer I use in EVERY live training
    • vote: count student votes during trainings
    • make_file: used in many exercise test files
    • zero: helps me resize my screen properly

    Some are tools I needed 🧰

    • bullet points: parse WorkFlowy exports
    • dmath: date math CLI
    • reformat_diary: translated OhLife exports
    • reconcile: analyzed finance files
    • jot: my daily journaling
    • plan_meeting: timezones

    treyhunner,
    @treyhunner@mastodon.social avatar

    Writing code that solves a real problem is a great way to deepen your Python skills. 🥅

    But if you don't have a problem that a bit of code would solve, it can be hard to keep up your learning. 🧱

    When you hit a growth wall, try Python Morsels: https://pym.dev 💖

    Already an experienced Python practitioner? ⚗️ Try out a few intermediate or advanced exercises and see what you think. 🎽 There are currently 27 exercises or decorators, descriptors, and metaclasses alone. 🐍🍪

    treyhunner,
    @treyhunner@mastodon.social avatar

    Some Python exercises came from personal need and made feel wizard-like at the time 🧙

    • iospy: spies on stdout & stderr (joint & separately) & stdin
    • replr: save objects from a REPL session & restore a previous session
    • replsync: synchronize state of 2 active Python REPLs

    Those are some of the exercises based on tools I actually used.

    Many exercises are also loosely inspired by the needs of my students' work and some are alternate implementations of third-party tools.

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    The Python Morsels web app & pastebin tool now support Python 3.12: https://www.pythonmorsels.com/history/278/

    Also the solution walk-throughs for all Python Morsels exercises now discuss Python 3.12 features, where relevant.

    Want to try out some interesting Python 3.12 features in your web browser?

    Play with this paste: https://www.pythonmorsels.com/p/2vxxa/

    treyhunner,
    @treyhunner@mastodon.social avatar

    @pamelafox I compile it from source based on some instructions in the cpython repo and a bunch of advice I got from a couple kind Python devs who are much more wasm-smart than I am.

    I've been considering sharing my process but not sure how many folks would actually use it, since using pyodide is likely easier. I don't want the arbitrary JS code execution it allows though.

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    What's a feature you wish existed but doesn't? 🤔

    It can even be something others would think is absurd. 🛸

    Dream big! 💭

    treyhunner,
    @treyhunner@mastodon.social avatar

    @juliangonggrijp I explain my thinking on my preference for comprehensions over the functional-esque approach (in Python specifically) a bit more in these two videos:

    1. On why I avoid map & filter in Python https://www.youtube.com/watch?v=2Gapzc6tpTQ (text version: https://pym.dev/map-and-filter-python/)

    2. On why I avoid reduce https://www.youtube.com/watch?v=yTWGRGlZU08 (text version: https://pym.dev/reduce/)

    I'd never thought of any/all as our version of a find function before today. Thanks for helping me find that analogy!

    treyhunner, to linguistics
    @treyhunner@mastodon.social avatar

    "loanword is a calque and calque is a loanword"

    I'm a sucker for edutainment videos with a clever punchline

    https://www.youtube.com/watch?v=TFpzps-DCb0

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    A context manager class

    class C:
    def init(self, x):
    self.x = x
    def enter(self):
    print("☂️")
    return self # for "as"
    def exit(self, cls, exc, tb):
    print("🌂")

    optionally return truthy value to suppress exception re-raising

    And here's how to use that context manager:

    >>> with C("🥳") as c: # "c" becomes the enter return value
    ... print(c.x)
    ...
    ☂️
    🥳
    🌂

    More:
    https://pym.dev/what-is-a-context-manager/
    https://pym.dev/creating-a-context-manager/

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Dictionary keys and set items must be hashable in .

    But what does "hashable" actually mean?

    And what does hashability actually do for us?

    That's the topic of this week's Python Morsels video.

    https://youtu.be/DKR0-PDWb20?si=gs4x40ABbe1H7duM

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Data read from outside the Python process is read as raw bytes.

    When opening files in text mode, decodes bytes to text using a charcter encoding (utf-8 by default). In many other cases, Python doesn't guess an encoding.

    This week's screencast is on encoding & decoding bytes.

    https://youtu.be/rD4ZXzeoJHo?si=Ydp4SYgC_nU5iQ35

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Does your object have a "length"? 📏

    It might make sense to support the built-in len function.

    You just need a len method! 🪄

    https://youtu.be/vnhDr2Dq4s8?feature=shared

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    In , looping over an iterable one way does the same thing as looping another way.

    >>> name = "Trey"

    Looping with a *:

    >>> print(*name)
    T r e y

    With functions:

    >>> list(name)
    ['T', 'r', 'e', 'y']
    >>> " ".join(name)
    'T r e y'

    With tuple unpacking:

    >>> a, b, c, d = name
    >>> c
    'e'

    When you loop over "object X" one way, you'll see the same behavior when you loop a different way.

    An iterable is an iterable, no matter the form of looping.

    https://www.pythonmorsels.com/iterable/

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    This week's video is on customizing how the == operator works on your Python objects.

    You can use == between any 2 objects in , but "False" will be the typical response.

    You can make a eq method to give your objects a more natural sense of equality. 📐

    https://youtu.be/PYQ8kOVA2zw?feature=shared

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Python sequence shortcuts

    first = seq[0]
    last = seq[-1]

    first_n = seq[:n]
    last_n = seq[-n:]
    middle = seq[1:-1]

    first, *middle, last = seq
    reversed = seq[::-1]

    lazy_reversed = reversed(seq)

    These work on lists, tuples, range objects, and any other list-like object in Python.

    Here's a script that shows off these features: https://pym.dev/p/2e6fc/

    That script demonstrates these sequence features:

    ⭐ Indexing
    ⭐ Slicing
    ⭐ Extended tuple unpacking
    ⭐ Reversing lazily

    treyhunner, to python
    @treyhunner@mastodon.social avatar

    Have a object that you'd like to support index/key lookups (like["this"])?

    Add a getitem method to your class.

    https://youtu.be/R8Gun_58-Nk?si=yi8ANhpOw5VgskkA

  • All
  • Subscribed
  • Moderated
  • Favorites
  • megavids
  • thenastyranch
  • rosin
  • GTA5RPClips
  • osvaldo12
  • love
  • Youngstown
  • slotface
  • khanakhh
  • everett
  • kavyap
  • mdbf
  • DreamBathrooms
  • ngwrru68w68
  • provamag3
  • magazineikmin
  • InstantRegret
  • normalnudes
  • tacticalgear
  • cubers
  • ethstaker
  • modclub
  • cisconetworking
  • Durango
  • anitta
  • Leos
  • tester
  • JUstTest
  • All magazines