#esoteric-python

1 messages · Page 78 of 1

snow beacon
#

Order of operations was built into the grammar.

zealous widget
#

i feel like there's a more elegant way to do parenthesis but i haven't thought about it much

#

hmm, like scope += symbol == "("

#

that looks dope

snow beacon
#

For each index, you can get it's nesting depth by counting number of "(" - number of ")" before it in the string.

zealous widget
#

do lists have count methods

#

they do

#

nice

marsh void
#

Idk is my method like that bad? lul

sick hound
#

@marsh void [math] > print(__builtins__['exec']) <built-in function exec>

marsh void
#

okay, gotcha

#

globals().pop('__builtins__', {})? @sick hound

sick hound
#

?

#

are you suggesting that as a possible hack/circumvention or a way of solving that problem or...?

marsh void
#

To remove that thing lel

#

So basically I am trying to sanitize the input, right?

#

You have shown me that you can get access to functions from __builtins__, so I think there could be a line saying globals().pop('__builtins__') in the executor string

sick hound
#

hmm

marsh void
#
[math] > __builtins__['exec']
Invalid expression provided.
NameError: name '__builtins__' is not defined``` that does the trick, so uhm
sick hound
#

try object.__subclasses__()[64].acquire.__globals__['__builtins__']['exec']

marsh void
#

Lmao how am I gonna sanitize that

#

Actually lemme dis.dis

sick hound
#

although that doesn't work in 3.7 or 3.8

#

in 3.8 it's 80 instead of 64

marsh void
#

okay

sick hound
#

and in 3.7 it's 75

distant wave
#

!e ```python
print(1 .class.mro[1].subclasses()[75])

night quarryBOT
#

@distant wave :white_check_mark: Your eval job has completed with return code 0.

<class '_frozen_importlib._ModuleLock'>
sick hound
#

yep

brazen geyser
#

this feels like trying to prevent leaks from a sieve instead of using a funnel.

edgy kelp
#

sanitizing the input would be modifying it to make sure it can't get where it shouldn't, you're just restricting what it can do

#

and there's a lot of restricting to do

distant wave
#

nvm, doesn't work with operators

sick hound
#
>>> ast.literal_eval('pi')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Users\Aaay\AppData\Local\Programs\Python\Python36\lib\ast.py", line 85, in literal_eval
    return _convert(node_or_string)
  File "C:\Users\Aaay\AppData\Local\Programs\Python\Python36\lib\ast.py", line 84, in _convert
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Name object at 0x0000016778DD8470>```
snow beacon
#
exit.__setattr__("__code__",compile("exec('import __hello__')","","eval")),exit()```
marsh void
#

Hm

sick hound
#

that doesn't actually work

#

exit is a _sitebuiltins.Quitter

snow beacon
#

It was replaced with a lambda

#

In env

edgy kelp
#

quit does work though

sick hound
#

oh right

edgy kelp
#

which is the same thing

brazen geyser
#

shouldn't you always account for the possibility that you missed something or someone can overcome your sanitization through some unforeseen exploit? aka the only sane way of doing this is full on sandboxing

#

doesn't matter how thorough you make the sanitization

snow beacon
#

Make your own bytecode interpreter

#

Only support safe bytecodes

marsh void
#

lol very epic idea

#

Actually

snow beacon
#

I found an article talking about it when I was looking up a way to safely eval. I don't remember the url

sick hound
#
[math] > __builtins__['__import__']('sys')._getframe(1).f_globals.__setitem__('get_dis', lambda _: '')
[math] > raise BaseException
Traceback (most recent call last):
  File "calc.py", line 63, in <module>
    main()
  File "calc.py", line 52, in main
    safe_exec(input('[math] > '))
  File "calc.py", line 45, in safe_exec
    f()
  File "<string>", line 1, in _zH7JggrMBe
BaseException```
marsh void
#

Okay so

#

I have just made it much more strict

#

Having __import__ in code, in any way or form is causing the error to be raised

#

As well as exec and eval; quit and exit are mocked with the same lambda that exit had

sick hound
#
[math] > ().__class__.__base__.__subclasses__()[64].acquire.__globals__['__builtins__']['__imp' + (lambda: '')() + 'ort__']('sys')._getframe(1).f_globals.__setitem__('get_dis', lambda _: '')
[math] > raise ().__class__.__base__.__subclasses__()[64].acquire.__globals__['__builtins__']['BaseException']
Traceback (most recent call last):
  File "calc.py", line 54, in <module>
    main()
  File "calc.py", line 44, in main
    safe_exec(input('[math] > '))
  File "calc.py", line 39, in safe_exec
    f()
  File "<string>", line 1, in _JOikomAtqn
BaseException```
marsh void
#

Hahaha

#

Damn you are smart pleased_lemon

#

Is what we are doing idk, entertaining or it is getting tiring? I could continue for some more time, heh

sick hound
#

'__imp' + (lambda: '')() + 'ort__'

#

also this is definitely entertaining (for us at least)

marsh void
#

yeah lol

#

Yeah that one is smart

brazen geyser
#

'__tropmi__'[::-1]

marsh void
#

I could restrict __subclasses__ though

#

This is going to end at some point in time, right? haha

sick hound
#

well actually we have to go now :(

#

but if you just spend some time trying to make a good sandbox, when we get back we can smash it to pieces in seconds try to break out of it

marsh void
#

Yeah ok

#

See ya

snow beacon
#

I'm still here for 15 minutes.

#
exit.__setattr__("__code__",compile("ex"+""[::]+"ec('im"+""[::]+"port __hello__')","","lave"[::-1])),exit()```Doesn't use `__subclasses__`
#
exit.__setattr__("__code__",compile(f"ex{''}ec('im{''}port __
hello__')","",f"ev{''}al")),exit()```Slightly clearer to read.
brazen geyser
#
>>> 'icokwtmxhmbjptesnooyluparhordwttcihp'[::6]
'import'

it is more or less impossible to prevent all cases of string garbling

#

and that in itself should give you pause

snow beacon
#
"\N{LATIN SMALL LETTER I}mport"```
marsh void
#

LOL

brazen geyser
#

lol wtf is that

snow beacon
#

Escape sequence that evaluates Unicode names

brazen geyser
#

damn

#

TIL

snow beacon
#

You can also use more traditional hex escapes, binary escapes, that sort of thing

marsh void
#

Y’all ever test your code? lol

distant wave
#

Can you do it without using __? That's a possible ban case

marsh void
#

'im{''}port' is gonna throw an error lol

#

yeah makes sense actually

distant wave
#

block builtins and __ and I'm not sure how to break out

snow beacon
#

Other quote marks

#

f"im{''}port"

brazen geyser
#

you can still do all kinds of garbled ways to get __

snow beacon
#

But if you can't use them in the code itself, it's harder to access attributes

marsh void
#

INVALID_CODE = ('__', 'import_name'.upper(), 'raise_varargs'.upper(), 'exec', 'eval', 'breakpoint') ok so now we have this I think

distant wave
#

Just block __ and builtins, honestly. That removes nearly everything..

#

Regardless, there are many things that aren't safe to allow, and you should use a tried and true well-built solution like snekbox

marsh void
#

yup

#

Is it on PyPI tho?

distant wave
#

You can pip install from git

#

An example of stuff that seems innocous but would cause real problems:
bytearray(0x7FFFFFFF)

marsh void
#

oh yep, that stuff

#

Yeah well, I’ve dropped my thing because obviously there are much better solutions

#

But it was fun while it lasted, lol

distant wave
#

Oh this is interesting

#

what the H

#

!e ```python

it = 'abracadabra'
for _ in range(1000000):
it = filter(bool, it)

del it
print("Got here")

night quarryBOT
#

@distant wave :warning: Your eval job timed out or ran out of memory.

[No output]
distant wave
#

!e ```python

it = 'abracadabra'
for _ in range(1000000):
print("s")
it = filter(bool, it)

del it

#

Odd

#

On my end it does this:

#
$ python3
Python 3.7.2 (default, Feb 12 2019, 08:16:38)
[Clang 10.0.0 (clang-1000.11.45.5)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
>>> it = 'abracadabra'
>>> for _ in range(1000000):
...     it = filter(bool, it)
...
>>> del it
Segmentation fault: 11
snow beacon
#

Is that like the foo = foo.__call__ shenanigan?

distant wave
#

It takes about 1.5 seconds to happen, so the 1s exec time limit on snekbox is probably ending it

#

Sortof

#

it's nastier

snow beacon
#

Iters within iters within iters

distant wave
#

The deallocator overflows the stack

snow beacon
#

Put it in a function and watch people get confused when it goes out of scope.

distant wave
#

ew.

#

just

#

ew

#

Speaking of segmentation faults, cefpython's javascript-python method binding structure is quite fragile. Give it a single, well-defined, locally-scoped function that dispatches, otherwise it gets very unhappy ;-;

#

I thought I could pass it lambdas. That turned out to be a poor decision ;-;

snow beacon
#

Can't you just compile Python to web assembly and bind to that?

sick hound
#

@marsh void py [math] > getattr(getattr(getattr(getattr(getattr((), '_a_acalaaasasa_a_'[::2]), '_a_abaaasaea_a_'[::2]), '_a_asauabacalaaasasaeasa_a_'[::2])()[64].acquire, '_a_agalaoabaaalasa_a_'[::2])['_a_abauaialataianasa_a_'[::2]]['_a_aiamapaoarata_a_'[::2]]('sys')._getframe(1).f_globals, '_a_asaeataiataeama_a_'[::2])('get_dis', lambda _: '') [math] > raise ().__class__.__base__.__subclasses__()[64].acquire.__globals__['__builtins__']['BaseException'] Traceback (most recent call last): File "calc.py", line 54, in <module> main() File "calc.py", line 44, in main safe_exec(input('[math] > ')) File "calc.py", line 39, in safe_exec f() File "<string>", line 1, in _aNUDIMEQEh BaseException

#

:P

snow beacon
#

Is getattr in the scope?

sick hound
#

yes

#

...apparently BaseException is too

#
[math] > getattr(getattr(getattr(getattr(getattr((), '_a_acalaaasasa_a_'[::2]), '_a_abaaasaea_a_'[::2]), '_a_asauabacalaaasasaeasa_a_'[::2])()[64].acquire, '_a_agalaoabaaalasa_a_'[::2])['_a_abauaialataianasa_a_'[::2]]['_a_aiamapaoarata_a_'[::2]]('sys')._getframe(1).f_globals, '_a_asaeataiataeama_a_'[::2])('get_dis', lambda _: '')
[math] > raise BaseException
Traceback (most recent call last):
  File "calc.py", line 54, in <module>
    main()
  File "calc.py", line 44, in main
    safe_exec(input('[math] > '))
  File "calc.py", line 39, in safe_exec
    f()
  File "<string>", line 1, in _9orsK4obqI
BaseException```
#

(that very long first line disables the filtering so that we can do raise)

snow beacon
#

What's the point of env = {'abs': abs, 'sqrtre': sqrtre, 'sqrt': sqrt, 'e': e, 'pi': pi, 'i': sqrtre(-1), 'exit': exit_mock, 'quit': exit_mock} if you can access anything you want?

sick hound
#

well you can't access exit and quit since they're shadowed

#
[math] > globals()['_a_abauaialataianasa_a_'[::2]]
Invalid expression provided.
KeyError: '__builtins__'``` and `__builtins__` is gone
snow beacon
#

But everything else is still there?

sick hound
#

yes

snow beacon
#

That would have made it much easier to break if I'd known that.

sick hound
#

yeah actually our method can be a bit shorter

#
[math] > getattr(getattr(getattr(object,'_a_asauabacalaaasasaeasa_a_'[::2])()[64].acquire,'_a_agalaoabaaalasa_a_'[::2])['_a_abauaialataianasa_a_'[::2]]['_a_aiamapaoarata_a_'[::2]]('sys')._getframe(1).f_globals,'_a_asaeataiataeama_a_'[::2])('get_dis',lambda _:'')
[math] > raise SystemExit```
#

and we could probably also do something better with the __ stuff

#

anyway gtg now bye

snow beacon
#

The solution to sanitise code like this is to ban iterable slicing. Then everything will be safe.

marsh void
#

Actually

#

Restrict string literals. That’s it. Lol

proper vault
#

chr(65)+chr(66)

lament ibex
#

Come to think of it, why not just use ast.literal_eval from the beginning and then add the functions you want

#

A blacklist method just won't work

snow beacon
#

I prefer the custom bytecode interpreter idea, but there are a few gotchas with it.

#

Actually, why not just write a parser?

grave rover
#

Refactoring my bytecode optimizer, any ideas on how I should handle jumps?

grave rover
#

Right now I just remove opcodes

grave rover
#

got jumps working ish?

#

it did break most of my other code tho

grave rover
#

And I somehow broke it again reee

grave rover
#
    def f():
        x = 1
        b = 2
        if x:
            x = 2
            y = 2
            return y + 1
``` ```
 40           0 LOAD_CONST               1 (1)
              2 POP_JUMP_IF_FALSE       12

 41           4 LOAD_CONST               2 (2)
              6 LOAD_CONST               1 (1)

 42           8 BINARY_ADD
             10 RETURN_VALUE

 43     >>   12 LOAD_CONST               0 (None)
             14 RETURN_VALUE
#

making progress

#

fuck my optimizer doesn't check for usage in nested blocks

proper vault
#
a = lambda: b
b = 6
a()```
snow beacon
#

Isn't dynamic scope great?

grave rover
#

The downside is that the bytecode can differ depending on the context

#

At top level this would evaluate to using LOAD_CONST 6 STORE_NAME b

#

In a function body it'd be LOAD_CONST 6 STORE_FAST b

#

But in a function body with b defined at top level it'd be LOAD_CONST 6 STORE_NAME b again

#

Speaking of bytecode

#

I can now optimize every module by hijacking the import

grave rover
#

And I just fixed varnames, sweet

grave rover
#

did I kill this channel

glacial venture
#

idk

snow beacon
#

What is dead may never die.

zealous widget
#

season 8 disagrees

sick hound
#

esoteric programming is interesting

#

it's like compacting rube goldberg machines

rugged sparrow
#

challenge for people. write Hello World to stdout without importing anything or print or input

#
del __builtins__.__import__
del __builtins__.print
del __builtins__.input```
snow beacon
#

Is site already imported?

rugged sparrow
#

you start with a normal interpreter

#

so no

snow beacon
#

Ah, got it

#
input("Hello World")```
rugged sparrow
#

whoops forgot about input

gilded orchid
#

is that even possible without importing stuff

#

I'm guessing it involves some crazy dunder stuff or something

brazen geyser
#

isnt there some vague way to get the sys module without importing?

#

it's stored in some builtin list somewhere

pure dew
#
sys = next(
    getattr(c, f).__globals__["sys"]
    for c in ().__class__.__base__.__subclasses__()
    for f in dir(c)
    if isinstance(getattr(c, f, None), type(lambda: None))
        and "sys" in getattr(c, f).__globals__
)

sys.stdout.write("Hahah")
#

yes there is

gilded orchid
#

oh wow

rugged sparrow
#

nice

#

looping thru all subclasses of object and looking for non-builtin functions to grab the globals off them

pure dew
#

:D

#

disclaimer: I did not originally write this

#

I just make it a nice single statement

brazen geyser
#

how about just (lambda: None).__globals__['sys'].stdout.write('Hello World\n')

pure dew
#

wont work

#

unless sys is already in the current globals table

brazen geyser
#

i tested it

pure dew
#

i did too

gilded orchid
#

challenge: make a hello world using the least unique characters, without using any of the chars in Hello, World!\n

brazen geyser
#

oh right, shouldnt be in IDLE

pure dew
#

what

brazen geyser
#

i tested it in the IDLE REPL

pure dew
#

oh

brazen geyser
#

well, it seems to work outside of the REPL too

pure dew
#

yea you gotta reach into a function that has it in scope

brazen geyser
#

where did you test it

pure dew
#

python 3.6.1 repl on windows 10

brazen geyser
#

oh wait, im a moron. thought i commented out all lines in this file but there was one at the top in grey i didnt notice

#

can you guess the content of this line 🙂

pure dew
#

same thing hap-- oh lol

#

import sys?

brazen geyser
#

bingo

#

@gilded orchid could you elaborate a bit more on what you mean by using the least unique characters?

gilded orchid
#

like abcdcba would be 4 unique chars

#

abcd

brazen geyser
#

oh. literally least number of unique characters.

gilded orchid
#

yeah

#

I worded that poorly

brazen geyser
#

no im just very tired 😅

pure dew
#

@gilded orchid Does this count?

#
print("".join(map(lambda c:chr(ord(c)-13),"Uryy|9-d|\x7fyq.\x17")))
gilded orchid
#

um

#

it looks like it does

#

though it does have a , and I said no chars from Hello, World! (if I'm being picky)

pure dew
#

wasnt sure if your character restriction applied to the string or source

#

if its the whole source it definitely doesnt count

#

could fix that with hex obfuscation, but i'd rather play sniper elite

snow beacon
#

There's also a

#

And a o and l

hollow patrol
#

WHAT I WANT:

lambda: (
    x = 0
    while x < 6:
        x += 1
        yield x
)```

WHAT I GET:

```python
func(lambda v: (
    setattr(v, x = 0),
    (yield from during(lambda v: v.x < 6, lambda v: (
        setattr(v, x = v.x + 1),
        (yield v.x)
    )))
))```
#

I got the 2nd one to work

#

The 1st one (sadly) isn't valid Python 😦

pure dew
#

ayy bruh have you seen pyskell

hollow patrol
#

nope

pure dew
#

its alll valid python

#

lemme dig up a few examples

#

import demo

include %"to_import"

include [sys]

class Main(main):
    from Imported import add3
    from Sys import PYSKELL_VERSION

    main : IO()
    main | (
        print( "Hello, World!"),
        print("Pyskell version", PYSKELL_VERSION),
        print( add3( 5))
    )
#

Functor/fmap impl demo

def trait(Functor: f):
    fmap : Func(a, b).f(a).f(b)

def data(Maybe: a):
    Just(a),
    Nothing

def instance(Functor: Maybe):
    fmap(func, Just(val)) | Just( func( val))
    fmap(func, Nothing)   | Nothing

main | (
    data := Just(5),
    print( fmap( add( 3), data)),
)
hollow patrol
#

It looks like valid Python to me

pure dew
#

oh, syntax yea

hollow patrol
#

I don't get how it doesn't have any import at the top

#

It needs some import to load the code and parse the AST and rewrite it

pure dew
#

well, these are pure source files

#

you aren't gonna run these with python

hollow patrol
#

true

#

maybe i could do something like this

pure dew
#

gonna be like pyskell functor.py

#

for your case, i wouldnt

hollow patrol
#
func(lambda x, y, z: '''while True:
    print(x)
    print(y)
    print(z)
''')```
pure dew
#

oh

hollow patrol
#

but that seems even worse then my previous one

pure dew
#

yea tbh

hollow patrol
#
func(lambda v: (
    during (lambda v: True, lambda v: (
        print(v.x),
        print(v.y),
        print(v.z)
    ))
))```
#

that's what i have

pure dew
#

well you can't really get too much better in pure python

#

lambdas are expressions

hollow patrol
#

so

#

i have two anonymous function choices

#

my anony

#

or my lambdatools

#

anony looks better, but can't support generators

#

lambdatools looks worse, but has more flexibility

#

@pure dew you're probably right

#

but i really wish we had better lambda support 😦

pure dew
#

python isn't really a functional language at all

#

I try to keep everything pythonic and I don't find myself missing good lambdas too much

#

but i do prefer functional languages

#

Haskell 😩

hollow patrol
#

Alright

#

Wait, I have an idea

snow beacon
#

The main Scheme features I miss are tail-call elimination and not having to import foldr a.k.a. reduce.

#

Without those, my code barely functions.

pure dew
#

maybe try writing python instead of scheme then /s

brazen geyser
#

i think the reduce in functools is foldl

#

and it looks kinda janky to work with

snow beacon
#

I can rewrite my algorithms to work around python's flaw.

#

Trampolines, iteration etc

#

Dynamic programming is harder than tail calls, but it's probably for the best to use that too.

brazen geyser
#

idk if it's very fair to characterize it as a flaw, rather than a different approach.
guido explains here at length why he considers it unpythonic: http://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html
the reasoning seems sound to me.

another thing i remembered: i think Stackless Python might have TCO and is currently up to 3.7 so you could check that out.

#

according to wiki: In practice, Stackless Python uses the C stack, but the stack is cleared between function calls.
sounds like TCO would be a natural consequence of this, but im not sure.

#

oh nice looks like they have a 3.8 beta release too

grave rover
#

I could probably write TCO for python

grave rover
#

it'd save a bunch of cycles because it's just a jump rather than PyObject_Call

brazen geyser
#

what about non self calls tho

grave rover
#

wdym

#

I can just check if a STORE_NAME happens to the same function name

thin trout
grave rover
#

occasionally

#

I wish I could just write python bytecode tho :(

brazen geyser
#

i mean howre you gonna do non self calls with just a jump

grave rover
#
def x():
    ...
    return x()  # JUMP_ABSOLUTE(0)```?
#

like that?

brazen geyser
#

thats a self call

grave rover
#

🤔

#

wdym then

brazen geyser
#

tail calls dont necessarily have to recurse

#

so that could be another function, y()

grave rover
#
def x():
    ...
    return y()  # LOAD_NAME(y) CALL_FUNCTION```
brazen geyser
#

just as long as you know you no longer need the stack for x, you can perform the optimization

#

thats not gonna be optimized

#

itll add another frame

grave rover
#

no way to optimize that in just bytecode

#

unless you get the function at compile time and embed it

#

resulting in more memory usage

brazen geyser
#

not necessarily. you could add all the frame cleanup bytecode right there. it would be messy and very involved. but doable.

grave rover
#

there's one alternative which is literally moving the IP to the start of y but that requires a lot of ctypes hacking

grave rover
#

TCO within local function is done

#

wooo

#

(does not support kwargs)

night quarryBOT
grave rover
#

heck

#

fine

grave rover
#

@brazen geyser @snow beacon would you guys mind testing some code with this? to enable it on imports: ```py
import sys
import dis
from importlib._bootstrap_external import FileFinder, SourceLoader

from bytecode_optimizer import optimize_code

class ByteOptimizer(SourceLoader):
def init(self, *args):
self.module, self.path = args

def get_filename(self, fullname):
    return self.path

def get_data(self, path):
    print(self.module, self.path)
    with open(self.path, "rb") as fp:
        return fp.read()

def source_to_code(self, data, path='<string>', **kwargs):
    code = SourceLoader.source_to_code(self, data, path)
    excluded_modules = ("six",)
    if b"# no-optimize" not in data and not self.module.startswith("_") and self.module not in excluded_modules:
        # Don't optimize python internals or files marked with `# no-optimize`
        code = optimize_code(code)
    return code

@classmethod
def enable(cls):
    loader_opts = [cls, [".py"]]
    sys.path_hooks.insert(0, FileFinder.path_hook(loader_opts))
    for k, v in sys.path_importer_cache.copy().items():
        if isinstance(v, FileFinder) and ("python3" not in v.path or "site-packages" in v.path):
            # Don't modify stdlib
            del sys.path_importer_cache[k]```
formal sandal
#

By the way, it probably won't optimize itself :)

#
if b"# no-optimize" not in data
wind maple
#

it's a negative check

#

wait no even I'm getting confused

#

wait no yes I was right

#

You should really prefer early returns >:(

grave rover
#

how so

#

also it's not supposed to optimize itself since it only runs at application start

formal sandal
#

@wind maple my point was that this file contains # no-optimize, so it won't be optimized.

wind maple
#

oh yert

brazen geyser
#

ive got both bytecode_optimizer.py and this ByteOptimizer class in separate files

#

now am i supposed to make a third file, import ByteOptimizer, call its enable method, then import a function from somewhere else?

#

@grave rover

grave rover
#

uhhh

#

kinda

#

lol

#

structure wasn't well thought out

#

I use it like this:

# main.py
from import_optimizer import ByteOptimizer
ByteOptimizer.enable()
import entrypoint
entrypoint.main()
#

I recommend disabling the TCO flag though, it doesn't seem to like kwargs just yet

#

making a repo for this soon

next mist
#

i made a nick name maker, you just pit in your name and get a new one out, any ideas for improvement?

class BoopBoop():
    
    def BorpBif(BepaBip, BupBup):
        BapBif = BepaBip
        Bip = ""
        BopBip = Bip.join(BapBif)
        BepBid = "urgle"
        BufBip = (BopBip+" "+BupBup+BepBid)
        print(BufBip)
    def Bobbup(Blup):
        BupBup = Blup
        BefBip = {
            "BabBab":"a", "BadBab":"b", "BabBap":"c", "BabBad":"d",
            "BebBeb":"e", "BedBeb":"f", "BedBep":"g", "BebBed":"h", 
            "BibBib":"i", "BidBib":"j", "BidBip":"k", "BibBid":"l",
            "BobBob":"m", "BodBob":"n", "BodBop":"o", "BobBod":"p",
            "BubBub":"q", "BudBub":"r", "BudBup":"s", "BubBud":"t",
            "BaabBaab":"u", "BaadBaab":"v", "BaadBaap":"w", "BaabBaad":"x",
            "BoobBoob":"y", "BoodBoob":"z", "BoobBoop":" "
        }
        BepaBip = (BefBip["BoobBoob"],BefBip["BodBop"],BefBip["BaabBaab"],BefBip["BudBub"],BefBip["BoobBoop"],
            BefBip["BodBob"],BefBip["BabBab"],BefBip["BobBob"],BefBip["BebBeb"],BefBip["BoobBoop"],BefBip["BibBib"],BefBip["BudBup"])
        BoopBoop.BorpBif(BepaBip, BupBup)
    def BipBop(BaapBip, Bup):
        BupBeep = (BaapBip*Bup)
        BepBep = (''.join(sorted(BupBeep)))
        Blup = (BepBep[len("ba")]+BepBep[len("Boof")])
        BoopBoop.Bobbup(Blup)

    def BopBid():
        Bup = len("Bap")
        BoopBip = "BabBoop>>>"
        BaapBip = input(BoopBip)
        BoopBoop.BipBop(BaapBip, Bup)
if __name__ == '__main__':
    BoopBoop.BopBid()

sick hound
#

do you mean make-it-better improvement or make-it-more-esoteric improvement

#

if you want it to be actually better then don't ask here because this is not the right channel for that advice

#

if you want it to be more esoteric, then this is the perfect place to ask :)

lament ibex
#

lol it's like a 5 year old used text to speech to make the identifiers 😂

worthy pollen
#

phonetic variables... someone needs to code that up, sound/click driven coding for the blind

next mist
#

im thinking i need to pay a singer to scat sing my code

#

and then i upload that to github and call it open source

#

but yes better ways too add on to its... esotericness?

formal sandal
#
def BoobBob(Bap,Bup,Beb=0):
    if not((Beb*3-Beb<<1-Beb)or Bup):
        return Beb
    Boomb,*Brump=Bup
    return BoopBoop.BoobBob(Bap,Brump,-(-Bep-1))```
#

Replace len with this.

tame crow
next mist
#

that is amazing @formal sandal

marsh void
#

haha

glacial venture
#

heres a challenge

#

make an esolang

#

that can be played as a (kinda) pleasant music file

#

or audio file

#

and also run as a thing

#

its not a proper challenge but sounds interesting

wind maple
gilded orchid
#

yeah velato basically just is that

formal sandal
#

So that in addition to the despair you feel when reading the code you wrote a few months ago you could also listen to black metal?

grizzled cloak
#

does someone have a example of what hello world sounds like?

snow beacon
#

It's linked to on the page.

#

I don't think it's related to Python though.

gilded orchid
#

i mean there is a python interpreter for it

#

if that counts

proper vault
#

that needs a REPL

grave rover
#

now to make LOAD_CONST SOME_COMPARE short circuit

pure dew
#

now make it a decorator

#

and make it compatible with lru_cache

snow beacon
#

That doesn't seem very hard.

#

If you don't want to mutate the original decorated function it'd be slightly harder.

pure dew
#

ah nah

#

just cache the original and return a new one

grave rover
#

even better

pure dew
#

is it on GH/GL?

grave rover
#

not yet

#

gonna clean up a bit

#

I posted a pastebin of an old version earlier this week tho

grave rover
pure dew
#

tf is .snekrc

grave rover
#

Snekchek

snow beacon
#

Challenge: get this to work```python
a, b = var_length()
a, b, c = var_length()
a, = var_length()

brazen geyser
#

whats var_length @snow beacon ?

snow beacon
#

It's a function for you to define

#

It should return an iterable, of course.

#

The length of the iterable is the important thing, because all three of the cases require a different length.

brazen geyser
#

ohh variable length i see

pure dew
#

without diving into real deep, i'll say this

#

you can unpack a variable length sequence/iterable by tacking a star on one of the assigners ex. a, b, c, *d = range(10)

#

also, it doesnt have to be on the end

#

a, *b, c, d = range(10) works just as well

pure dew
#

slice indexing is faster, but not as cool

snow beacon
#

I was hoping some devious coder could make a function that alters the length of its return value based on what the result is assigned to.

pure dew
#

wew

#

that'd be some wacky stackframe shit

#

but what if you just return the function instead of assigning it

snow beacon
grave rover
#

should be doable

#
from dis import opmap, stack_effect
from functools import wraps
from inspect import stack

def var_length(func):
    @wraps(func)
    def inner(*args, **kwargs):
        code = stack()[1].frame.f_code
        pos = stack()[1].frame.f_lasti
        ops = list(zip(code.co_code[::2], code.co_code[1::2]))
        op = ops[int(pos / 2)+1]
        try:
            effect = stack_effect(op[0], op[1])
        except ValueError:
            try:
                effect = stack_effect(op[0])
            except ValueError:
                effect = 1
        if op[0] == opmap["UNPACK_SEQUENCE"]:
            nargs = op[1]
        elif effect < 0:
            nargs = -effect
        else:
            nargs = 0
        return func(nargs, *args, **kwargs)
    return inner
#

there

#

@snow beacon how's this

grave rover
#

note: mostly untested

#
@var_length
def zero(n):
    if n > 1:
        return [0] * n
    if n == 1:
        return 0


a = zero()
b, c = zero()
d, e, f = zero()
assert a is b is c is d is e is f is 0
``` this works
#

cc @brazen geyser @pure dew you guys would like this too

brazen geyser
#

noice

grave rover
#

alternatively:



def yielding(func):
    iterable = func()

    @wraps(func)
    def inner(n):
        buffer = []
        while len(buffer) < n:
            buffer.append(next(iterable))
        if n > 1:
            return buffer
        if n == 1:
            return buffer[0]

    return var_length(inner)


@yielding
def some_generator():
    x = 0
    while True:
        yield x
        x += 1


a = some_generator()
b, c = some_generator()
d, e, f = some_generator()

assert (a, b, c, d, e, f) == (1, 2, 3, 4, 5, 6)
wind maple
#

I feel like you could replace that buffer thing with islice

pure dew
#

oooh

grave rover
#

islice doesn't like generators though @wind maple

wind maple
#

wdym

#

it's designed for iterators

#
>>> def gen():
...     while True:
...         yield 1
...
>>> g = gen()
>>>
>>> itertools.islice(g, 3)
<itertools.islice object at 0x000001F9AAFD07C8>
>>> list(_)
[1, 1, 1]```
pure dew
#

where do you define stack and stack_effect tho

grave rover
#

o

#

imported

#

updated post

#

here's a pastebin

pure dew
#

oh, dis

#

i gotta look into that a bit more

grave rover
#

tldr if you need to work with opcodes, dis is your friend

pure dew
#

i've never used it for more than pretty printed disassembly before

sick hound
#
def is_even(n):
    return eval('-'*n + '1') > 0```
grizzled cloak
#
def is_even(n):
    return not n&1
#

still my favorite

#

and actually usefull

sick hound
grizzled cloak
#

true

#

@sick hound
f = lambda n: bool(type(n).__neg__(True.__rand__(n))+True)

#

better?

sick hound
#

yeah that's definitely more obfuscated and esoteric

grizzled cloak
#

even better now

sick hound
#

__rand__ sounds like something to do with random numbers but it's actually just a version of &

grizzled cloak
#

yup

#

right_add

sick hound
#

yep

snow beacon
#

Nice work on the function, Martmists. It's surprisingly modularised even, despite most code this channel sees being golfed.

rugged sparrow
#
def is_even(num):
    try:
        eval("'"*int(str(num)[-1]))
        return True
    except:
        return False``` @sick hound my personal favorite
marsh void
#

bare except uwu

wind maple
#

lol no else block

marsh void
#

bruh

grave rover
#

@snow beacon I could golf it some more (hell, I could just write manual bytecode) but this is clean and understandable

proper vault
#

is_even=lambda i:not (lambda f,x,n: f(f,x,n))((lambda g,y,o: g(g,y-1,~o) if y else o),i,0)

marsh void
#

Let’s make 2+2 return 5 SmirkThink

thin trout
#

If you can assign 2.5 to 2, you’re golden

wind maple
#

or just assign 5 to 4

thin trout
#

Not sure if it would work

wind maple
#

yes

#

I've done it

rugged sparrow
#
chronos@localhost ~ $ pip3 install forbiddenfruit
Requirement already satisfied: forbiddenfruit in /usr/local/lib/python3.8/site-packages (0.1.3)
chronos@localhost ~ $ python3
Python 3.8.0 (default, Oct 18 2019, 01:12:04) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from forbiddenfruit import curse
>>> curse(int, '__add__', lambda a,b:5)
>>> 2+2
5
>>> ``` @marsh void
thin trout
#

Of course..

marsh void
#

well that’s not what I wanted heh

#

only 2+2 should be 5 SmirkThink

thin trout
#
>>> from forbiddenfruit import curse
>>> curse(int, '__add__', lambda a,b: 5 if a == b and a == 2 else a + b)
>>> 2+2
5```
#

@marsh void ^

grizzled cloak
#

try that for something other than 2

#

cant imagine this works
a + b

thin trout
#

(Haven’t tried tbh)

grizzled cloak
#

thats calling add again

thin trout
#

Oh yeah

#

Well

rugged sparrow
marsh void
#

Yeah

#

That’s the problem heh

thin trout
#
>>> from forbiddenfruit import curse
>>> intadd = int.__add__
>>> curse(int, '__add__', lambda a,b: 5 if a == b and a == 2 else intadd(a, b))
>>> 2+2
5```
marsh void
#

Oh I know

thin trout
#

Like this?

grizzled cloak
#

yeah

marsh void
#

else a - (-b)

grizzled cloak
#

i was just about to post that

marsh void
zealous widget
#

if a==b==2

marsh void
#

^ like honestly

#

Mine is cooler anyway

thin trout
#

Wasn’t sure if it worked

#

Should use !e more often

grizzled cloak
#
fb.curse(int, '__add__', lambda a,b: 5 if a==b==2 else a.__radd__(b))
2+2
Out[5]: 5
2+3
Out[6]: 5
3+1
Out[7]: 4```
#

because no-one likes making variables

marsh void
#

smart

grizzled cloak
#

dont think it gets any shorter:
fb.curse(int,'__add__',lambda a,b:5if a==b==2else a.__radd__(b))

marsh void
#

fb.curse(int,'__add__',lambda a,b:5if a==b==2else a--b)

#

shorter but slower

grizzled cloak
#

who cares about speed

marsh void
#

heh

#

Now I don’t think it gets any shorter kek

grizzled cloak
#

fb.curse(int,'__add__',lambda a,b:5if a|b==2else a--b)

marsh void
#

heh

#

smart

grizzled cloak
#

1 char less hehe

marsh void
#

Actually no

#

0 + 2

grizzled cloak
#

uhoh

marsh void
#

eheh

zealous widget
#

is there a way to put the original add function inside the function

#

lambda a,b: original_add(a,b) if a==b==2 else 5 in some form

grizzled cloak
#

yeah

#

original_add = int.__add__

#

before the curse

#

but then its nolonger one line

thin trout
#

Hey I posted this stupid solution 😄

#

Guys, I want to do weird things. You know any resource to get started at being esoteric?

zealous widget
#

my ternary is backwards

#

w/e

pure dew
#

@thin trout there isnt really a resource

#

just look for unreadable code you've written and make it worse

thin trout
#

Hun.

calm rampart
#

@grizzled cloak will that work? int.add is just a slot wrapper, are you sure it doesn't end up invoking the new one recursively?

grizzled cloak
#

Yes it creates a copy I guess

#

Curse actually replaces the function with some fancy c hooks

snow beacon
#

Another one liner (for the function):python (lambda original_add: lambda a,b: original_add(a,b) if not a==b==2 else 5)(int.__add__)

zealous widget
#

can you overwrite __eq__ with forbiddenfruit?

grizzled cloak
#

dont think so

snow beacon
#

If you do, make sure to also overwrite __hash__, otherwise Python will not work properly. Although, to be fair, you're already using forbiddenfruit, so that probably doesn't matter.

zealous widget
#

it spat error messages at me

sick hound
#

this channel is a fever trip

pure dew
#

yes thats the goal

#

consider it an initiation

pure dew
#

that may be dangerous

#

unless fb only does the member cursing

thin trout
#

Eval run in NsJail, trust me, you can't break out of this thing

pure dew
#

oh

#

i dont know much about the bot

thin trout
#

I don't think anyone every break out of NsJail

#

I googled a bit and there was a technic, but it required very low level access that only C provide

pure dew
#

fb does create C hooks, don't it?

thin trout
#

Maybe, but the breach has been patched very quickly

pure dew
#

fascinating

#

i still wouldnt trust it on my server tho

#

guess thats why they use docker

thin trout
#

I mean, breaking out of a container is easy

#

They aren't designed to protect from inside attacks

#

As NsJail is done for it

#

Oh well, it is designed by google

formal sandal
#

I had a slight problem today...

#

There is a Coord class with fields width, height, and offset.

    def __contains__(self, point):
        (offset_x, offset_y) = self.offset
        (x, y) = point
        x_inside = (0 <= x-offset_x < self.width)
        y_inside = (0 <= y-offset_y < self.height)
        return (x_inside, y_inside)
#

Can you spot the bug? :-)

#

Why doesn't this throw an error?

snow beacon
#

||It's converting a tuple to a boolean. Since the boolean isn't ever empty, it's true.||

formal sandal
#

Well, yeah.

lament ibex
#

Huh thought it would type error or something. Guess it converts if it can. Just tried implementing __len__ as return True and yep it returns 1.

formal sandal
#

I don't understand why this is allowed.

#

However, returning a non-boolean value from __bool__ will throw an error.

#

That conversion made me remember Javascript again...

lament ibex
#

Well that's interesting and inconsistent

formal sandal
lament ibex
#

Have to try all the dunders now

formal sandal
#

I think this is a very bad thing for exactly the same reason it is bad in JS.

#

You find an element like <div id="#undefined">
And you have no idea where the error is

lament ibex
#
Test.__len__ = lambda s: True #fine 
Test.__length_hint__ = lambda *_: True #fine
contains, fine
TypeError: __bool__ should return bool, returned int
TypeError: __str__ returned non-string (type int)
TypeError: __repr__ returned non-string (type int)
#

eq/lt/gt etc also can return anything but that's mentioned in docs and in comparisons bool() will be called anyway

proper vault
#

it does sorta make sense, as every value is truthy or falsey in python and you may want to return a tuple, which, if empty, means false, else true

lament ibex
#

Seems way too implicit. (False, False) becoming True, especially in a contains method seems very unintuitive to me

wind maple
#

how

proper vault
#

any non-empty tuple is true

wind maple
#

It would be even more confusing and more implicit if it did type checking and returned the result of any on an iterable

proper vault
#

same for lists, sets, dicts

wind maple
#

contains is the form of a verb that asks, I don't know the english word for it

lament ibex
#

It should just TypeError like the rest of the methods

wind maple
#

Send this suggestion to the mailing list or

#

the uh

#

new discussion website

lament ibex
#

As for the truthy falsy business, well I just don't like it in general (in any language). I always have to stop and think what counts as true, whereas the dev could just spend 2s explicitly saying what they're checking for

proper vault
#

I agree

wind maple
#

The list of things that are considered false are very intuitive

#

And this allows you to not write the same piece of code time and time again

#

Clearly naming is also a part of whether something is readable

lament ibex
#

Hmm not sure about that. Did a quick test e.g. bool(nan) is True, while in a different language, say JS it's false. Add to that the fact that you can define bool yourselves. Maybe you get used to it over time but when I was getting started it was definitely not an intuitive thing.

lament ibex
#

http://hyperpolyglot.org/ this is also interesting, there's a section on falsehoods. Seems every language has their own idea of it. Also another thing I thought of, return code 0 is success but 0 is falsy in just about every lang. Whole thing just seems so convoluted.

pure dew
#

well the return codk is a posix thing

lament ibex
#

Sure, maybe not 100% relevant to bring up but just another little snag

grave rover
#

what else could I make my library optimize 🤔

lament ibex
#

Inline short functions? Idk how doable that is and what you've already done

proper vault
#

maybe replace things with generators whenever possible. It may not be viable though

wind maple
#

The IEEE standard does not define a truthiness value for NaN

#

And it's also strictly not equal to any other numeric value, including 0

#

and since the truthiness in python for numerics are defined solely by zero

#

NaN being truthy is a fairly consistent choice

#

Technically it's an illegal conversion as there's no legal conversion to a numeric from NaN

grizzled cloak
#

because someone asked for it:

import math;f=lambda n:[print(x)for x in[' '.join([str(y*x).rjust(int(math.log10(n*n)+1))for y in range(1,n+1)])for x in range(1,n+1)]]```
#

multiplication table until n

proper vault
#

f=lambda n:[print(x)for x in[' '.join([str(y*x).rjust(int(__import__('math').log10(n*n)+1))for y in range(1,n+1)])for x in range(1,n+1)]] at least make it a true one liner

grizzled cloak
#

Heheh

proper vault
#

also, whu not do len(str(n*n))

grizzled cloak
#

Thats too simple

proper vault
#

alright, how about this then (lambda z: (lambda f,v,a: f(f,v,a)) (lambda f,v,a: f(v//10,a+1) if v else a) )(n*n)

hot mist
#

wait

#

rewrite it using walrus notation

distant wave
#
lambda x:[print(*[f'{i*n:>3}'for n in range(1,x)])for i in range(1,x)]
#

With walrus:

#
lambda x:[print(*[f'{i*n:>3}'for n in y:=range(1,x)])for i in y]
#

and to keep the spacing scaling:

#
lambda x:[print(*[f'{i*n:>{len(str(x*x))}}'for n in range(1,x+1)])for i in range(1, x+1)]
#

That has a bug

#

And fixed with -2chars

#

And again with +4, sigh

hot mist
#

🙂

distant wave
#

This seems right at least

hot mist
#

:=

distant wave
#
  1   2   3   4   5   6   7   8   9  10  11  12  13  14  15
  2   4   6   8  10  12  14  16  18  20  22  24  26  28  30
  3   6   9  12  15  18  21  24  27  30  33  36  39  42  45
  4   8  12  16  20  24  28  32  36  40  44  48  52  56  60
  5  10  15  20  25  30  35  40  45  50  55  60  65  70  75
  6  12  18  24  30  36  42  48  54  60  66  72  78  84  90
  7  14  21  28  35  42  49  56  63  70  77  84  91  98 105
  8  16  24  32  40  48  56  64  72  80  88  96 104 112 120
  9  18  27  36  45  54  63  72  81  90  99 108 117 126 135
 10  20  30  40  50  60  70  80  90 100 110 120 130 140 150
 11  22  33  44  55  66  77  88  99 110 121 132 143 154 165
 12  24  36  48  60  72  84  96 108 120 132 144 156 168 180
 13  26  39  52  65  78  91 104 117 130 143 156 169 182 195
 14  28  42  56  70  84  98 112 126 140 154 168 182 196 210
 15  30  45  60  75  90 105 120 135 150 165 180 195 210 225
#
lambda x:[print(*[f'{i*n:>{len(str(x*x))}}'for n in y:=range(1,x+1)])for i in y]
#

There ye go

#

80 chars

#
lambda x:[print(*(f'{i*n:>{len(str(x*x))}}'for n in y:=range(1,x+1)))for i in y]
#

slightly reduced ram consumption :P , maybe. Now makes an intermediate generator instead of list

#

hm, I can't actually test on 3.8, that y and y:= might need to be swapped

#

idk

#

Sometimes I wish for a kind of "map" expression, that doesn't require handling lambdas

#

something like, map(f'{x}', [1, 2, 3])

pure dew
#

can be made

distant wave
#

oh?

snow beacon
#

You'd need to put it in a string, I'd bet. Either that or you'd need to do some sort of symbolic computation, which would get messy.

pure dew
#

i dont think so

#

just some inspect/ast black magic

snow beacon
#

expression_map(1/isinstance(x, type(...)), [1, 2, "foo"]) would need to be coded pretty cleverly to work out of the box.

zealous widget
#
lambda x:[print(('{:4}'*x).format(*range(i,i*x+1,i))) for i in range(1, x+1)]

is this shorter?

pure dew
#

@snow beacon whats with the 1?

thin trout
#

@pure dew raise if isinstance return False (I think)

pure dew
#

well it would yea

#

I'm wondering about the reason he did that

#

cus it would end up as 1/0

snow beacon
#

That's the point. If x isn't an Ellipsis it'll raise an error.

#

That sort of code would be difficult to support.

pure dew
#

oh

#

well doing something like in a normal map raises an error anyway

snow beacon
#

But the error depends on what list you give it.

grave rover
pure dew
#

wait what

#

did i mis understand the point of that repo?

grave rover
#

what did you think it was @pure dew

pure dew
#

Alternative implementation of Jython

#

but this is

#

idk

#

makes me feel some kinda way

grave rover
#

I mean

#

It's python on the JVM

#

But better than Jython since we're planning on exposing jvm objects to it

sick hound
#
async def nick(ctx,member: discord.Member,arg):
        await member.nick(arg)```
#

Whats wrong with this?

marsh void
#

Oh, I see you were kind of ignored in discord-py channel, so let me write it down here:
member.nick returns the nickname of a member, so what you have in your function will error, saying that string is not callable.
If you wish to change member's nickname, there is a method member.edit(*, reason=None, **fields. So, your code will look somewhat like:

async def nick(ctx, member: discord.Member, *, nickname):
    await member.edit(nick=nickname)``` @sick hound
odd blade
#

answered in help

#

not sure how it came here

marsh void
#

kek

rare juniper
#
grade = 'C'

# Instantiate a switchcase called case that iterates over cases in the order
# that they're inserted.
with Switch(grade) as case:
    # Calling case.Break() stops other cases from being evaluated.
    case['A'] = (lambda value: print(f"Good job, you got an {value}!"), case.Break())
    case['B'] = case['A']
    case['C'] = lambda value: (print(f"Not bad! You got an {value}!"), case.Break())
    case['D'] = lambda value: (print(f"You received an {value}."), case.Break())
    case['F'] = case['D']
    
    # Case.default will run if it's defined and no other cases are ran.
    case.default = lambda value: print(f"Error: Unknown grade {value}")```


Thoughts on this syntax for switch-cases? I think it should be pretty easy to program a class called Switch that has this behavior.
haughty halo
#

very interesting

#

kinda like cases in c

#

sort of

snow beacon
#

What about comparisons?

#

The only syntaxes I can think of don't support assignment.

rare juniper
#
class Switch:
    def __init__(self, value):
        self.value: Hashable = value
        self.conditions: Dict[Hashable, Callable] = OrderedDict()
        self.default: Optional[Callable] = None

        # Defining in __init__ should allow more interesting logic for
        # nested switch cases?
        class BreakException(Exception):
            pass

        class Break:
            def __init__(self, *args):
                raise BreakException(*args)

        self.BreakException = BreakException
        self.Break = Break

    def __enter__(self):
        return self

    def __setitem__(self, condition: Hashable, func: Callable):
        self.conditions[condition] = func

    def __getitem__(self, condition: Hashable) -> Callable:
        return self.conditions[condition]

    def __exit__(self, exc_type, exc_val, exc_tb):
        condition_met = False
        try:
            for case, func in self.conditions.items():
                if self.value == case:
                    condition_met = True
                    func(self.value)
        except self.BreakException:
            return

        if not condition_met and self.default is not None:
            self.default(self.value)```
#

ah right comparisons... Hmm

#

maybe like

#

case[lambda value: value > 5]

#
from collections import OrderedDict
from typing import Hashable, Dict, Callable, Optional


class Switch:
    class Expression:
        def __init__(self, expression: Callable):
            self.expression = expression
    ex = Expression

    def __init__(self, value):
        self.value: Hashable = value
        self.conditions: Dict[Hashable, Callable] = OrderedDict()
        self.default: Optional[Callable] = None

        # Defining in __init__ should allow more interesting logic for
        # nested switch cases?
        class BreakException(Exception):
            pass

        class Break:
            def __init__(self, *args):
                raise BreakException(*args)

        self.BreakException = BreakException
        self.Break = Break

    def __enter__(self):
        return self

    def __setitem__(self, condition: Hashable, func: Callable):
        self.conditions[condition] = func

    def __getitem__(self, condition: Hashable) -> Callable:
        return self.conditions[condition]

    def __exit__(self, exc_type, exc_val, exc_tb):
        condition_met = False
        try:
            for case, func in self.conditions.items():
                if isinstance(case, self.Expression):
                    if case.expression(self.value):
                        condition_met = True
                        func(self.value)
                elif self.value == case:
                    condition_met = True
                    func(self.value)
        except self.BreakException:
            return

        if not condition_met and self.default is not None:
            self.default(self.value)
#

there we go

#
grade = 'C'

# Instantiate a switchcase called case that iterates over cases in the order
# that they're inserted.
with Switch(grade) as case:
    # Calling case.Break() stops other cases from being evaluated.
    case[case.ex(lambda value: value in ['A', 'B', 'C'])] = lambda value: print("Good job you passed!")
    case['A'] = lambda value: (print(f"Good job, you got an {value}!"), case.Break())
    case['B'] = case['A']
    case['C'] = lambda value: (print(f"Not bad! You got an {value}!"), case.Break())
    case['D'] = lambda value: (print(f"You received an {value}."), case.Break())
    case['F'] = case['D']

    # Case.default will run if it's defined and no other cases are ran.
    case.default = lambda value: print(f"Error: Unknown grade {value}")
#

I could allow a shorthand like...

case.ex[lambda v: v > 5] instead of case[case.ex(lambda v: v > 5)]

karmic kettle
#
class Switch:

    def __init__(self, value, default='default', dry=False):
        self.value = value
        self.cases = {}
        self.default = default
        self.dry = dry

    @property
    def choice(self):
        condition = self.value
        default = self.cases.get(self.default, None)
        return self.cases.get(condition, default)

    def __enter__(self):
        return self

    def __exit__(self, *_):
        if not self.dry:
            case = self.choice
            condition = self.value
            if case is not None:
                case(condition)
        return None

    def case(self, *cases):
        def decorate(func):
            for case in cases:
                self.cases[case] = func
            return func
        return decorate

mine has a pretty easy implementation

#

can even specify dry=True to stop the exit from running and use s.choice yourself

rare juniper
#
 with Switch(grade) as s:                    
                                             
     @s.case('A', 'B')                       
     def good(value):                        
        print(f'Good job, you got {value}!')
                                             
     @s.case('C')                            
     def notbad(value):                      
        print(f'Not bad, you got {value}.') ```

example of the above in action (reposted from [#python-discussion](/guild/267624335836053506/channel/267624335836053506/))
karmic kettle
#

ty 😄

rare juniper
#

that's pretty cool. Hmmm. So how does it work if you want to, say, break explicitly? I'm guessing that's the s.choice / dry thing?

#

Like, if I want two conditions to evaluate (only the second one breaks)... wat do

karmic kettle
#

Hmmm. Yeah Ill give that a shot.

#

OrderedDict to the rescue

rare juniper
#

yuppp

karmic kettle
#

and ill break with return value, if its False it breaks.

snow beacon
#

It might be difficult to implement, but case[case > 3] = lambda val: print("You got more than three") is valid Python.

rare juniper
#

Oh that's clever

pure dew
#

might require some ast hacks

#

/inspect as well

rare juniper
#

NO ASTS lollll

#

oh man

#

Just for performance reasons, the syntax would be nice

pure dew
#

ya'll gonna be like Procez over here

snow beacon
#

My proposed syntax could just have case implement a few comparison operators as continuations.

#

I saw a context manager that implemented __iter__ a while ago, so you could do with Switch(x) as case, default:

#

So those are some ideas.

rare juniper
#

Hmmm. Comparison overriding could get hairy fast. Not everything can be overridden -- like is

snow beacon
#

A special case (no pun intended) like case.is[None] = ... would suffice there.

rare juniper
#

Oh hmm, switch statements in other languages support modifying the value...

So like...

switch(x):
   case 9:
       x += 30

   case 10:
       x += 5

   case 15:
       x -= 6

so if x was 10 x would be 10, then 15, then 9, and I think only case 10 and case 15 would run

karmic kettle
snow beacon
#

If you knew it were called x you could do globals()['x'] and locals()['x']

#

That would let you update the value.

#

Perhaps if you called it with the name of your variable. with Switch('x') as case:

rare juniper
#

RooScared globals

snow beacon
#

What channel are we in again?

karmic kettle
#

#nintendo-switch

#
with Switch(grade) as s:

    @s.case('A', 'B')
    def good(value):
        print(f'Good job, you passed!')
    
    @s.case('C')
    def notbad(value) -> Break:
        print(f'Not bad, you got {value}.')

    @s.case('D', 'F')
    def bad(value):
        print(f'You recieved an {value}')

Decided to abuse type annotations instead.

rare juniper
#

OH NO LOL

#

BUT WHAT IF YOU WANNA ONLY BREAK CONDITIONALLY D:

karmic kettle
rare juniper
#

You gotta raise break

#

I think

#

orrr call a break function on s (which then raises break)

karmic kettle
#

Yeah that should work.

rare juniper
#

I support the latter 'cause you can't raise in lambdas

#

but both approaches are valid

#

s.case('C')(lambda value: (print(f'Not bad, you got {value}.'), s.Break())```
pure dew
#

functionally the same tho, yea?

rare juniper
#

yeah, just calling .Break() lets you do it in a lambda -- you can't use the raise keyword argument in one. Although, with the decorator approach, there's not a good reason to

#

I liked the returning False for break tho

snow beacon
#

What about None for not breaking, and any other value for breaking? That way, if your function doesn't return, it won't break.

rare juniper
#

breaking news

#

turns out

#

I don't understand how switches work

#

after the first one is true

#

all subsequent ones get evaluated without checking for the condition

#

.......................... fuck this LOL

snow beacon
#

Not too much of a change.

rare juniper
#

yeah but I'm suddenly horrified

snow beacon
#

Many languages automatically break after a case, which is simpler.

rugged sparrow
#

@rare juniper

>>> r = lambda e:(0for _ in()).throw(e)
>>> 
>>> r(Exception)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
  File "<stdin>", line 1, in <genexpr>
Exception
>>> ```
pure dew
#

cursed

rugged sparrow
#

i think imma try to rewrite my lambda try/except

#

3.8 broke the way it worked with no imports

snow beacon
#
import operator

no_value_given = object()

class UnfinishedCondition:
    def __init__(self, op, init_val, switch):
        self.op = op
        self.init_val = init_val
        self.switch = switch
        self.called = False
    def __call__(self, value):
        if not self.called:
            self.switch.add_case((self, value))
            self.called = True
        else:
            return self.op(value, self.init_val)

def relational_op(operator):
    def operate(self, value):
        return UnfinishedCondition(operator, value, self)
    return operate

class Switch():
    def __init__(self, value=no_value_given, autobreak=False):
        self.value = value
        self.cases = []
        self.autobreak = autobreak
    def __enter__(self):
        return self
    def __exit__(self, *_):
        if self.value is not no_value_given:
            return self.eval(self.value)
    def __iter__(self):
        yield self
        yield self.default
    def eval(self, value=no_value_given):
        match = False
        for condition, callback in self.cases:
            if condition(value) or match:
                match = True
                if callback(value) is not None or self.autobreak:
                    break
    def add_case(self, case):
        self.cases.append(case)
    def __setitem__(self, key, callback):
        if key == self.default:
            new_case = (lambda v: True, callback)
        else:
            new_case = (lambda v: v == key, callback)
        self.add_case(new_case)
    __eq__ = relational_op(operator.eq)
    __ne__ = relational_op(operator.ne)
    __gt__ = relational_op(operator.gt)
    __lt__ = relational_op(operator.lt)
    __ge__ = relational_op(operator.ge)
    __le__ = relational_op(operator.le)
    __contains__ = relational_op(operator.contains)
    is_ = relational_op(operator.is_)
    is_not = relational_op(operator.is_not)
    __call__ = eval
    default = object()
#

Oh, that's more code than I thought it was.

#

Anyway, here's a demo:

number = int(input("number: "))
with Switch(number, autobreak=True) as (case, default):
    case[42] = lambda x: print('neat!')
    (case > 100000)(lambda x: print("wow! I can't count that high!"))
    (case > 10)(lambda x: print(f"not 42, but {x} is still a big number."))
    case[default] = lambda x: print(f"What sort of number is {x}?")
#

You can also delay the evaluation of the switch until later, or evaluate it multiple times.

brazen geyser
#
class switch:
    def __init__(self, *inputs, default=None):
        self.inputs = inputs
        self.default = default

    def __call__(self, *cases):
        for case, result in zip(*[iter(cases)]*2):
            if callable(case):
                if case(*self.inputs):
                    return result
            elif self.inputs == case:
                return result
        else:
            return self.default


x, y, z = 1, 1, 1

result = switch(x, y, z, default='lol')(
    (1, 2, 3), 22,
    (4, 5, 6), 12,
    lambda a, b, c: a < b < c, y
)
#

keeping it simple

#
default = lambda *args: True

class switch:
    def __init__(self, *inputs):
        self.inputs = inputs

    def __call__(self, *cases):
        for case, result in zip(*[iter(cases)]*2):
            if callable(case):
                if case(*self.inputs):
                    return result
                
            elif self.inputs == case:
                return result


x, y, z = 1, 1, 1


result = switch(x, y, z)(
    (1, 2, 3), 22,
    (4, 5, 6), 12,
    lambda a, b, c: a < b < c, y,
    default, 'lol',
)

slightly cleaner with a different way of specifying default

zealous widget
snow beacon
#

I'd swap __call__ and __init__ so you can create the case without applying it yet.

brazen geyser
#

would have to jump through some hoops to implement the third case if thats done

#

specifically the fact that it returns y

#

would have to add some other way of specifying return the middle input or something like that

snow beacon
#

You could do the exact same thing, except you'd put the (x, y, z) after the call with all the cases.

brazen geyser
#

the intention is that youd be returning the middle input regardless of what the inputs actually are

#

so if that case was to return one specific middle input for a given set of inputs, there wouldnt be much point to create the switch without applying it

#

this way it's more... idk. semantically consistent?

#

i did write a version with them swapped btw

snow beacon
#
default = lambda *args: True

class switch:
    def __call__(self, *inputs):
        for case, result in zip(*[iter(self.cases)]*2):
            if callable(case):
                if case(*inputs):
                    return result
            elif inputs == case:
                return result
        

    def __init__(self, *cases):
        self.cases = cases


x, y, z = 1, 1, 1


result = switch(
    (1, 2, 3), 22,
    (4, 5, 6), 12,
    lambda a, b, c: a < b < c, y,
    default, 'lol',
)(x, y, z)``` Here's my attempt
brazen geyser
#

then switched to this when i encountered that third case

#

felt nicer

snow beacon
#
switcher_func = switch(
    (1, 2, 3), 22,
    (4, 5, 6), 12,
    lambda a, b, c: a < b < c, y,
    default, 'lol',
)
print(switcher_func(1, 11, 111))```
brazen geyser
#

youre missing my point

snow beacon
#

What's wrong with the third case?

#

Oh, right.

brazen geyser
#

the goal of the third case is to return the middle input

#

regardless of what it is

#

x, y, z are just example inputs

#

to demonstrate

#

not intended to be constants

snow beacon
#

I think the reverse from your implementation is more versatile, even if it doesn't work perfectly for the third case.

brazen geyser
#

i disagree. and i think having the inputs first is more in line with the classic idea of what a switch statement is.

#

looks-wise

grave rover
#
with switch(x):
    with case(1):
        ...
    with case(2):
        ...
    with case(lambda x > 10):
        ...
```something like this should be doable too shouldn't it?
#
@contextmanager
def case(target):
    value = case._value
    if (iscallable(target) and target(value)) or (value == target):
        yield

@contextmanager
def switch(value):
    case._value = value
    yield
    case._value = None
``` something like this?
#

Wait no that won't work

#

hmm...

#

Oh found a nasty way to do it

#

Gimme a few mins

#

Aaa I'm so close to getting this

#

Why can't with block cancel

grave rover
#

I could enable this behavior with a decorator

#

like ```py
@has_switch
def func():
with switch(x := 10):
with case(20):
...
with case(x > 3):
...

wind maple
#

make it non-cpython-dependent so I can use it in kython

grave rover
#

are people actually using kython now mmLol

grizzled cloak
#

What's kython

grave rover
#

Python interpreter in Kotlin

grave rover
wind maple
#

wdym

brazen geyser
#
This PEP proposes a new contextvars module and a set of new CPython C APIs to support context variables. This concept is similar to thread-local storage (TLS), but, unlike TLS, it also allows correctly keeping track of values per asynchronous task, e.g. asyncio.Task.
wind maple
#

no

brazen geyser
#

got this far then realised exceptions raised in __enter__ wont get sent to __exit__ lel

#

but probably outdated

wind maple
#

not that you couldn't do it before

brisk zenith
#

could you?

sick hound
#

well you could just manually write stuff to unparse it manually

wind maple
#

what I meant with "you couldn't" is that the people here probably would have figured it out if they wanted to yert

#

There's also a patch to clean up parenthesis

brazen geyser
#
a, b, c = 1, 2, 3

with switch(a, b, c):
    with case(lambda a, b, c: a < b < c):
        print('ayy 0')

        with switch(b, a, c):
            with case(2, 1, 3):
                print('nested switch!')

            with case(1, 2, 3):
                print('this wont be printed')

    with case(1, 2, 3):
        print('ayy 1')

        with case(lambda a, b, c: b == 2):
            print('holy shit a nested case!')

        switch_break()

    with case(1, 2, 3):
        print('ayy 2')
#

should be thread/async safe

#

@grave rover what do you reckon

#

did i do it right

#

oh hmm, on second look, needs some more work for threadsafety. bit confused on how to work with contextvars correctly here.

#
>>> import contextvars
>>> import threading
>>> var = ContextVar('vat')
>>> var.set('hello')
<Token var=<ContextVar name='var' at 0x00000202707B5C48> at 0x00000202707E0728>
>>> var.get()
'hello'
>>> def test():
    try:
        print(var.get())
    except LookupError:
        print('var not set in this context')
    var.set('12321')
>>> thread = threading.Thread(target=test)
>>> thread.start()
var not set in this context
>>> 
#

nevermind, it's fine

grave rover
#

@brazen geyser did you actually just abuse stackframes and settrace to skip the block

brazen geyser
#

abuse is a strong word :p

#

how about 'gently nudged'

marsh void
#

lOl

opal totem
#

Is there anything that ... can be replaced with in this code to make the assertion true? ```py
def sig():
yield 0

def fn():
return (lambda a: ...)(sig())

for v in fn():
assert(v == 0)```

#

The normal way to write it being yield from sig(), this actually cropped up in an attempt at using asyncio in one line

proper vault
#

iter(int,...)

#

... can be any value

#

probably not what you want though

#

a will probably do more along the lines of what you want

#
def sig():
  yield 0

def fn():
  return (lambda a: a)(sig())

for v in fn():
  assert(v == 0)```
spare tide
#

I keep looking at the name of this room in the sidebar like . . . Someday.

snow beacon
#

It is an arcane art steeped in mystery.

#

There is no paved path. You must find your own way here, as all do in the end.

rugged sparrow
pure dew
#

Speaking of esoteric, here's my side project idea

#

an HTML/CSS framework for building terminal UIs

proper vault
#

run electron in the bg and convert to terminal resolution and colors /s

pure dew
#

no thanks

#

im not having js involved

#

nor am i even having any networking

distant wave
#

Merge two strings:

#
def merge(a: str, b: str) -> str:
    if len(a) != len(b):
        raise ArgumentError("Strings must be same length")
    c = [" "]*len(a)*2
    c[::2] = a
    c[1::2] = b
    return ''.join(c)

>>> merge("123", "abc")
'1a2b3c'
grizzled cloak
#

sounds easy so far 😉

#

ah

distant wave
#

-.-

#

Some interesting onelineability

pure dew
#
>>> def merge(a, b):
...     return "".join(f"{ca}{cb}" for (ca, cb) in zip(a, b))
...
>>> merge("123456","abcdef")
'1a2b3c4d5e6f'
#

doesn't care if strings are same length

sick hound
#
merge=lambda a,b:''.join(sum(zip(a,b),()))```
pure dew
#

woah wat

distant wave
#
def merge(a, b):
    c= ([" "]*len(a)*2)
    return ''.join([[c for c[::2] in [a]], [c for c[1::2] in [b]]][1][0])
pure dew
#

oh nice thats clever @sick hound

distant wave
#
merge = lambda a, b, c=[]: ([None for c[:] in [[" "]*len(a)*2]]), ''.join([[c for c[::2] in [a]], [c for c[1::2] in [b]]][1][0]))[-1]
#
merge = lambda a, b, c=[]: ([None for c[:] in [[" "]*len(a)*2]], ''.join([[c for c[::2] in [a]], [c for c[1::2] in [b]]][1][0]))[-1]
#
merge = lambda a, b, c=[]: ''.join([c for c[:], c[::2], c[1::2] in [([*(" "*(len(a)<<-~False))],a, b)]][0])
#

I think I succeeded in making this pretty much unreadable

gilded orchid
#
merge=lambda a,b,c=[]:''.join([c for c[:],c[::[]==[]+[]==[]],c[[]==[]::[]==[]]in[([" "]*(len(a)<<-~False),a,b)]][[]==[[]]])```
#

remove all spaces and numbers

distant wave
#

Needs to have a - in front of the ~, typoed it

gilded orchid
#

ok fixed

#

what'd be a good way to obfuscate the '' and the " "

distant wave
#

chr()

#

and str()

#
merge=lambda a,b,c=[]:str().join([c for c[:],c[::2],c[1::2]in[([*(chr(True<<5)*(len(a)<<-~False))],a,b)]].pop(False))
gilded orchid
#
merge=lambda a,b,c=[]:str().join([c for c[:],c[::[]==[]+[]==[]],c[[]==[]::[]==[]]in[([(chr([]==[]<<5)]*(len(a)<<-~False),a,b)]][[]==[[]]])```
pure dew
#

oh this is an esoteric challenge, not a golf challenge?

distant wave
#

both

gilded orchid
#

it could probably be golfed a ton

distant wave
#

"Something that is clearly not a joke but will never be able to be clearly understood again"

gilded orchid
#

I'm just trying to make it look as dumb as possible

distant wave
#

I suppose you could call it the "Now only god knows" challenge

#
merge=lambda a,b,c=[]:str().join([c for c[:],c[::-~True],c[True::-~True]in[([*(chr(True<<5)*(len(a)<<-~False))],a,b)]].pop(False))
gilded orchid
#

if you want to golf it

#
lambda a,b:''.join(sum(zip(a,b),()))```
#

(I have no clue how that works but it does)

brazen geyser
#

zip yields a bunch of tuples

#

sum adds all their content together into one big tuple

#

join joins all the contents of this one big tuple

gilded orchid
#

what's with the () in sum?

pure dew
#

,() is the key bit

#

it defines the starting value

#

normally it'd be a number

distant wave
#
merge=lambda a,b,c=[]:str().join([c for c[:],c[False::-~True],c[True::-~True]in[([*(chr(True<<5)*(len(b)<<-~False))],a,b)]].pop(False))
pure dew
#

but in this case it makes a tuple that gets appended to

gilded orchid
#
lambda a,b:''.join(sum(zip(a,b),()))```
I wonder if this can be golfed anymore
snow beacon
#

lambda*s:''.join(sum(zip(*s),())) should work, possibly needing a space before the first *.

gilded orchid
#

I think python lambda*s:`sum(zip(*s),())`[2::5] works in python 2

#

which is shorter but it's python 2

wind maple
#

Unconventional challenge: make the most readable code for merge(*strings: str)

example:

merge('a', 'b', 'c')
'abc'

merge('abc', 'def', 'hijkl')
'adhbeicfjkl'

merge('abc', 'd', 'efg')
'adebfcg'
zealous widget
#
In [60]: strings = ('a','b','cde')

In [61]: "".join(strings)
Out[61]: 'abcde'
proper vault
#

do note that sum may fail on non-numeric inputs according to the spec IIRC

#
sum(iterable, /, start=0)
    Return the sum of a 'start' value (default: 0) plus an iterable of numbers

    When the iterable is empty, return the start value.
    This function is intended specifically for use with numeric values and may
    reject non-numeric types.```
zealous widget
#

oh, merge shuffles

#
In [71]: from itertools import zip_longest
    ...: strings = ('abc', 'def', 'ghi')
    ...: "".join(letter for row in zip_longest(*strings) for letter in row)
Out[71]: 'adgbehcfi'
#

is this more readable?

In [73]: from itertools import zip_longest, chain
    ...: strings = ('abc', 'def', 'ghi')
    ...: "".join(chain(*zip_longest(*strings, fillvalue='')))
Out[73]: 'adgbehcfi'
tame crow
#

zip_longest will need fillvalue='' to pass the tests

#

Otherwise it'll try to .join None's

#

(when strings have differing lengths)

zealous widget
#

fair

proper vault
#
#if the goal is readable, a for loop works well
def merge(*strings: str):
    out: str= ""
    for i in range(max(map(len,strings))):
        for string in strings:
            if i < len(string):
                out+=string[i]
    return out
zealous widget
#

+= is real bad performance-wise though for strings

#

better appending to a list and joining at the end

brazen geyser
proper vault
#

I think CPython optimizes it. The difference is marginal

#

sum is not supposed to work for non-numbers, and it is not the same as the above 2 snippets

brazen geyser
#

well, it does

zealous widget
#

i thought *s doesn't work with lambdas anymore

brazen geyser
#

that + some proper indentation and naming would be the nice goldilocks zone between readability and evil

#

imo

zealous widget
#

it does work

proper vault
brazen geyser
#

oh ok, so we have strings of variable length

brazen geyser
#
>>> from itertools import zip_longest
>>> def merge(*strings):
    return ''.join(
        character
        for merged_characters in zip_longest(*strings)
        for character in merged_characters
        if character is not None
    )

>>> merge('abc', 'def', 'hijkl')
'adhbeicfjkl'
>>> 

how bout this

#

oh hold on thats not right lol fixd

#

oh salt already did this one anyway

#

i think we gotta agree on how to rank readability first

#

@wind maple define most readable

snow beacon
#
def merge(*string_list) -> str:
    """
    Interleaves strings passed as arguments
    together into one string,
    by taking a character from each one in turn.
    When the end of a string is reached, it is removed
    from the round robin of characters.
    Note: returns a str, not a generator.
    """
    #fliter out empty strings
    string_list = [string
                   for string in string_list
                   if len(string) > 0]
    accumulator = ""
    while len(string_list) > 0:
        #iterate through every string until they're all gone
        next_strings = []
        for string in string_list:
            #split string into first character,
            #and a list of all other characters in it
            first_char, *rest_of_string = string
            #accumulator collects one character per string per cycle
            accumulator += first_char
            if len(rest_of_string) > 0:
                #filter the string out of next iteration if it's now
                #empty, otherwise, convert the list to a string, and
                #append it to the strings still left to process
                rest_as_string = "".join(rest_of_string)
                next_strings.append(rest_as_string)
        string_list = next_strings
    return accumulator
zealous widget
#

tl;dr

snow beacon
#

But if you had read it, I'm sure it would be the most readable function you'd ever beheld.

zealous widget
#

readable like canterbury tales, there's a lot to read, but no one wants to

snow beacon
#

Or the YAML spec.

#

This is why a definition of 'readable' would be useful.

pure dew
#

i prefer "grokkable"

grave rover
#

Damn, disappointed you can't sum() strings

gilded orchid
#

(for summing strings)

distant wave
#

It.. shouldn't..?

#

!e ```python
print(sum(['abc', '123'], ''))

night quarryBOT
#

@distant wave :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 | TypeError: sum() can't sum strings [use ''.join(seq) instead]
gilded orchid
#

Oh uh

#

It might be because the thing on my phone uses an old version of python

#

Yeah it uses 3.4, so that's probably why

distant wave
#

doesn't work in 2.7 or 3.7

gilded orchid
#

It's either the thing on my phone is buggy, or it worked in some versions between 2.7 and 3.7

#
sum = lambda x: __import__('functools').reduce(lambda a, b: a+b, x)```
#

Terrible replacement for sum that should work

edgy kelp
#

Terrible r placement that was used before sum was added :D

proper vault
#
sum = lambda a, b: (lambda f, a, l: f(f, a, l))((lambda f, a, l: f(f, a+l[0], l[1:]) if l else a), b, a)```
#

no imports

#

reduce used to not need importing

#
reduce = lambda op, a, b: (lambda f, a, l: f(f, a, l))((lambda f, a, l: f(f, op(a, l[0]), l[1:]) if l else a), b, a)```
snow beacon
#

I think I figured out a way to do it with the sum function.

#

I don't remember it now.

brazen geyser
#
>>> class DummyString:
    def __add__(self, other):
        return other

    
>>> sum(('afsf', 'sfdsdf', 'sadfasdf'), DummyString())
'afsfsfdsdfsadfasdf'
>>> 
snow beacon
#

I think that was it, yes. Except I called it AdditiveIdentity() to be descriptive.

#

It was in my multiplication code, from memory.

brazen geyser
#
>>> sum(('34234', '4353', 'sdfasdf'), type('', (), {'__add__':lambda a,b: b})())
'342344353sdfasdf'

one-liner-ized :p

vestal solstice
#

eval('"'+ '"+"'.join(strings) + '"')

distant wave
#

!e ```python
strings = ["123", "123123123", "asdfasdf"]
print(
eval(''.join(map(repr, strings)))
)

night quarryBOT
#

@distant wave :white_check_mark: Your eval job has completed with return code 0.

123123123123asdfasdf
distant wave
#

1 char shorter :P

vestal solstice
#

neat

snow beacon
#

I don't think I'm winning any awards with this one:python lambda*s:print(*s,file=(f:=__import__('io').StringIO()),sep="",end="")or f.getvalue()

proper vault
#

or as sequence of operations is Galaxy brain

snow beacon
#
lambda*s:(f:=__import__('io').StringIO()).getvalue(*filter(bool,(print(*s,file=f,sep="",end=""),)))
```I'm not sorry.
proper vault
#

lambda*s:(lambda f,a,s:f(f,a,s))(lambda f,a,s:f(f,a+s[0],s[1:],'',s) if s else a) not tested

formal sandal
#
f=lambda s:s[0]+f(s[1:])if s else""
#

But that's cheating

#

!e

f=lambda x,*y:x+((y or'')and f(*y))
print(f("Hello", "World", "1", "31415"))
night quarryBOT
#

@formal sandal :white_check_mark: Your eval job has completed with return code 0.

HelloWorld131415
proper vault
#

At least use walrus, so you can name it properly

snow beacon
#

What aboutpython merge=(lambda f:f(f))(lambda f:lambda x,*y:x+((y or'')and f(*y)) print(f("Hello", "World", "1", "31415")))

grizzled cloak
#

saddly that error message is actually part of the c code 😦 not something the string class evokes

/* reject string values for 'start' parameter */
        if (PyObject_TypeCheck(result, &PyBaseString_Type)) {
            PyErr_SetString(PyExc_TypeError,
                "sum() can't sum strings [use ''.join(seq) instead]");
            Py_DECREF(iter);
            return NULL;
}```
thin trout
#

You can also override sum()

#

So you can sum strings

snow beacon
#
from functools import reduce
add = lambda x, y: x + y
sum = lambda iterable, start=0: reduce(add, iterable, start)
thin trout
#

You can't start with 0

#

You need to start with ''

snow beacon
#

This is a replacement sum

#

sum starts with 0

proper vault
#

That would probably be slower than the normal sum for numbers, though

snow beacon
#

Python is about versatility rather than speed.

#

Original sum is implemented in C, so short of delegating to it for non-strings...

thin trout
#

I mean, if you start with 0, you can't add strings

proper vault
#

His sum variant can do that too: sum(map(str, range (88)),'')

thin trout
#

It... Doesn't work?

Traceback (most recent call last):
  File "<string>", line 5, in <module>
  File "<string>", line 3, in <lambda>
  File "<string>", line 2, in <lambda>
TypeError: unsupported operand type(s) for +: 'int' and 'str'```
proper vault
#

Did you set the starting value properly

#
add = lambda x, y: x + y
sum =lambda iterable:( lambda iterator: reduce(add, iterator, next(iterator)))(iter (iterable))```
crystal mica
#

You can do extra work to get rid of that initial

#

!e ```py
from functools import reduce
add = lambda x, y: x + y
sum = lambda iterable, start=0: reduce(add, iterable, '' if any(isinstance(x, str) for x in iterable) else start)

print(sum(map(str, range(88))))
print(sum(range(88)))

night quarryBOT
#

@crystal mica :white_check_mark: Your eval job has completed with return code 0.

001 | 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
002 | 3828
proper vault
#

Or just use the first element as the initial value

#

That way it works for anything that defines add

snow beacon
#

It's different from the base sum if so.

proper vault
#

It is

#
add = lambda x, y: x + y
sum =lambda iterable:( lambda iterator: reduce(add, iterator, next(iterator)))(iter (iterable))
print(sum(list(range(80)) for x in range(80)))```
zealous widget
#

whoa, i didn't know lambdas took default arguments

crystal mica
#

Hmm, interesting

#
print(sum([1, 2, 3, '4', 5, '6']))
# -------
TypeError: can only concatenate str (not "int") to str```
#

Time to fix add as well haha

#

!e ```py
from functools import reduce
add = lambda x, y: x + y if all(isinstance(i, int) for i in (x, y)) else f"{x}{y}"
sum = lambda iterable, start=0: reduce(add, iterable, '' if any(isinstance(x, str) for x in iterable) else start)

print(sum(map(str, range(88))))
print(sum(range(88)))
print(sum([1, 2, 3, '4', 5, '6']))```

night quarryBOT
#

@crystal mica :white_check_mark: Your eval job has completed with return code 0.

001 | 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
002 | 3828
003 | 123456
crystal mica
#

This is an abonimation

zealous widget
#

i found this in some forgotten folder the other day:

In [298]: my_list = [1,2,3,4]
     ...: accumulate = [j for j in [0] for i in my_list for j in [j+i]]

In [299]: accumulate
Out[299]: [1, 3, 6, 10]
grizzled cloak
#

what

proper vault
#

Cool

zealous widget
#

sort of abusing comprehension to define a variable

crystal mica
#

wow damn, that is cool

snow beacon
#

You can do this ```python
lambda a, *, b: None
lambda a, /, c: None

zealous widget
#

you can use this method to assign things temporarily in lambdas, i think

snow beacon
#

You could do a sum by taking ...][0] of it

zealous widget
#

yep, well the other end of it

snow beacon
#

Touché

proper vault
#

map(lambda *x:sum(x), *([0]*k+list_in[:(-k,None)[not k]] for k in range(len(list_in))))

grizzled cloak
#

i havent really been paying attention, but why shouldnt this work?

sum = lambda args: __import__("functools").reduce(lambda x,y: str(x)+str(y),args)```
#

or are we trying to avoid functools

proper vault
#

That will not work for anything other than strings

grizzled cloak
#

why not?

#
In[2]: sum = lambda args: __import__("functools").reduce(lambda x,y: str(x)+str(y),args)
sum(["hey", 1, "there"])
Out[3]: 'hey1there'```
#

oh

#

i see

#

wont work for actual summing

proper vault
#

Indeed. Shirus will work for multityped iterables as long as one of the types.is a.string, mine will work for lists of a single type that defines addition with itself

grizzled cloak
#
sum = lambda args: __import__("functools").reduce((lambda x,y: str(x)+str(y)) if any(map(lambda x: isinstance(x,str), args)) else (lambda x,y: x+y),args)
sum([1,2,3])
Out[17]: 6
sum([1,2,3,'h'])
Out[18]: '123h'```
#

whats the expected output for sum([1,2,3,'h'])?

#

is it '123h' or '6h'?

crystal mica
#

should be 123h, but 6h looks more fun!

zealous widget
#

sum all adjacent numbers and concatenate everything else

grizzled cloak
#

made it a bit shorter:

sum=lambda a:__import__("functools").reduce((lambda x,y:str(x)+str(y))if(str in map(lambda x:type(x),args))else(lambda x,y:x+y),args)```