Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

huhu posted:

I tried to add
code:
@login_required
to my Flask app and now I'm getting an error when accessing those pages with that.

You might have done this, but the login manager class has a field "login_view" that can be set, like
code:
login_manager.login_view = "users.login"
at https://flask-login.readthedocs.io/en/latest/#customizing-the-login-process

I just realized I was using the login extension wrong, I'm glad you asked this ...

I've never done any web-dev before, and despite c# being my goto language I decided to follow https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world up to the point where openid gets involved. I really like using flask, sqlalchemy, the whole bit is really good when I don't really know what I'm doing python-wise. I really like writing python3 though, and it's super loving easy to read other's python3 code.

I just can't handle the runtime type checking though, it makes me real uneasy. I annotate all of my functions and still gently caress everything up all of the time. The best fuckup was when I passed a string into a function that was supposed to take a list of strings and make directories out of them ...

I guess I have two questions for the thread:
- Is there an advantage to annotating my function definitions beyond having some documentation?
- Is there a less heavy handed way to do m:n style threading in python besides using celery/rabbitmq? I'm looking for something like .Net's Task Parallel Library or whatever Go does.


vvv lol now if I can only get this web app to read forum posts for me i'd be solid

dougdrums fucked around with this message at 19:39 on Mar 9, 2017

Adbot
ADBOT LOVES YOU

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I've just been doing like:
code:
def hi(
    name : str,
    punc : str):
    print('hello %s%s' % (name, punc))

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I tried writing a hella OOP version of a thing in python like I might in javaish C#, and it took me far too long to realize that I was typing out the same stuff over and over again when none of it is enforced or anything; might as well just use them for the constructors. Python's OOP seems more useful when you do something like rust's traits with it.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
code:
$ pip3 search make sandwich

pysandwich (0.1.2) 		python sandwiches.
panini (2.4.6) 	 		The Simple Sandwich Maker. (https://panini.io)
libsandwich (0.1)  		Wrapper for libsandwich
sandwich-python (3.13.2) 	Python module for crossway multi-aspect production patterns.
yasm (1.4) 			Yet Another Sandwich Maker
pysw (1) 			makes yto samwitch!!!
sandwichmaker (2.0) 		easy to use sandwich maker
...

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I'm not sure, but you might be able to put searchable keywords or something into the setup.py. I know that if the package name is not the same as the module name, and I search for the module name, I will still get the package even if it's not in the description.

I decided to enter python's gates of dependency hell and it's a fuckin blast.

dougdrums fucked around with this message at 18:37 on Apr 25, 2017

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Python code:
noisymodule.print = lambda x : None

Haha take that noisy module!

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

Hadlock posted:

For those who have used VS Code in the last ~6 months (the vscode product has changed/improved a lot since early last year) What's the delta between vscode and pycharm these days once you plugin the top two or three vscode python plugins? I've been using vscode now for a little over a year writing Go, Powershell, Bash etc and trying to see if the jump to pycharm CE is worth it for Python.

I find VS Code's python features acceptable, but definitely not as good as PyCharm. It's good for small projects, scripts, or making modifications to a larger project quickly. I just used VS 2017 Community for a project someone was working on in PyCharm and it worked almost as well as using VS for usual C# debugging. I was able to start a PyCharm project up and debug it with no problems.

VS2017 really stepped up the python support. You can run Flask projects on azure straight from it iirc.

Loezi posted:

This, but VSCode also when you are not running on a proper workstation. I'm simply unable to use PyCharm on my work laptop (SSD, 16Gb memory, i5-5300U) because it's so sluggish.

Yeah I prefer Code for laptop editing in pretty much any language.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I enjoy my C#, but I really think python3 is the most well put together programming language today. If something is terribly complex to express in python, I'm definitely thinking too hard about it.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
There is something that bothers me about putting/seeing stickers on laptops, but I have no idea what it is.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I lied actually, I have a label with my name and phone number on the bottom of it :D

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
* Seventh, sent pm *

dougdrums fucked around with this message at 20:49 on Sep 7, 2017

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I've been thinking that the for/in/if construct was the way to do a map/filter eagerly. I haven't used pandas though, and only numpy a little, I'm not sure how they structure things. Are these libraries or CPython able to do some special sort of reductions or optimization with the functional operators?

I started out writing things with generators, and applying the for/in/if to yield and receive (via send). Would I benefit from using map/filter/reduce in this case? Or is it just that the general way to use pandas or numpy is to build a "query" using functional operators? That's what finally sold me on python tbh; I started using python to replace dotnet in general a few months ago, if that gives you some idea of my perspective.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

CarForumPoster posted:

Do you have anything I can read (or would you share) about why this is, particularly in the case of a while loop?

I believe the usual thing to do is to use range, count, or xrange like so:
code:
for i in range(100):
    print(i)
I dunno if click() blocks or something but I'd just do this assuming it does:
code:
def take_screenshot(x, y, *args):
    pyautogui.click(x, y)
    return screenshot.grab(*args)

for index, image in zip(count, partial(take_screenshot, x, y)):
    image.save(f'filename{index}.png')
No idea if that works ... e: oh i forgot the args

dougdrums fucked around with this message at 17:34 on Jun 10, 2018

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

cinci zoo sniper posted:

This is not to say that for loops are bad or that Pandas is ideal, just that using for loops with Pandas in absolute majority of cases is a sign of a clueless newbie.

I don't know about pandas, but it would makes sense to me to use functional methods when using numpy because that's what most of the people using numpy would be used to, outside of python. I'd think that numpy probably does some special reductions, or can parse that info otherwise though.

CarForumPoster posted:

Correct. I have to watch a zillion training videos for a new job and I am too lazy to click next and they had tests, but I appreciate the other perspectives and solutions its definitely a problem I encounter a lot where I need to do it over a limited number of items in a list or something.

I can't think of a place in python for it. You'd only need to explicitly specify an iterator variable like that if you wish for it to be modified somewhere in the loop. The only example that comes to mind is for a parser to skip ahead in a source document when the iterator is passed by pointer in C -- which is a niche case.

The essence of an iterator index is to define an order. In the 'screenshot' case here, if the order didn't matter, you could very well leave 'i' out and use a random number. If the order does matter, using something informative and already ordered -- like the current time -- would not be a bad upgrade. Using the time would mean you can leave out 'i' here too.

So, you would not need an explicit iterator count for a couple reasons: The set you're working on already has some notion of order you can go by; or you just don't care about the order anyways.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Python code:
import operator as op
map(op.and, zip(a, b, c))

I'm not exactly sure what is being specified though. I think you just want to and the two lists itemwise because bool([ False, False, False ]) is True. Ofc you can just any() the result if that is the goal.

E: actually am I wrong about this? I think op.and does bitwise and? Are there not boolean operations in operator?

When I do dir(op) in 3.7 it doesn't even list it ...

This works though! Just a different name... which is why I suppose operator has no boolean and. I feel kinda silly for mentioning any but missing this ...

Python code:

map(all, zip(a, b, c))

dougdrums fucked around with this message at 09:59 on Aug 3, 2018

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
It's generally called absolute difference, for the sake of searching. Just didn't see it mentioned.

quote:

Nah I wanted the list in my example comment (d = [False, False, True]).
Haha ya ofc, it's early here.

Python code:
list(map(all, zip(a, b, c)))
[/quote]
I've been wondering if it is generally considered "more proper" to do this or the comprehension syntax.

Comprehensions are cool and good but I'm really annoyed when I have to come up with a name every time.

dougdrums fucked around with this message at 11:50 on Aug 3, 2018

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I never use pylint in real time because it's super distracting, and I'm too lazy/in a hurry to figure out what I want silenced.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

cinci zoo sniper posted:

I sincerely hope you are the only person who sees your code.

... in real time ...

I can be the only person that sees my code, especially with python. Sometimes I just want my computer to do a thing right now, and python is 100% the thing for that. I've slowly started to use python in lieu of grep awk xargs shell script nonsense, it's always an improvement. I find it's tough to get fancy with python's syntax, outside of like comprehensions with multiple binds. Also I don't know perl.

E: Seems like my real problem was that I have 'save on focus change' and 'lint on save' both set in my settings.

dougdrums fucked around with this message at 14:02 on Aug 23, 2018

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Some offhand :words: on error handling: I use assert liberally, usually at the top of functions and whenever I make an unpure call. It's a habit I picked up from C and sort of from C# contracts. I like doing this because I can focus on the constraints of what I'm writing without taking the time to figure out how I should handle the failure, if that makes sense. I can just grep them later and fill it in once I figure it out. It also provides a relatively specific message for higher level code.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
BSON is kinda silly. Auditing mongoDB databases is fun (because you can charge more). My DB class in college was 90% mongoDB and also 100% a waste of time.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Oh yeah my thoughts exactly. It was more of a mac troubleshooting class, not unlike the others. Relational algebra got a week.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Ya I've used *args for variadic functions. Now I'm kinda wondering if variadic function signatures are overkill for any language that has a dynamic list built-in. The extra brackets aren't going to hurt. It only makes sense to me in python for ensuring a variable is at least a list or dict without explicit typing. The typing module and annotations can do that now though. I feel like I'm missing some other magic here or something. It makes sense in C for functions that implement dynamic structures, because you need those functions to do the actual allocation anyways.

I regret my every use of **kwargs. And of course you should split things up once the number of arguments gets unruly.

E: I guess you can use it to compose arguments but fuuuck.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Ugh yeah but I just always assume None is [] since they're both false. If None were iterable it'd be ok. Then you might have an optional list args situation, but those should be split into seperate function definitions anyways. Of course type annotations would make it explicit.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Type annotations don't imply static typing. You can do whatever wierd type stuff you like, whenever you like. You can do stuff like dependant types (now with a sensible syntax) since annotations can be callable. You can use it just to call a bunch of assertions without using mypy or any static checks you want. It's just slow as poo poo.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Sir, the tests just returned, I'm sorry to state that it is an instance of Haskell Brain. Unfortunately, we know nothing of an applicable cure. One it has been bound, it is very difficult to lift back out. We simply cannot erase Haskell Brain once it has been constructed. You have been reduced to two weeks to find some new job. Otherwise, this case of Haskell Brain is functionally terminating. My condolences, I will join you in prayer. I wish this were in error.

oh no ... oh GOD

dougdrums fucked around with this message at 21:57 on Feb 5, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Pythonic just means anything you don't personally think is bad form that has acceptable performance. It's all relative imo. PEP 20 is dumb. Anyone wnho has time to muse about these things at such high level should get back to work.

Also I believe the two forms posted above have different evaluation semantics. (iter vs. for/break)

I'd probably use filter in most cases personally, unless bar.names are not unique then next. Next tends to be an alias for "first" in my head.

dougdrums fucked around with this message at 03:09 on Mar 13, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I had a situation where I installed 3.8 from source and had 3.7 installed with apt, and pip would install packages for 3.7 instead. Try doing
code:
python3 -m pip install cyberfloodClient
instead.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I think the correct way to do this (at least on linux) would be to use alsaaudio, that way it is buffered on the hardware and the hardware deals with the timing. You would write DC into the PCM buffer until the length of your sample. Given a sample rate of 44.1khz, 140bpm; you'd need to write (60*44100/140)-(sample length) DC samples into the PCM buffer to achieve your timing, then your tick sample, then repeat.

https://larsimmisch.github.io/pyalsaaudio/ will get you where you want to go in linux.

https://docs.microsoft.com/en-us/windows/desktop/Multimedia/waveform-audio would be the windows way I believe, but I don't know of a python wrapper that exists for it, sorry.

E: Ahh I just realized that you want to call an arbitrary function. Yeah I would implement it on the arduino and go the other way around if your user program needs to know. Crazy option: wire line out to the arduino.

dougdrums fucked around with this message at 16:42 on Mar 30, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Pandas has trouble with the two offset headers if you pass header[0,1], I'm guessing because of the duplicate names and maybe something else. You can do it by using header=1 and mangle_dupe_cols=True, but you lose half of the column name.

I wrote this because I had a similar challenge for a programming competition and didn't get it in time, and it's been haunting me since. I assume the winner knew some numpy/pandas trick that I did not, idk how the gently caress he got it because this is still pretty gnarly:
Python code:

def unfuck_table(filename, header_size=2):
    import re
    from itertools import chain, tee, groupby
    from operator import itemgetter
    regex = re.compile(r'\b\w+\b')
    with open(filename) as file:
        def scan(line):
            match = regex.search(line)
            while match:
                yield match.group(0), match.span()
                match = regex.search(line, pos=match.end())
        parts, other_parts = tee(map(list, map(scan, file)))
        spans = map(itemgetter(1), chain(*other_parts))
        def overlaps(a, b):
            return max(a[0], b[0]) <= min(a[1], b[1])
        def union(a, b):
            return min(a[0], b[0]), max(a[1], b[1])
        guides = []
        for span in spans:
            def search():
                for i, guide in enumerate(guides):
                    if overlaps(span, guide):
                        guides[i] = union(span, guide)
                        return
                guides.append(span)
            search()
        guides = sorted(guides, key=itemgetter(0))
        def within(a, b):
            return a[0] >= b[0] and a[1] <= b[1]
        def range_to_column(r):
            return next( i 
                for i, guide in enumerate(guides) 
                if within(r, guide))
        columnized = [
            [ (data, range_to_column(r)) for data, r in part ]
            for part in parts ]
        data = columnized[header_size:]
        header = sorted(chain(*columnized[:header_size]), key=itemgetter(1))
        header = ([ ' '.join(map(itemgetter(0), groups))
            for _, groups in groupby(header, key=itemgetter(1)) ])
        assert len(header) == len(guides)
        data = [ list(map(itemgetter(0), row)) for row in data ]
        return [ header ] + data

E: gently caress I just figured it out. He used str.parse() and specified the width.

dougdrums fucked around with this message at 18:21 on Apr 2, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Nah it was a good break from the regular torture.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
It's gonna be somehing like
Python code:

# pip install parse
from parse import parse
parse('{:7}{:8}{:11}{:8}{:9}{:8}', line)
for the example. I got the string formatter parse function confused with this package.
Since iozone uses fprintf to produce the output you can just take it from the format string it's using. Or use the excel output ...

Manually entering the format widths is cheating though imho :colbert:

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
When she says

quote:

When possible and reasonably convenient, try to keep functions “pure”, and keep state that changes in well-thought-out, well marked places.
It's less of the concept of keeping the functions pure, as it is to keep your data consistent and not redundant (as far as python is concerned). I've been learning django for a project and they throw around he term DRY alot, and that is the idea: replace as much of the data (state of your program) that you can with equivalent code, or that is, code that produces an equivalent result. This makes it far easier to reason about the state of your program at any given point.

She mentions "idempotent functions", but you want to consider what input from the user or system calls (impurities) will be non-idempotent, and will require a change to the program's state; and which inputs are really idempotent where the result can be produced purely using code without changing the program's state.

The primary purpose of using immutable data structures is to avoid scope errors. That is, it prevents an inner scoped function from altering the previously asserted behavior of an outer function that calls it.

If you look at the code I posted on the last page, as an example of functional programming, you should notice that there is only one piece of data that is effectively mutable: the 'guides' list variable. I could've used reduce or something but whatever. 'columnized', is only read from to generate the 'header' and 'data' lists. Everything is done from two reads of the file from 'parts' and 'other_parts', once to discover the guide sizes, and then once more to sort the data into columns.

I consider dicts to be a sort of 'backing store' for your program when used mutably, or as a sort of annotated source of data when used immutably. The only sort of use for that example that I can think of is when you want to 'tag' some data with additional data on the way out the door, but you should never remove items! Of course you would not have this guarantee in python unless you used a dict type that is explicitly immutable.

dougdrums fucked around with this message at 02:03 on Apr 4, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Yeah honestly that update syntax along with the fact that you can do dictionaries in comprehensions is one of my favorite things about python.

E: It just occurred to me that you can rewrite existing keys with that syntax, but I guess it produces a seperate object?

dougdrums fucked around with this message at 02:54 on Apr 4, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I was thinking the same thing, but I don't know alot about docker. My python deployments are pretty much provider provisioning w/ user data -> sdist -> scp -> ssh tar xf && pip install. But I have some crazier packages with c where it would make sense to get more familiar with docker, if not just for the sake of getting with the times.

shrike82 posted:

Docker is compelling if your application has non-python dependencies, and your team uses heterogeneous, potentially shared, development machines

My particular use case requires GPU access and we have a hierarchy of dev machines - from MacBook Pros/Linux gaming laptops to in-house multi-GPU linux servers to AWS GPU instances. Docker papers over the various hardware setups. It also allows for pretty fine-grained isolation, down to exposing individual GPUs to a given instance, so this helps a lot with maximizing usage of the in-house servers.
This is pretty slick. I have some ML stuff using EGL, and it would be 100% less of a pain in the dick to sort this out with docker.

dougdrums fucked around with this message at 07:05 on Apr 9, 2019

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
Stay safe ghost server

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

KICK BAMA KICK posted:

A simple dict mapping strings to strings (can guarantee they're short, alphanumeric, no whitespace) that I want to read/write from disk -- is pickle the best option or would you rather write it as a text file? Few hundred entries at most, accessed/modified a only few times a day. Portability between implementations and platforms would be a huge plus.
shelve exists.

quote:

A “shelf” is a persistent, dictionary-like object. The difference with “dbm” databases is that the values (not the keys!) in a shelf can be essentially arbitrary Python objects — anything that the pickle module can handle. This includes most class instances, recursive data types, and objects containing lots of shared sub-objects. The keys are ordinary strings.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I can't stand watching videos to learn stuff. I think it's a combination of impatience and the desire to skip around. I still keep books around for some niche or real general reference topics. If I need to learn something new I just look at the documentation online or some examples on github. Books cost money and go out of date too quickly nowadays.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I'd say before the if and never use elif.

Before the if because it's clear that the comment expresses something about the comparison as a whole, if that makes sense.

Never use elif because you should return or continue instead; or use a dict with (nested) functions if you want to switch on a value.

E: oh jeez I'm a page too slow.

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)
I'm phonepostin' and otherwise preoccupied so to speak, so this isn't really a useful example but somehing like:
Python code:

def paint_color(color : Color):
  return paint({
    Color.RED: '#ff0000',
    Color.GREEN: '#00ff00',
    Color.BLUE: '#0000ff'
  }.get(color, '#000000'))
Or maybe:
Python code:

def route(page : str, *args):
  return {
    'index': index_view,
    'about': about_view,
    'contact': contact_view,
  }.get(page, not_found_view)(*args)
You can get really wacky with this and functools or somethig but that's the basic idea.

Oh and if you want to match on regex or an expression, you can filter with a comprehension over the dict then reduce.

Else Statement Considered Harmful

dougdrums fucked around with this message at 02:41 on May 10, 2019

Adbot
ADBOT LOVES YOU

dougdrums
Feb 25, 2005
CLIENT REQUESTED ELECTRONIC FUNDING RECEIPT (FUNDS NOW)

Boris Galerkin posted:

I guess I was talking more about 1:1 math functions, like the one I stole from here:
Switch cases in other languages don't normally accept expressions. I wouldn't use lambdas or functions as a key, but you could, and it's a handy thing to do if you want to match multiple cases, or be stubbornly idiomatic (via next).

For the example given, I'm of the opinion that it is always better to write a seperate function in the form:
Python code:

def f(x):
  if x < 2:
    return x*x
  if x == 2:
    return 6
  if x <= 6:
    return 10 - x
  raise ValueError('x is only defined in (-inf, 6]')
y = f(z)
Because:
  • You're forced to give it a name, possibly obliviating the need for a comment anyways.
  • You can be certain of the state of the rest of the function, outside of the scope of your branches.
  • It's not possible to return from the outer function within your branches, complicating control flow.
  • It can be typed and the type can be validated, if thats your thing.
In compiled languages this would be inlined anyways, no idea if it happens in python.

QuarkJets posted:

I don't think that this is good advice; if/elif/else give you much more control and capability than a dict and I can think of numerous examples where I'd want to use these builtin Python keywords instead of hacking together some sort of dictionary implementation (which I assume would also be much slower on repeated calls?)
I don't do this with expressions as keys, because I don't want coworkers/contributors to kill me in my sleep, but I'd argue that you actually have more control for mostly the same reasons listed above. (That is, a generator comprehension inside of next() or with a filter clause.)

In the case where you're simply matching by equality (or equality of a type) like a more traditional switch construct, I definitely prefer it. Calling this simple case 'hacky' is naive. A lot of times when I'm writing a switch, I really just want a table of calls, possibly wrapped in another call. A dict with functions as values expresses my intent exactly.

If the performance of this is really an issue, you shouldn't be using python. If you must and are are still concerned that it is creating a dict object each time (no idea if this is the case, but I would also assume so), you can define an instance of it immediately before the function definition and refer to that.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply