Skip to content

Conversation

@petrem
Copy link
Contributor

@petrem petrem commented Dec 21, 2025

  • Renamed chr to char in the snippets because chr is a built-in function and although shadowing it in this case may not be a problem, it is still a bad practice when it can be avoided.
  • The dictionary-join approach mentions list comprehensions, but instead it uses a generator expression. Replaced this in the explanation and expanded to give the list comprehension based implementation along with a brief comparison.
  • The overview mentions one approach is four times faster. In a brief comparison, it varies from 2.5x for a very short string and up to 60x faster for a 10^6 long one. Probably not worth going into the details, but 4x is just innacurate.

I noticed that the maketrans based approach mentions the translation is done between ASCII ordinal values. This happens to be true because the characters involved are ASCII letters, but the functions deal with unicode ordinals.

Do you think this is worth mentioning?

@BethanyG
Copy link
Member

BethanyG commented Dec 21, 2025

Hi there @petrem! Thanks so much for this. I haven't taken a close look yet...but wanted to reply to your message/questions first.

Renamed chr to char in the snippets because chr is a built-in function and although shadowing it in this case may not be a problem, it is still a bad practice when it can be avoided.

Good call. Shadowing is just something to avoid, generally. Unless of course you program in a language where its SOP for some reason. I would probably go even further and just name it character - but I'm fine with char too.

The dictionary-join approach mentions list comprehensions, but instead it uses a generator expression. Replaced this in the explanation and expanded to give the list comprehension based implementation along with a brief comparison.

I might go even further here and talk a little about how generator expressions avoid excess memory by not creating values in a list in memory and instead yielding values at runtime. The downside being that once consumed, a generator cannot be "re-run". They can also (paradoxically seeming) be slower, depending on the data and the expression.

However, list comprehensions (or any concrete comprehension) do create their values in memory, which might quickly become a no-op when processing large amounts of data.

For the size of data we're talking about in this exercise, its not terribly important - but worth discussing.

The overview mentions one approach is four times faster. In a brief comparison, it varies from 2.5x for a very short string and up to 60x faster for a 10^6 long one. Probably not worth going into the details, but 4x is just inaccurate.

I don't know if you took a look at the performance article/benchmarks, but the info likely comes from there. And as you are probably well aware, accurate benchmarking is complicated and also highly dependent on hardware. The best you can do is be really honest about how you crafted the benchmark and what hardware was used. I'd love if someone did a quick once-over of the performance stuff .. and if it is just horrid, we should probably remove the mention of 4x or do the range you pointed out. But yeah, I was not really a fan of the perf stuff from this author, but was sort of in a position where I had to approve the PR.

I noticed that the maketrans based approach mentions the translation is done between ASCII ordinal values. This happens to be true because the characters involved are ASCII letters, but the functions deal with unicode ordinals.

Do you think this is worth mentioning?

Yes. If you have the energy and interest, it is well worth mentioning. Python claims to be UTF-8 first and full able to process Unicode. So students should be aware of how that happens.

@BethanyG
Copy link
Member

Just took a deeper look, and I don't have any nits at the moment beyond the one found by @BNAndras. 😄 But will wait to merge in case you have additions after my comments above. 🎉

@@ -5,7 +5,7 @@ LOOKUP = {"G": "C", "C": "G", "T": "A", "A": "U"}


def to_rna(dna_strand):
return ''.join(LOOKUP[chr] for chr in dna_strand)
return ''.join(LOOKUP[char] for char in dna_strand)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using "character" as a full word is better than using "char" as an abbreviation, especially since it is also a full word on its own. And there are very few abbreviations in this document, other than the defined in context dna/DNA and rna/RNA of the subject matter. That is a good thing.

@petrem
Copy link
Contributor Author

petrem commented Dec 21, 2025

Thank you. I'll make some updates tomorrow (ASCII/unicode and perhaps take another look at the list comprehension vs generator expression).

would probably go even further and just name it character - but I'm fine with char too.

I was actually tempted to name it nucleotide, I wonder if you (plural) think that would be a good idea, too?

@BethanyG
Copy link
Member

I was actually tempted to name it nucleotide, I wonder if you (plural) think that would be a good idea, too?

I like that. 😄

@kotp
Copy link
Member

kotp commented Dec 21, 2025

would probably go even further and just name it character - but I'm fine with char too.

I was actually tempted to name it nucleotide, I wonder if you (plural) think that would be a good idea, too?

Exactly, using language at the problem being solved (domain language) is definitely good for showing intent in the reading of the code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[approach-dictionary-join]: https://exercism.org/tracks/python/exercises/rna-transcription/approaches/dictionary-join

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for blank line at the end of markdown/asciidoc files is that when processing, you end up with a blank line between the sources, which is generally intended. That is to say that the final line of a document of this type is typically terminated as \n\n.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd personally make the processing ensure the blank line when stitching, but I see your point. Should this apply also to the conent.md files, @kotp ?

Copy link
Member

@BethanyG BethanyG Dec 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd personally make the processing ensure the blank line when stitching, but I see your point. Should this apply also to the conent.md files, @kotp ?

This is not me trying to be a jerk .... seriously. But as the maintainer of this track - I heartily agree @petrem - I would strongly prefer to find a programmatic way of auditing/introducing things like file-terminating \n\n (pre-commit hooks, CI, auto-formatting, linting, etc.), and not drag that requirement into manual PR reviews right now.

Fixing typos, syntax errors, and roadblocks to student understanding feel more urgent. As does adding in approaches that are important but missed and adding approaches for exercises that don't have them.

Since I am upgrading things in general, I can take a renewed look at things like Prettier, Black, Yapf, and other tools to do some markdown linting and auto-formatting. Last time I took a look at these they weren't great ... but it's worth the time to revisit. Let's not worry too much about it right now. We can fix it where we see it, but let's not go hunting. 🙂

We just have too many docs in the repo, and manually going back over everything is a nightmare.

BethanyG and others added 21 commits December 23, 2025 00:44
* bitwise-operators concept

* small fizes to about.md

* Proposed Edits and Links

First draft of edits and links for Bitwise operations.

* Typos and Review Changes

---------

Co-authored-by: BethanyG <[email protected]>
…ism#3583)

* [Leap]: Add `calendar-isleap` approach and improved benchmarks

* added comments on `isleap()` implementation and operator precedence

* Approach and Chart Edits

Various language edits and touchups.

Added chart reference and alt-textm as well as link to long description.  Probably unnecessary for this particular article but wanted to establish an example of what to do when alt-texting a chart.  See https://www.w3.org/WAI/tutorials/images/complex/ for more information and examples on how to alt-text complex images.

* Fixed Awkward Chart Intro

* Another try on alt-text

* Trying Yet Again

* Attempt to align figcaption

* Giving up and going for description location in alt

---------

Co-authored-by: BethanyG <[email protected]>
* Update content.md remove <p> tag from around svg image

Noticed after the push that the image was showing as broken on dark theme.  Hoping this helps.

* Update content.md

put whole tag on one line, in case that makes a difference.
…tch Graph. (exercism#3593)

* Updated table with newer timings to match graph.

* Apply suggestions from code review

Further adjustment to the numbers.  _sigh_
Small typo on the intro to the exercise "meltdown mitigation"
* Sync the `reverse-string` exercise's docs with the latest data.

* Sync the `reverse-string` exercise's metadata with the latest data.
* [Pythagorean Triplet]: Approaches Draft

* [Leap]: Add `isleap` approach and improved benchmarks

* Delete exercises/practice/leap/.articles/performance/timeit_bar_plot.svg

Sorry, I committed this to the wrong branch. Embarrassingly amateurish!

* Suggestions, Edits, etc.

Suggestions and edits.
Because we need to PR to a different repo, the `.svg` images have been removed, and the text adjusted.

---------

Co-authored-by: BethanyG <[email protected]>
…ercism#3600)

* [Currency Exchange]:  Update stub with Module Docstring

Sub file was missing a docstring and tripping a "missing module docstring" warning in the Analyzer.

* [Currency Exchange]: Update exemplar.py

Added same docstring to exemplar file that was added to the stub file.

* Update exchange.py removed numeric stack doc

* Update exemplar.py 

Removed numeric stack doc.

[no important files changed]
Changed version from Python `3.11.2` to `3.11.5`
…ve Exercise Directory (exercism#3603)

* Marked parallel-letter-frequency as foregone.

* Removed string-formattig prerequisites and set dict-methods live to students.

* Added parallel-letter-frequency back into depricated array.

* Removed parallel-letter-frequency exercise directory.
A few instructions missed additional parameter in function declaration. Added.
Bumps [juliangruber/read-file-action](https://github.com/juliangruber/read-file-action) from 1.1.6 to 1.1.7.
- [Release notes](https://github.com/juliangruber/read-file-action/releases)
- [Commits](juliangruber/read-file-action@02bbba9...b549046)

---
updated-dependencies:
- dependency-name: juliangruber/read-file-action
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…`math.remainder()`, `%` & `operator.modulo` (exercism#3611)

* Added refences for divmod, fmod, remainder, modulo and operator.modulo

* Added comma on line 6 for clarity.
BethanyG and others added 14 commits December 23, 2025 00:44
…ty" on line 15 of Instructions (exercism#3993)

* Corrected critical to balanced in criticaltiy on line 15 of intructions.

* Corrected docstring to refer to balanced in criticality.
New tests were added and solutions need to be re-run.
…ded an Additional Hint. (exercism#3995)

* Fixed up code examples for join and added an additional hint.

* Touched up hints phrasing, added no loop directive to instructions, and added additional examples to concept about.

* Typo correction.

* Corrected separator misspelling.

* Cleaned up in-line comments per PR review.

* Fixed capitalization on inline comments in last join example.
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 5.6.0 to 6.0.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@a26af69...e797f83)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/stale](https://github.com/actions/stale) from 9.1.0 to 10.0.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](actions/stale@5bef64f...3a9db7e)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…xercism#4009)

* Fix possessive 'its' spelling in documentation and tests
* Corrected 'possibly' to 'possible
* Revert "Corrected 'possibly' to 'possible"
This reverts commit 9a42041.
* revert: changes in reference/ folder

[no important files changed]
…ism#4010)

* Update introduction.md
Fixed a typo for better readability.

* Updated Dicts concept about.md
Made same spelling change to the concept about.md, which uses the same code examples.

---------

Co-authored-by: BethanyG <[email protected]>
This commit will:
- Fix the typo "lean" to "learn"
Bumps [actions/checkout](https://github.com/actions/checkout) from 5.0.0 to 6.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](actions/checkout@08c6903...1af3b93)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/setup-python](https://github.com/actions/setup-python) from 6.0.0 to 6.1.0.
- [Release notes](https://github.com/actions/setup-python/releases)
- [Commits](actions/setup-python@e797f83...83679a8)

---
updated-dependencies:
- dependency-name: actions/setup-python
  dependency-version: 6.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [actions/stale](https://github.com/actions/stale) from 10.0.0 to 10.1.0.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](actions/stale@3a9db7e...5f858e3)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-version: 10.1.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
…sm#4051)

* robot-name approach: fix typos, minor rephasing/improvements

- Fixed a few typos.
- Rephrased here and there where I subjectively thought it useful. Please let me know if
 they're undesirable.
- Expanded some contractions - this might help non-native speakers.
- When another approach is mentioned, added link to it - hopefully this is useful rather
  than an distraction
- I thought the explanation about the alternative to using the walrus operator was not
  clear, so rephrased and added a code snippet. I hope this is useful.

* Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/name-on-the-fly/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/name-on-the-fly/content.md

Co-authored-by: BethanyG <[email protected]>

* Update exercises/practice/robot-name/.approaches/mass-name-generation/content.md

Co-authored-by: András B Nagy <[email protected]>

* blank lines after headers and remove trailing whitespace

* add blank lines around code snippets and expand one more contraction

---------

Co-authored-by: BethanyG <[email protected]>
Co-authored-by: András B Nagy <[email protected]>
- Replaced `char` with `nucleotide` as this is terminology from the domain.
- Rephrased a "see also" link to be more screen reader friendly.
- A note about the exercise not requiring tests for invalid characters is preset in one
  of the approaches. Copied it over to the other approach, for uniformity.
- Rephrased mention about performance and speedup.
- Replaced mention of ASCII with Unicode adding a brief explanation and links.
@petrem petrem requested a review from a team as a code owner December 22, 2025 22:45
@petrem
Copy link
Contributor Author

petrem commented Dec 22, 2025

Oh boy. I messed up my branches. Sorry about that :-(
I'm afraid we should discard this PR and create clean new one.

@BethanyG
Copy link
Member

BethanyG commented Dec 23, 2025

Oh Nos! My empathy for you: I often screw up branches, so I know what that feels like! Go ahead and open a new PR, and then link to this one so we don't lose the discussion. Ping me here, on Discord or on the forum when you are ready for review.

See my updated comment below.....I think I managed to fix this!

@BethanyG
Copy link
Member

BethanyG commented Dec 23, 2025

Closing this per @petrem note above. Can you also please remove the codeowners/admin review? That is going to ping Jermey and Erik, and that's not really necessary here (unless you'd like them to do some sort of rollback or other admin-only action).

@BethanyG BethanyG closed this Dec 23, 2025
@BethanyG
Copy link
Member

Reopening to see if I can fix this.

@BethanyG BethanyG reopened this Dec 23, 2025
@BethanyG
Copy link
Member

BethanyG commented Dec 23, 2025

Alright @petrem - I've managed to drop all the other commits you picked up, and so now there are only 4 changed files. The bad news? I had to do a merge commit for the rebase, so now we have that long horrid list of commits in the history - along with you being on them as co-author. But I think we're out of the woods (and I think if we squash on merge we'll get that long list suppressed), should you want to continue with this PR rather than opening a new one. 😄

@petrem
Copy link
Contributor Author

petrem commented Dec 23, 2025

Sorry to have put you trough the trouble. I don't even know how I got here which makes it worse. Usually I simply use git cli but I don't find anything suspicious in the history. Must've done something really stupid in the editor <:-|

It's still a mess (that I've created) so I'd prefer to start afresh, if that's OK? Or perhaps there's something I'm missing and it's better to continue here, in that case, that's also fine.

With my last commit I think I've implemented all changes/suggestions. I've also copied a note over from one approach to the other. This would apply to any approach, so maybe it should be moved to the introduction?

@BethanyG
Copy link
Member

BethanyG commented Dec 23, 2025

Hi @petrem - apologies for not replying earlier. I am in PST, and went to bed on the early side last night. 🙂

It's still a mess (that I've created) so I'd prefer to start afresh, if that's OK? Or perhaps there's something I'm missing and it's better to continue here, in that case, that's also fine.

If you are more comfortable restarting, let's do that. I think the only issue is that this PR has quite a bit of discussion on it, so we lose that direct link. But as long as you reference & link to this PR in your new one, I think we'll be fine. 😄

I don't even know how I got here which makes it worse. Usually I simply use git cli but I don't find anything suspicious in the history. Must've done something really stupid in the editor <:-|

Having just played with the gh cli last night (it was the only way to edit the PR branch without creating a new one), I think what happed was a gh pr update-branch that was done directly from the repo (not your fork), and was missing the --rebase flag. So it pulled in the last year's worth of changes on main, and merged them to your branch as "new" commits. But I don't know for sure. 😱

My typical workflow for anything I do on the track is:

TL;DR? Always pull in all upstream changes before branching to do work. 😄

  1. Switch to my local main, and do a git fetch --all to pull down all new refs. I have remotes set for the repo (upstream) and my fork (origin).
  2. Once the refs download, I do a git rebase upstream/main, which replays my local main onto the fetched one. (e.g. it updates my main with all pulled in changes)
  3. After rebase, I check the status, and if needed, I push my local main changes to my fork (origin).
  4. Once main has been updated, I checkout and update the branch via git rebase main - although typically, I am doing the update before starting work, so instead of rebasing a branch I am creating one via git checkout -b <branch name>.
  5. Once done with branch work, I do a git push, which updates my fork (origin). From there, GH flags the change and the web interface asks if I want to PR to upstream. If I've already PR'd, the upstream branch is updated automatically.

All that doesn't guarantee I won't screw something up royally (I have a talent). And if I do mess up, oh shit, git is usually my very first stop, followed by increasingly hysterical googling. 😆

So - no harm, no foul! I appreciate all the work and am happy to have you re-do the PR. 💙

With my last commit I think I've implemented all changes/suggestions. I've also copied a note over from one approach to the other. This would apply to any approach, so maybe it should be moved to the introduction?

Yes - I'd move the note to the introduction if it applies generally. 😄 And YAY! For finishing things up. I look forward to your PR. Hope all the shenanigans didn't scare you off!

... because it applies to the exercise in general, not a particular approach.
@petrem
Copy link
Contributor Author

petrem commented Dec 23, 2025

Hi @BethanyG ,

To quote you, TL;DR -- I moved the note to introduction.md. If you can get rid of the commits during squash, and can do that without wasting hours, I'm fine. If not, I'll start a new branch and I can attempt to cherry-pick so that I preserve the authors/co-authors. Please let me know your preference. Thank you for your patience.

apologies for not replying earlier. I am in PST, and went to bed on the early side last night. 🙂

No need to apologise. I'm in EET (as in UTC+2), so we'll inevitably have delays.

If you are more comfortable restarting, let's do that. I think the only issue is that this PR has quite a bit of discussion on it, so we lose that direct link. But as long as you reference & link to this PR in your new one, I think we'll be fine. 😄

Oh yes. Plus the commits directly made from suggestions from all the helpful people. If you can clean it up on squash without messing up the history, and without losing hours, I'm fine. I just don't like leaving a mess after me.

Having just played with the gh cli last night (it was the only way to edit the PR branch without creating a new one), I think what happed was a gh pr update-branch that was done directly from the repo (not your fork), and was missing the --rebase flag. So it pulled in the last year's worth of changes on main, and merged them to your branch as "new" commits. But I don't know for sure. 😱

I'm not familiar with gh cli, and not too familiar with fork workflows either. So I appreciate your input.

My typical workflow for anything I do on the track is:
TL;DR? Always pull in all upstream changes before branching to do work. 😄
[...]

Thanks for sharing that! I do a variation of that so at least that's reassuring. There are some differences that I will look into.

I did update my main, but as I work off a branch rather than directly on main, I thought it'll be safe. And I guess then I somehow managed to pull/rebase/merge my origin/main on the local branch.

With my last commit I think I've implemented all changes/suggestions. I've also copied a note over from one approach to the other. This would apply to any approach, so maybe it should be moved to the introduction?
Yes - I'd move the note to the introduction if it applies generally. 😄

Will do. Done.

And YAY! For finishing things up. I look forward to your PR. Hope all the shenanigans didn't scare you off!

I'll be fine, I've done much worse. Let me just say clinical data and production database (all was well in the end, patients safe, just aged an year or two in the hour that I fixed it 😆 ).

Copy link
Member

@BethanyG BethanyG left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work, @petrem 🎉

I am ready to merge this unless @BNAndras & @kotp - either of you have additional comments or thoughts?

A variant that uses a list comprehension is almost identical, but note the additional square brackets inside the `join()`:

```python
LOOKUP = {"G": "C", "C": "G", "T": "A", "A": "U"}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor nit. This code snippet is internally inconsistent w.r.t quoting style. Though feel free to disregard if you don't want extra input here :)

Copy link
Contributor Author

@petrem petrem Dec 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleaner the better. Happy to update it but I won't commit anything more unless @BethanyG says so at this point to ensure I won't hinder any ongoing activity.

Of course one example / approach / article should have internal consistency, but I wonder: do we have a preferred quotation style on the Python track? I personally prefer double quotes, but many others prefer single quotes. Pep-8 does not give a recommendation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.