#esoteric-python

1 messages · Page 86 of 1

proper vault
#

for example, fibbonaci numbers

COMBINATOR = lambda f, *args, **kwargs:f(f, *args, **kwargs)
FIBREC = lambda f, prev_fib, this_fib, limit: f(f, this_fib, prev_fib+this_fib, limit) if this_fib < limit else prev_fib
GREATEST_FIBBONACI_UP_TO_N = lambda n: COMBINATOR(FIBREC, prev_fib=1, this_fib=1, limit=n)
cursive plover
#

wdym when you say Combinator

zealous widget
#

i use this one:

Y = lambda f:(lambda x: f(lambda z:x(x)(z)))(lambda x:f(lambda z:x(x)(z)))
proper vault
#

ye, that is the more usual one

#

in actual lambda calc that is

#

essentially, all the combinator I used does is call f and pass f it as the first arg

zealous widget
#

well the lambda cal one is:

Y = lambda f:(lambda x: f(x(x)))(lambda x: f(x(x)))
#

but the previous one prevents python from evaluating all the arguments

proper vault
#

actually, that is the Z combinator, is it not?

#

pretty sure Z combinator is Y combinator adjusted for strict langs

cursive plover
#

all this is so complex, did you just discover it along the way just like that or is there some place you picked it up from?

#

I'm not even sure if there's someone who actually teaches this

zealous widget
#

if you use ipython and you want it to use this input:

import re

__λ__ = re.compile(r'λ[a-z]+[.]')

def __λ_sub__(m):
    m = m.group()
    return f'lambda {", ".join(m[1:-1])}:'

def _transform_λ(lines):
    return [__λ__.sub(__λ_sub__, line) for line in lines]

get_ipython().input_transformers_cleanup.append(_transform_λ)
#

only works for single letter variables

#

my regex isn't good enough

fiery hare
#

Is there ever a time when it makes sense to implement __del__ for a class?

#

if it's not guaranteed that it will actually be called, it seems like the only use case is if you want to log when something gets garbage collected.

#

When I first learned about it, I wanted to use it to make sure that certain cleanup behavior always happens for a certain type for if context management would require the with block to be too long.

zealous widget
#

i tried to implement it for a subclassed set i had, but it wasn't reliable

brazen geyser
#

if it's a hard crash there's no guarantee that context managers get to do their thing either

#

that doesnt make them useless

#

i've used __del__ to do clean up for objects representing posix/sysv shared memory segments, because unfortunately there's no way to make the kernel do it automatically.

#

basically any time you have an object whose lifespan extends further than a single block, with resources that the gc cant handle, del is your friend

#

!pep 442

night quarryBOT
#
**PEP 442 - Safe object finalization**
Status

Final

Python-Version

3.4

Created

2013-05-18

Type

Standards Track

brazen geyser
#

iirc the changes made here guarantee __del__'s invocation as much as any context manager

fiery hare
#

@brazen geyser I'm going to take a look at this.

#

I thought that __del__ was especially unlikely to be called if the object isn't garbage collected by the end of the program

#

though I guess I'll see what this says

brazen geyser
#

far as i understand, this entails that ALL references get broken down as part of finalization, including cyclical ones, which would be where the main concern about it not being called would come from.

fiery hare
#

On a similar note

#

I had the idea that the language could be changed so that the compound key word global del would delete the object with a given reference directly, rather than just removing one reference

#

And I'm pretty sure this is a terrible idea

#

Because there are probably many changes that would need to be made to the language's implementation so that you'd get a new exception type if you delete an object before the last time it gets referenced.

#

So the question is, given that the garbage collector will be there regardless, is there a case where you could get better performance if you could destroy an object at a specific time?

brazen geyser
#

so essentially, a version of gc.collect that'll be able to target a specific object instead of all garbage?

#

Because there are probably many changes that would need to be made to the language's implementation so that you'd get a new exception type if you delete an object before the last time it gets referenced.

the machinery for this part is already in place pretty much
https://docs.python.org/3/library/gc.html#gc.get_referrers

fiery hare
#

@brazen geyser maybe I'm misunderstanding what that function does. Doesn't it just give you a fresh set of references to objects that are referred to elsewhere?

#

I assume this doesn't change the fact that you can't force-delete those objects.

brazen geyser
#

this let's you know if the object is ready to be deleted

#

i.e. still being referred to somewhere

fiery hare
#

So if, for some reason, you wanted to delete an object for which references will still be used later on in the code, you can't do that?

#

This is probably a good thing. I'm just thinking that it still has the same limitation of the del keyword.

brazen geyser
#

im bringing it up in reference (heheh) to this part of your idea:

Because there are probably many changes that would need to be made to the language's implementation so that you'd get a new exception type if you delete an object before the last time it gets referenced.

don't think there would be too many changes needed to raise an exception if you try to force delete an object before its last reference. the GC already has ways of tracking live referents/referrers so that could be tapped into.

#

as indicated by gc.get_referrers

stark fable
#

technically it would be possible to artificially force-delete an object with no checks using ctypes

#

if there was actually still a reference to it then weird things happen```py

import ctypes
def force_delete(obj):
... ctypes.c_size_t.from_address(id(obj)).value = 0
...
obj = [1, 2, 3]
force_delete(obj)
pbj
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'pbj' is not defined
obj
[1, 2, 3]
obj.append(4)
obj
[]```

lament tendon
#

TIL you can use Δ as a variable name in python

#
>>> Δ = 0
>>> Δ += 1
>>> Δ        
1
>>> 
proper vault
#

ye, python lets you use most unicode letters

lament tendon
#

that is actually dope

#

does this violate pep8 i wonder

muted locust
#

will it run on different systems? like if there's something that's latin1 that uses this would it cause an issue or not?
I've only bumped into encoding problems a bit

lament tendon
#

pretty sure it will since python is interpreted

proper vault
#

pretty sure python uses UTF-8 pretty insistently

#

some editors may not like it though

muted locust
#

i'm not too sure - i thought utf8 was default but it's not in somethings, it has to be given explicitly in pyreadstats at least for reading spss files

half thorn
#

γκουντ τζομπ

vestal solstice
#

"good job"

fiery hare
#

I feel like there's a lot of redundancy in how __eq__ and __hash__ get implemented; they usually work on the same instance variables.

#

is there a class decorator or something that lets you specify which instance variables are meant to identify that instance?

#

maybe a decorator that gives you an __identity__ method?

#

I might attempt to implement it myself for the learning experience if it hasn't already been done.

bitter iris
#

Well, as you said, you could override the hash if there isn't any dunder eq. If there is, you could just use dunder eq. Well if you dont want to deal with them just use dataclasses with field(compare=False/True, hash=False/True)

fiery hare
#

@bitter iris what if you don't want everything that dataclasses do?

brazen geyser
#

@stark fable is this really a deletion

#

oh artificially force-delete

bitter iris
#

what if you don't want everything that dataclasses do?
well, you can pretty much control what should generated and what shouldn't with like dataclass(init=False, repr=False, ...) etc.

trail vault
#

Is there any reason why list(dict.keys()) should be used instead of simply list(dict) to get a list of keys in a dict?

#

I'm curious though, because that quote is from 3.8 docs whereas the 3.6 version states:

Performing list(d.keys()) on a dictionary returns a list of all the keys used in the dictionary, in arbitrary order (if you want it sorted, just use sorted(d.keys()) instead).

rugged sparrow
#

Backwards compatibility I believe

twin torrent
#

Another thing is that it's readable. I know when I see list(dict.keys()) that you are getting a list of keys of the dict, when I see list(dict) it isn't 100% clear, you have to know that list(dict) returns only the keys to know what's going on there

earnest wing
#

Yeah, it's not clear at first glance that dict's __iter__ only goes through keys, although most people learn after the first try.

proper vault
#
from optics import lens
from collections import namedtuple
T = namedtuple("T", "a b c")

>>> lens.of([[{'u':T(1,2,[5,6])}]])[0][0]['u'].c[1] << 12 
[[{'u': T(a=1, b=2, c=[5, 12])}]]
```not exactly useful, but fun
sick hound
#

probably the ugliest thing i ever wrote that worked

#

x = ast.literal_eval(json.loads(json.dumps(tst.replace('null','""'))))

#
newresp = '['+myresp[myresp.find('[')+1:myresp.find('],"')]+']' 
filename = str(message.id) + '.txt'
tst = re.split('(,{)', newresp)
#

or this

#

from the same project lemon_sentimental

snow beacon
#

Is literal_eval safe?

fallen heath
#

Yes

#
ast.literal_eval(node_or_string)
Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

This can be used for safely evaluating strings containing Python values from untrusted sources without the need to parse the values oneself. It is not capable of evaluating arbitrarily complex expressions, for example involving operators or indexing.```
bitter iris
#

There are bunch of errors it might raise, if you catch them all and have a maximum input length. It is safe~ish.

limber orchid
#

Semi-proud of creating this reversed exponential distribution list for any m items using listen comprehension:

m = 4
e = 2.5
[e**i/(sum([e**j for j in range(m)])) for i in range(m)][::-1]

Not much, but we're getting there ^^

fiery hare
#

Someone on the python ideas forum suggested a system for streamlining __init__ implementations where the attributes being assigned have the same name as the parameter

#

It looks like you can do it using a decorator and inspect.signature, but I can't shake the feeling that there's something horribly wrong with that idea.

rugged sparrow
#

You already have dataclass which is similar

fiery hare
#

I guess

#

but you might want to have a class with class attributes

#

whereas with dataclass, all your class attributes become part of the __init__, among other things.

desert garden
#

Is there a way to get hold of the current stack being used by the internal VM, without modifying cpython?

rugged sparrow
#

You can get frames

#

If that’s what you mean

desert garden
#

What I'm after is the stack that individual bytecode instructions push and pop from

#

So say LOAD_CONST 0 was run, I'd like a way to view the internal stack that now has whatever co_const[0] was sat at the top

#

(I've got a settrace running on every instruction)

#

I have a suspicion there's no way to do it in vanilla cpython

rugged sparrow
#

You can def do it with ctypes. It'll just be tricky probably

edgy kelp
#

verbose python?

#

!e

exec("""\
\N{LATIN SMALL LETTER D}\N{LATIN SMALL LETTER E}\N{LATIN SMALL LETTER F}\N{SPACE}\N{LATIN SMALL LETTER F}\N{LATIN SMALL LETTER U}\N{LATIN SMALL LETTER N}\N{LATIN SMALL LETTER C}\N{LEFT PARENTHESIS}\N{RIGHT PARENTHESIS}\N{COLON}
\N{SPACE}\N{SPACE}\N{SPACE}\N{SPACE}\N{LATIN SMALL LETTER P}\N{LATIN SMALL LETTER R}\N{LATIN SMALL LETTER I}\N{LATIN SMALL LETTER N}\N{LATIN SMALL LETTER T}\N{LEFT PARENTHESIS}\N{QUOTATION MARK}\N{LATIN CAPITAL LETTER H}\N{LATIN SMALL LETTER E}\N{LATIN SMALL LETTER L}\N{LATIN SMALL LETTER L}\N{LATIN SMALL LETTER O}\N{COMMA}\N{SPACE}\N{LATIN SMALL LETTER W}\N{LATIN SMALL LETTER O}\N{LATIN SMALL LETTER R}\N{LATIN SMALL LETTER L}\N{LATIN SMALL LETTER D}\N{EXCLAMATION MARK}\N{QUOTATION MARK}\N{RIGHT PARENTHESIS}
\N{LATIN SMALL LETTER F}\N{LATIN SMALL LETTER U}\N{LATIN SMALL LETTER N}\N{LATIN SMALL LETTER C}\N{LEFT PARENTHESIS}\N{RIGHT PARENTHESIS}
""")
night quarryBOT
#

@edgy kelp :white_check_mark: Your eval job has completed with return code 0.

Hello, world!
snow beacon
#

I seem to recall a coding that allows escape sequences in code without the exec.

proper vault
edgy kelp
#

how deep can we go

proper vault
#

probably about 10MB is the limit of what you can trivially paste

desert garden
#

@rugged sparrow I did some digging into cpython's eval functions and it turns out it was easier that I'd though. Not all of the PyFrameObject variables are exposed normally, so a quick ctypes cast gave me access to f_stacktop, which is a pointer to the stack

rugged sparrow
#

Nice

hushed chasm
#

!e

m = 4
e = 2.5
print([e**i/(sum([e**j for j in range(m)])) for i in range(m)][::-1])
night quarryBOT
#

@hushed chasm :white_check_mark: Your eval job has completed with return code 0.

[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
formal sandal
#

!e

# Golfed version
m,e=4,2.5
print([e**i/sum(e**j for j in range(m))for i in range(0,m,-1)])
night quarryBOT
#

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

[]
formal sandal
#

oops

#

!e

# Golfed version
m,e=4,2.5
print([e**i/sum(e**j for j in range(m))for i in range(m,0,-1)])
night quarryBOT
#

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

[1.5394088669950738, 0.6157635467980296, 0.24630541871921183, 0.09852216748768473]
formal sandal
#

I screwed it up...

#

Oh, the range goes from m to 1.

stark fable
#

!e py m,e=range(4),2.5;print([e**i/(sum(e**j for j in m))for i in m][::-1])

night quarryBOT
#

@stark fable :white_check_mark: Your eval job has completed with return code 0.

[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
stark fable
#

@formal sandal that's 4 characters shorter than yours and it actually works

formal sandal
#

👍

#

!e

m,e=range(4),2.5;print([e**i/sum(e**j for j in m)for i in m][::-1])
night quarryBOT
#

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

[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
rugged sparrow
#

!e ```
*m,e=3,2,1,0,2.5;print([ei/sum(ej for j in m)for i in m])

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
rugged sparrow
#

@formal sandal @stark fable cut some length off by getting rid of the [::-1] at the end by removing the range

formal sandal
#

true, but this solution is not enterprise-ready as it doesn't scale well!

proper vault
#
(lambda r:(lambda w, g=set():{(lambda j:[print(j),('_'in j or quit("Win")),(lambda f:print(*f)or (len(f)>6and quit("Lose")))(g-{*w})])(''.join(('_'+c)[c in g] for c in w))and g.add(input()) for _ in iter(int,1)})(r(open('dict.txt').readlines())[:-1]))(__import__('random').choice)
```hangman in one line (any inputs that are not exactly 1 char are undefined behavior)
rugged sparrow
#

I don't think any of those solutions are "enterprise ready"

#

@proper vault you could __import__('sys').stdin.read(1)

proper vault
#

Then I would have to filter out newlines

rugged sparrow
#

Afaik it does that by default

#

I used that trick for my minesweeper

hushed chasm
#

lol

#

was not my code to begin with

#

just wanted to see what it did

rugged sparrow
#

@proper vault but it depends on the implementation

stark fable
#

Then i would have to filter out newlines
Afaik it does that by default
does it? ```py

import sys
[sys.stdin.read(1) for _ in range(20)]
hello
world
qfimqfw
['h', 'e', 'l', 'l', 'o', '\n', 'w', 'o', 'r', 'l', 'd', '\n', 'q', 'f', 'i', 'm', 'q', 'f', 'w', '\n']```

rugged sparrow
#

Depends on the implementation afaik

#

My python app on my phone does it

#

But just in case you could always just .replace

rugged sparrow
#

?

hushed chasm
#

meant for bee

#

sorry

rugged sparrow
#

its all g

hushed chasm
#

fixing my message

#

actually now I'm confused

zealous widget
#

here's a challenge from the doc for assert:

Assignments to "__debug__" are illegal.  The value for the built-in
variable is determined when the interpreter starts.
#

so, assign something to __debug__

stark fable
#

that sounds difficult ```py

import dis
dis.dis('debug')
1 0 LOAD_CONST 0 (True)
2 RETURN_VALUE```

proper vault
#

ye, that is a parser special case probably.

#

#coding is one way

bitter iris
hollow patrol
#

I wish I could execute it on !e

#

But it's 4000 characters

#

I made a chains thing that allows you to use anonymous functions with more logic

#
print(
  Chain('a').
  iter(x = [1, 2]).
    iter(y = [1, 2]).
      print(v.a, '---', v.x, v.y).
    end().
  end()
)```
formal sandal
#

Is v like a global object?

rugged sparrow
#

@hollow patrol i still think you should have used ctypes to push the vars into the local scope

hollow patrol
#

Yes, @formal sandal it is

#

@rugged sparrow Maybe

rugged sparrow
#

it would be tricky but the end result would be clearer

hollow patrol
#

Chains aren't immediately evaluated, they're functions

#

And I'm not sure how I would do that

#

That would be very tricky

rugged sparrow
#

when iter(var='whatever') is called, you push var into the local scope, and when that iter ends, you remove it. (or you dont like python does natively)

hollow patrol
#

yeah

#

but that would require a lot of ctypes magic

#

and v.a is simpler for me to do

rugged sparrow
#

actually wait i have an idea

#

!e ```py
def f():
import inspect
inspect.currentframe().f_locals['a'] = 1
print(a)

f()

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 6, in <module>
003 |   File "<string>", line 4, in f
004 | NameError: name 'a' is not defined
rugged sparrow
#

dang

formal sandal
#

It's a bit more complicated than that

rugged sparrow
#

yea ik

#

trying something else

formal sandal
#

Here's a crazy thing using inspect.

def namespace(*, glob=None, fn=lambda x: x) -> Callable[[Callable], AttrDict]:
    frame = inspect.currentframe().f_back
    def _namespace(function_to_hack_open) -> AttrDict:
        nonlocal _namespace, glob
        _namespace.__name__ = f"namespace({function_to_hack_open.__name__}"
        source = dedent(inspect.getsource(function_to_hack_open))
        tree = ast.parse(source)
        glob = {**frame.f_globals, **(glob or {})}

        names_before = set(glob.keys())

        tree.body = tree.body[0].body

        """
        tree               tree
        before:            after:
        def fn():          a = 1
            a = 1          b = 2
            b = 2
        """
        exec(
            compile(
                tree,
                f"<namespace{function_to_hack_open.__name__}>",
                "exec"),
            glob
        )

        names_after = set(glob.keys())

        new_keys = names_after - names_before - {"local_names_before"}
        #
        # we have to subtract that set because `local_names_before`    ^
        # is defined after the collection of `locals()`:
        #      local_names_before = set(locals().keys())
        #

        return AttrDict({key: fn(glob[key]) for key in new_keys})    
    return _namespace
#

I don't remember if I showed this here.

rugged sparrow
#

that works

formal sandal
#

^

@namespace
def Numbers():
    e = pi = 3
    def hello():
        print("Hello, world!")

is equivalent to:

e = pi = 3
def hello():
    print("Hello, world!")
Numbers.e = e
Numbers.pi = pi
Numbers.hello = hello
#

So it's like a class with only static members

rugged sparrow
#

ofc for mine to work youd actually need sys._getframe(1)

#

cause youd need to update the outer scope

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

1
rugged sparrow
#

bet

#

@hollow patrol that code there would work ^

hollow patrol
#

@rugged sparrow That won't work on other python implementations

rugged sparrow
#

thats true

#

turns out that doesnt actually work anymore

formal sandal
#

I think it should work on CPython and pypy.

rugged sparrow
#

doesnt work inside of a secondary scope

#

but i think thats cause i implemented wrong tbh

#

!e ```py
import ctypes
import sys
def register(**kwargs):
frame = sys._getframe(1)
frame.f_locals.update(kwargs)
ctypes.pythonapi.PyFrame_LocalsToFast(ctypes.py_object(frame), ctypes.c_int(0))

f = lambda b=2:[register(b=3),print(b),register(a = 1),a]
print(f())```

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | 3
002 | Traceback (most recent call last):
003 |   File "<string>", line 9, in <module>
004 |   File "<string>", line 8, in <lambda>
005 | NameError: name 'a' is not defined
rugged sparrow
#

ahh ok

#

so i can mod an existing var but i cannot add

#

i think if you can mod the upper code object and add a STORE_FAST opcode (and add the required stuff to co_varnames it might work?

gilded orchid
#

is there an efficient way to replace an item at a specific index a list, in a lambda?

#

I could use a list comprehension but then I'd have to loop through every item of the list each time which seems dumb

proper vault
#

there is the dumb way of

lambda l, i: l.__setitem__(i, new_value) or l
snow beacon
#

Add two slices to the new item?

proper vault
#

that is akin to iterating over the whole list

snow beacon
#

Something like l[:i]+[v]+l[i+1:].

#

Oh, you mean that sort of efficient.

#

I'd use a lazy list with caching that generates each element as needed.

rugged sparrow
#

lambda l,i,o:l.insert(i,o) or l.pop(i+1) this replaces the item at the index, and returns the item that was replaced

zealous widget
#

is there a way to pass the module a class comes from into the __prepare__ method of its metaclass

brisk zenith
#

might it be possible to get it from cls.__module__?

marsh void
#

that's a name of the module

brisk zenith
#

indeed it is.

#

but it might still be possible to get it from that.

marsh void
#

ahhh

bitter iris
#

does __prepare__ receives the class? It might receive the metaclass itself (with classmethod), but I'm not sure if it can receive the actual class before it's construction

zealous widget
#

prepare only recieves a string

#

of the class name

#

not the class itself

#

i can use that string to search modules

bitter iris
#

yes, that was what I thought. It can't receive an unconstructed class ?

zealous widget
#

with sys.modules

#

i know i can use kwargs in the class def to pass the module name, but i'm not happy with that solution

bitter iris
#

hahaha, just posted that solution

zealous widget
#

prepare returns a heavily modified kind of defaultdict, but i want to make sure a name isn't in that classes namespace before i add it to the class dict

zealous widget
#

i thought of a solution: let the defaultdict add a dummy object then in __new__ we can replace all the dummy objects with the actual objects i want after checking the __module__

#

maybe that works

formal sandal
#

You can write something similar to macropy.

#

A brand new module management system.

zealous widget
#

this strategy worked pretty well with __new__ managing everything

formal sandal
#

No overengineering this time, then.

zealous widget
#

is there a maintained pretty printer for AST trees? i can only find old ones

bitter iris
#

astpretty is active

#

Also ast.dump itself got indent option recently for pretty printing

zealous widget
#

i thought about making one with bars | if it doesn't exist yet

bitter iris
#

How would it will look

formal sandal
#

I guess, like this

parent
|
+--- child
     |
     +--- grandchild
     |
     +--- grandchild(hello="world")
bitter iris
#

Hmm, interesting. Never seen such a printer for python's AST

zealous widget
#

something like that, but prettier

#

actually i could just wrap astpretty, would be easiest

formal sandal
#

You could also export into graphviz.

#

But it's such a pain in the ass... At least from my experience

zealous widget
#

hows this

#

maybe i should kill the brackets

#

oops, i have a hard-coded string in my function

#

which is why the tree doesn't match the expression

#
In [258]: pp('2 + 3 == 25 / (7 - 2)')
Expr(
└───value=Compare(
|   └───left=BinOp(
|       ├───left=Constant(value=2, kind=None),
|       ├───op=Add(),
|       └───right=Constant(value=3, kind=None),
|       ),
|   ├───ops=[Eq()],
|   └───comparators=[
|       └───BinOp(
|           ├───left=Constant(value=25, kind=None),
|           ├───op=Div(),
|           └───right=BinOp(
|               ├───left=Constant(value=7, kind=None),
|               ├───op=Sub(),
|               └───right=Constant(value=2, kind=None),
|               ),
|           ),
|       ],
|   ),
)
#

close, but not quite

rugged sparrow
#

i like it

#

maybe make the brackets an optional arg

sick hound
#

i suggest something like this, doesn't have to be xml, just wanna illustrate where i would place the operator

<expr>
  <bin op="eq">
    <bin op="add">
      <number>2</number>
      <number>3</number>
    </bin>
    <bin op="div">
      <number>25</number>
      <bin op="sub">
        <number>7</number>
        <number>2</number>
      </bin>
    </bin>
  </bin>
</expr>
proper vault
#

I would perhaps prefer an image for this like antlr4 does

zealous widget
#
In [353]: pp('2 + 3 == 25 / (7 - 2)')
Expr
└───Compare
    ├───BinOp
    |   ├───Constant
    |   |   └───2
    |   ├───Add
    |   └───Constant
    |       └───3
    ├───Eq
    └───BinOp
        ├───Constant
        |   └───25
        ├───Div
        └───BinOp
            ├───Constant
            |   └───7
            ├───Sub
            └───Constant
                └───2

i've got this so far

formal sandal
#

That looks way better than the standard printer.

zealous widget
#

i'm about to sleep, i can post the code if someone wants to tinker with it in the mean time

formal sandal
#

I'm totally interested.

#

Are you transforming the AST into some generic tree? Maybe you could then embed it into HTML so that you can fold and unfold the nodes.

zealous widget
#

i'm basically walking over _fields

zealous widget
#

ok, i cleaned it up a bit

#

this is the best function i've ever made though:

def snake(head, tail):
    yield head
    while 1: yield tail
formal sandal
#

lol

mild swan
#

hehehe

formal sandal
#

!e

def python(head, tail):
    yield head
    while 1: yield from tail()
tail = lambda: snake
snake = python(1, tail)
print(*snake)
night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 6, in <module>
003 |   File "<string>", line 3, in python
004 | ValueError: generator already executing
formal sandal
#

huh

zealous widget
#

i've never seen that error message

formal sandal
#

same

zealous widget
#

you can pass the indent level into the function now

#

i wanted to see if it would break for indent=0

#

but i got this instead:

In [378]: pp('2 + 3 is not 25 / (7 + 2)', 0)
Expr
└Compare
├BinOp
|├Constant
||└2
|├Add
|└Constant
|└3
├IsNot
└BinOp
├Constant
|└25
├Div
└BinOp
├Constant
|└7
├Add
└Constant
└2
formal sandal
#

Maybe you could replace it with an indenter_strategy (for the lack of a better name). It's a function that takes an int and returns an indentation string..

#

Or maybe this whole thing could be generalized.

#

So that it can be ported to HTML or something like that.

zealous widget
#

you can mess with the pieces in the class holding all the strings

#

i dunno anything about html though

#

or any web stuff, that's way past me

marsh void
#

@zealous widget man this printer looks sexy Pog

zealous widget
#

thanks, i'll bugcheck it in 12 hours or so

#

the gist above has all the updated code, gn for now

marsh void
#

gn

formal sandal
#

gn

sudden osprey
#

gn

formal sandal
#
snake("gn for now", "gn")
marsh void
#

eheheh

zealous widget
#

i had to refactor it to do function and class defs, but it's probably nicer now:

In [485]: pp('class Snake:\n    def __init__(self):\n        self.species = "Python"')
ClassDef
├──Snake
└──FunctionDef
   ├──__init__
   ├──arguments
   |  └──arg
   |     └──self
   └──Assign
      ├──Attribute
      |  ├──Name
      |  |  ├──self
      |  |  └──Load
      |  ├──species
      |  └──Store
      └──Constant
         └──Python

it's also trivial to add field names to this

rugged sparrow
#

@zealous widget you can generate AST from code objects right?

zealous widget
#

yep

rugged sparrow
#

does pp support that?

#

cause that would be dope

zealous widget
#

no, but it would be easy to add a conditional at the start of it

#

to check type

#

oh nevermind, can't go from code object to ast

#

can go from ast tree to code object though with compile

rugged sparrow
#

ah ok

#

you could use inspect.getsource to pseudo support it

zealous widget
#

that's true

#

can do this:

def pformat(code, indent=DEFAULT):
    if not isinstance(code, str):
        code = getsource(code)
    ind.indent = indent
    tree = ast.parse(code).body[0]
    return '\n'.join(stringify(tree))
#

will fail for things defined in console

rugged sparrow
#

true

#

i wonder if inspect could use console history support to implement getsource for the console

zealous widget
#

well, it's probably fine, if you defined something in the console, you have easy access to the text

rugged sparrow
#

true

#

i think i might write a getsource that works in the interpreter tbh

zealous widget
#

where does the console store the history and can get access to it

rugged sparrow
#

i think readline handles it

#

yea readline does

#

i wish readline provided an iterator :/

#

actually

#
def get_history():
  index = readline.get_current_history_length()
  while (line := readline.get_history_item(index)) is not None:
    yield line
    index -= 1
#

that should loop over the whole history backwards

#

And I can look for class and def and all other assignments using regex to find the most recent source object

glacial rampart
#
🐍 f'{foo bar}'
  File "<fstring>", line 1
    (foo bar)
         ^
SyntaxError: invalid syntax

why does it convert
the {} to ()?

edgy kelp
#

just what it places the expression into

snow beacon
#

It has no comma so it isn't a tuple, but if it had squiggly brackets it would be a set.

bitter iris
#

Python automatically inserts them to allow spaces in the start of expressions

#
>>> a = 5
>>>  a
  File "<stdin>", line 1
    a
    ^
IndentationError: unexpected indent
>>> ( a)
5
>>> f"{ a}"
'5'
fiery hare
#

I see this channel has been moved

vague gust
#

you're a real channel now

rugged sparrow
#

its like a promotion

rugged sparrow
#

!e ```py
import os
os.close(0)

night quarryBOT
#

@rugged sparrow :warning: Your eval job has completed with return code 0.

[No output]
rugged sparrow
#

!e ```py
import os
os.close(0)
print(1)

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

1
rugged sparrow
#

os.close(0) closes python's stdin, which triggers the interpreter to close (without throwing an exception)

#

could be used to make a module that only allows imports from non-interpreter (and will force close the interpreter if imported there)

rugged sparrow
#

!e ```py
r = lambda n,l=0,h=100:[*map(lambda m:((id(m)-l)%(h-l))+l,[[]for()in[()]*n])]
print(*r(10))
print(*r(10,h=5))
print(*r(10,l=50))

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

001 | 12 48 20 44 80 16 88 96 32 76
002 | 2 3 0 4 0 1 3 1 2 1
003 | 62 98 70 94 80 66 88 96 82 76
dusky dagger
#

This channel been moved?

rugged sparrow
#

seems like it

#

r = lambda n,l=0,h=100:[*map(lambda m:((id(m)-l)%(h-l))+l,[{}for()in[()]*n])] this can be used to generate n pseudo random numbers between l and h-1. it uses id so its relying on the garbage collector to cause the dicts to be stored at new addresses

edgy kelp
#

Get string ids and you have nice randomness on top of that

rugged sparrow
#

string ids are more random?

#

problem is that small strings and consistently used strings are interned which removes the randomness

#

best use of that func would be to generate a list of random numbers the length of every random val of that size you need and then pop the values off the list

edgy kelp
#

Oh, meant hashes. Those are salted for str/bytes so you could do some hacks with subprocesses

#

For a very roundabout randomness so I guess not really what you were going for with the short one above

rugged sparrow
#

yea that was more an attempt for something close enough to random that doesnt need any imports

lofty bison
#

hi, i am new to python . I will be glad if anyone can put me through in creating obfuscating letter

formal sandal
#

||A||

formal sandal
#

Has anyone seen the object system in OCaml? It seems to be very nice.

glacial pulsar
#

interesting

agile crane
#

Hey i dunno if this counts as 'esoteric' but is there a way to get a decorator to access everything that it's passed function has sent to stdout during the call? What i'm trying to monkeypatch is a decorator that catches any instances where 'ERROR' is printed to screen and then takes an action, basically sending an alert

#

I mean, i realise now that probably i should just enforce all the codes do proper exception throwing and then use try catch in the decorator...hmmm

#

the problem is that might mess with existing try catch stuff

#

i guess i could catch, send alert, re-throw same thing? might make the traceback a bit shit

rugged sparrow
#

You could wrap the func with contextlib.redirectstdout

agile crane
#

Ah man so many core packages i don't know enough about, thanks!

#

Next question 😄 : loguru, and probably other packages, do a cool thing where you can import loguru in your main thing, add a logger, and then import loguru in a different module (which might get imported into main) and everything still lines up nicely with the global logger. How is this usually done? Naively i would think you would instantiate something as soon as the logging module is imported, but doesn't that get overridden on multiple imports in different modules/files, or is that not how importing works? Is there some kind of #pragma once equivalent? I had a look into loguru spcifically but there's a bunch of other stuff going on there too which made it hard to easily get at this answer

snow beacon
#

It might remove itself from the module list. I think it's in sys.

#

I've never known anything to do that, but it doesn't sound impossible.

gilded orchid
#
for key,value in __builtins__.__dict__.items():
 __builtins__.__dict__.update({key:lambda:value})

print()("Hello World!")

why does this produce the error TypeError: <lambda>() takes 0 positional arguments but 5 were given?

#

(how were 5 positional args given?)

brazen geyser
#

@agile crane modules have their own global namespace inside which they can store things for the duration of their lifetime. once a module is imported it (as in the generated module object) is cached and so the same module object, along with its namespace, is reused upon next import. so this way you can get persistence across imports.

#
>>> import os
>>> import os as os2
>>> os.thing = 'hello'
>>> os2.thing
'hello'
>>> 
#

basically this but in different places

#

the cached modules are stored inside sys.modules

rugged sparrow
#

@gilded orchid print prob calls another builtin internally

#

you can use sys.modules to get modules with zero imports too

#

its useful for golfing/other challenges

#

!e ```py
print(help.call.globals['sys'])

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

<module 'sys' (built-in)>
rugged sparrow
#

!e ```py
print(help.call.globals['sys'].modules.keys())

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

dict_keys(['sys', 'builtins', '_frozen_importlib', '_imp', '_warnings', '_frozen_importlib_external', '_io', 'marshal', 'posix', '_thread', '_weakref', 'time', 'zipimport', '_codecs', 'codecs', 'encodings.aliases', 'encodings', 'encodings.utf_8', '_signal', '__main__', 'encodings.latin_1', '_abc', 'abc', 'io', '_stat', 'stat', 'genericpath', 'posixpath', 'os.path', '_collections_abc', 'os', '_sitebuiltins', 'pwd', 'site'])
river idol
#

Hello, can anyone tell me, is it possible to cache the constructor of a frozen dataclass?

Here's what I'm trying to achieve:

>>> from dataclasses import dataclass
>>> @dataclass(frozen=True)
... class C:
...     x: int
...     y: int
>>> a = C(1, 2)
>>> b = C(1, 2)
>>> a == b
True
>>> a is b
True

Here's what I get for that last line:

>>> a is b
False

I'd like to cache these objects for specific performance reasons. I know that it's possible to do this with a typing.NamedTuple, by doing something like:

MyNamedTuple.__new__ = functools.lru_cache(maxsize=None)(MyNamedTuple.__new__)
rugged sparrow
#

you could prob use __new__

#

!e ```py
from dataclasses import dataclass
import functools

@dataclass(frozen=True)
class C:
x: int
y: int

C.new = functools.lru_cache(maxsize=None)(C.new)

a = C(1,2)
b = C(1,2)
print(a is b)```

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 11, in <module>
003 | TypeError: object.__new__() takes exactly one argument (the type to instantiate)
river idol
#

Unfortunately, I think dataclasses use __init__

rugged sparrow
#

ok lru cache didnt work on __new__

river idol
#

it's an odd problem

#

Yeah, that's the error I got

rugged sparrow
#

one sec i have an idea

#

!e ```py
from dataclasses import dataclass
import functools

@dataclass(frozen=True)
class C:
x: int
y: int
cache = {}
def new(cls, *args, **kwargs):
if cache.get(args) is None:
cache[args] = super().new(cls, *args, **kwargs)
return cache[args]

a = C(1,2)
b = C(1,2)
print(a is b)```

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 14, in <module>
003 |   File "<string>", line 10, in __new__
004 | NameError: name 'cache' is not defined
rugged sparrow
#

oh woops

#

!e ```py
from dataclasses import dataclass
import functools

@dataclass(frozen=True)
class C:
x: int
y: int
cache = {}
def new(cls, *args, **kwargs):
if C.cache.get(args) is None:
C.cache[args] = super().new(cls, *args, **kwargs)
return C.cache[args]

a = C(1,2)
b = C(1,2)
print(a is b)```

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 14, in <module>
003 |   File "<string>", line 11, in __new__
004 | TypeError: object.__new__() takes exactly one argument (the type to instantiate)
rugged sparrow
#

maybe that doesnt work with dataclasses

#

or prob im doing it wrong

river idol
#

Ah, thanks for trying 😄

#

This might be a bad idea to begin with

rugged sparrow
#

it would be easier to do with a @classmethod

zealous widget
#

you can do it with a meta class or with a decorator

#

pick your poison

#

because i don't know all the details of the inner workings of dataclasses, it may be better with a decorator

rugged sparrow
#

it would be easier if dataclass was something you subclassed not a decorator

river idol
#

Ahh right @zealous widget , I could just decorate C with @lru_cache

#

Why did I not think of that

#

So the following would work?

#
@lru_cache(None)
@dataclass(frozen=True)
class C:
    x: int
    y: int

a = C(1, 2)
b = C(1, 2)
assert a == b
assert a is b
zealous widget
#

i'm not sure, but if it doesn't you can do this:


_cache = {}
def singleton(cls):

    def wrapper(*args):
        if args in _cache:
            return _cache[args]
        _cache[args] = cls(*args)
        return _cache[args]
    return wrapper


@singleton
class Test:
    def __init__(self, x, y):
        self.x = x
        self.y = y
#

oops i missed a return

#

ok, is that right

river idol
#

Ah ok.

#

I can run code here with !e, right?

zealous widget
#

i think so

river idol
#

!e

from dataclasses import dataclass
from functools import lru_cache

@lru_cache(None)
@dataclass(frozen=True)
class C:
    x: int
    y: int

a = C(1, 2)
b = C(1, 2)
assert a == b
assert a is b
night quarryBOT
#

@river idol :warning: Your eval job has completed with return code 0.

[No output]
river idol
#

Cool, seems to work

#

Lesson learned: start with the simpler method

zealous widget
#

if it wasn't a dataclass you could define a meta with your caching __call__

river idol
#

right, I'll look into that, although metaclasses scare me

zealous widget
#

but dataclasses can be fragile if you start poking them too much

#

so i think the decorator is probably the best

river idol
#

Thanks 😃

formal sandal
#

It's kinda trivial, but I still find it cool.

#

!e

Y = (lambda r: lambda x: r(r)(x))(lambda y: lambda f: lambda r: lambda x:(lambda u:[f(u),u][1])(r(lambda _r: lambda _x: y(y)(f)(r)(_x))(x)))
factorial = lambda r: lambda x: 1 if x<=0 else x*r(r)(x-1)
r = Y(print)(factorial)(6)
print("r =", r)
night quarryBOT
#

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

001 | 1
002 | 1
003 | 2
004 | 6
005 | 24
006 | 120
007 | 720
008 | r = 720
formal sandal
#

It's like the usual Y-combinator, but it executes something on each step.

rugged sparrow
#

you could def minimize that using iter and some mutable to carry state instead of recursion

formal sandal
#

Probably.

#

But that would be a bit further from lambda calculus.

rugged sparrow
#

!e ```py
_try=lambda t,*a,f=lambda a:a,e=Exception,**k,:(r:={}).pop('r',type('',(import('contextlib').ContextDecorator,),dict(enter=int,exit=lambda s,*a:isinstance(a[1],e)and[r.update(r=f(a))]))()(t)(*a,**k))

print(_try(lambda:1/0))

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x7f6b1b422900>)
rugged sparrow
#

!e ```py
def x():
print(1)

x(*[print(2)]*0)

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

001 | 2
002 | 1
night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 |   File "<string>", line 1, in <lambda>
004 | NameError: name 'a' is not defined
zinc light
#

is this where i ask how to rename certain statements or at least make an alias for them

nocturne saddle
#

@zinc light That depends. This channel is for everything esotic. If you want to ask a question about an actual pratical implementation, you're better off in one of the other channels.

zinc light
#

im pretty sure renaming statements to owo faces aren't practical

snow beacon
#

Then ask away.

zinc light
#

How do I rename/alias common statements like if/elif/for/in to something else like OwO/UwU/XwX/^W^

snow beacon
#

The easiest way is to define functions that perform those functions.

#

Or you could use a site coding.

zinc light
#

site coding?

snow beacon
#

You know how you can put # coding = ascii or however it's formatted at the top of a Python file?

#

Well you can define your own coding in site modules.

#

It's meant to be a data format, but there's nothing stopping you parsing the files that are in your format as python code and doing textual replacement before execution.

zinc light
snow beacon
#

Another option is to use whatever they did for Hy to get it to do alternative syntax, but that requires your Python code has no syntax errors.

#

That strategy uses an import which I believe halts execution of the rest of the file.

#

It then parses it. The problem is that a syntax error anywhere in your file means it won't get to the necessary import.

#

There are a lot of things that aren't syntax errors fortunately.

zinc light
#

thankies i'll try these

formal sandal
#

You can dynamically rename builtins to different faces according to some algorithm.

#

!e

import random
random.shuffle(bins := [*__builtins__.__dict__.values()])
eyes = "ou^0OU"
mouths = "Wwv_"
new_names = {}
for eye in eyes:
    for mouth in mouths:
        new_names[f"{eye}{mouth}{eye}"] = bins.pop()
print(new_names)
night quarryBOT
#

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

{'oWo': <built-in function ascii>, 'owo': <class 'BlockingIOError'>, 'ovo': <class 'NameError'>, 'o_o': <built-in function max>, 'uWu': <built-in function globals>, 'uwu': <class 'ResourceWarning'>, 'uvu': <built-in function eval>, 'u_u': <class 'TabError'>, '^W^': True, '^w^': <class 'AttributeError'>, '^v^': <built-in function ord>, '^_^': <class 'frozenset'>, '0W0': <built-in function chr>, '0w0': <class 'InterruptedError'>, '0v0': <class 'bool'>, '0_0': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", 'OWO': <class 'OSError'>, 'OwO': <built-in function open>, 'OvO': <class 'TypeError'>, 'O_O': <class 'KeyError'>, 'UWU': <class 'NotImplementedError'>, 'UwU': <class 'dict'>, 'UvU': <class 'list'>, 'U_U': <class 'ProcessLookupError'>}
zinc light
#

this is amazing

formal sandal
#

!e

factorial = lambda x:{1<2:lambda:1,x>0:lambda:x*factorial(x-1)}[1<2]()
print(factorial(6))
night quarryBOT
#

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

720
formal sandal
#

Based on @rugged sparrow's _try:

#

!e

P=(lambda j:lambda n:lambda f:(lambda u:({1:j,len({*map(type,((),u))})+2<__import__('math').pi and len({*map(type,(type,getattr(u,"__getitem__",lambda i:...)(0)))})+1<__import__('math').e:n}[1])(u))((lambda t,*a,f=lambda a:a,e=Exception,**k,:(r:={}).pop('r',type('',(__import__('contextlib').ContextDecorator,),dict(__enter__=int,__exit__=lambda s,*a:isinstance(a[1],e)and[r.update(r=f(a))]))()(t)(*a,**k)))(f)))

P(lambda x:print("result", x))(lambda x:print("error", x))(lambda: 1)

P(lambda x:print("result", x))(lambda x:print("error", x))(lambda: 1/0)
night quarryBOT
#

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

001 | result 1
002 | error (<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x7f26315c5fc0>)
formal sandal
#
P=(
  lambda j: lambda n: lambda f:
  (
    lambda u:
      (
        {
          1
            :j,
          len({*map(type,((),u))})+2<__import__('math').pi
          and len({*map(type,(type,getattr(u,"__getitem__",lambda i:...)(0)))})+1<__import__('math').e
            :n
        }[1])(u))(_try(f)))
#

Leaked pattern matching proposal PEP

maiden shard
#

my eyes oh my god

#

i know what lambda's do but i understand 0 of this xD

formal sandal
#

Well, that's on purpose (:

#
def P(j, n, f):
    u = _try(f)
    if type(())) == type(u) and type(type)==type(u[0]):
        return n(u)
    else:
        return j(u)
#

Well, I didn't have to do getattr(u,"__getitem__",lambda i:...)(0)

#

that's legacy code

bitter iris
#

haha @formal sandal

rugged sparrow
#
>>> _try(lambda a,b:a/b,1,b=0,f=lambda a:print(a[0]))
<class 'ZeroDivisionError'>
>>> _try(lambda a,b:a/b,1,b=0,f=lambda a:print(a[0]),e=TypeError)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 1, in <lambda>
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/contextlib.py", line 75, in inner
    return func(*args, **kwds)
  File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero
>>> _try(lambda a,b:a/b,1,b=0,f=lambda a:print(a[0]),e=(TypeError,ZeroDivisionError))
<class 'ZeroDivisionError'>
>>> ``` @formal sandal `_try` can do a lot more than just emulate ```py
try:
  ...
except:
  pass
#

t is the func that is called, all other positional args are passed into t, f is called with the exc (cls, inst, tb) tuple if an exception is raised, and e is either a single Exception subclass or a tuple of Exception subclasses. all other keyword args are passed into t.

#

basically _try is like this ```py
try:
return t(*a, **k)
except e as exc:
return f((type(exc), exc, exc.traceback))

stark fable
#
>>> factorial = lambda b:(lambda a:a(a))(lambda a:lambda b:(lambda c:lambda d:a(a)(b-1)(c)(c(d)))if b else lambda a:lambda a:a)(b)(lambda b: lambda a:a(b(lambda a:lambda a:a)(b(lambda a:lambda b:a)(lambda a:lambda b:lambda c:a(b)(b(c))))(lambda a:lambda a:a))(lambda a:lambda c:b(lambda a:lambda a:a)(a)(a(c))))(lambda a:a(lambda a:a)(lambda a:a))(lambda a:lambda b:a)(lambda a:a+1)(0)
>>> factorial(5)
120```
#

i'm not entirely sure how this works but it seems like it does

formal sandal
#
factorial = λb.
                (λa.a(a))
                (λa.λb.  # a
                    (λc.λd.
                        a(a)(b-1)(c)(c(d)))
                        if b
                        else F)
                (b)
                (λb.λa.
                    a
                    (b
                     (F)
                     (b
                       (T)
                       (λa.λb.λc.
                         a(b)(b(c))
                       )
                     )
                     (F)
                    )
                    (λa.λc.
                        b(F)(a)(a(c))
                    )
                )
                (λa.a(I)(I))
                (T)
                (Succ)
                (0)
>>> factorial(5)
zealous otter
#

I don't know if this is esoteric enough for this place but does someone know why I don't need a space between a digit and if but I need one between a digit and or?

>>> 0if 1 else 1
0```
```Python
>>> 0or 1
  File "<stdin>", line 1
    0or 1
     ^
SyntaxError: invalid token```
formal sandal
#

Because else1 is a valid identifier, but 0if is not.

#

you can do

zealous otter
#

Yeah I copied the wrong thing wait a minute

formal sandal
#

!e

print(0if 1else 1)
night quarryBOT
#

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

0
zealous otter
#

But why 0or 1 doesn't work?

formal sandal
#

!e ```py
print(0or 1)

night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 | SyntaxError: invalid octal literal
formal sandal
#

oh

#

0o is a beginning of an octal number

zealous otter
#

ah

#

thanks

formal sandal
#

!e

print(0o731)
night quarryBOT
#

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

473
zealous otter
#

But I get invalid token though

#

With 3.8

#

3.6 apparently

formal sandal
#

yes, I get 'invalid token' with 3.6

zealous otter
#

And invalid octal with 3.8

formal sandal
#

Error messages have been improved a bit

#

!e

1 or {1}()
night quarryBOT
#

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

<string>:1: SyntaxWarning: 'set' object is not callable; perhaps you missed a comma?
zealous otter
#

Woah

formal sandal
#

!e ```py
1 or ()()

night quarryBOT
#

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

<string>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
zealous otter
#

Never had a suggestion like that

#

Where would you put the comma here?

#

(),()?

snow beacon
#

There isn't anywhere else for it to go.

#

It makes more sense if you put brackets around the ()().

formal sandal
#

!e ```py

Makes more sense here:

my_list = [
(1, 2),
(3, 4),
(5, 6)
(7, 8),
(9, 0)
]```

night quarryBOT
#

@formal sandal :x: Your eval job has completed with return code 1.

001 | <string>:5: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
002 | Traceback (most recent call last):
003 |   File "<string>", line 5, in <module>
004 | TypeError: 'tuple' object is not callable
formal sandal
#

It might be hard to notice, especially if there's some stuff around it

#

that's one of the reasons why I put a trailing comma.

formal sandal
#

whoa

In [8]: class MaybeInt(SumType):
   ...:     Just.of(int)
   ...:     Nothing.of(())
   ...:

In [9]: x = MaybeInt.Just(42)

In [10]: x
Out[10]: 42

In [11]: type(x)
Out[11]: embellished('Just', <class 'int'>)

In [12]: y = MaybeInt.Nothing(())

In [13]: y
Out[13]: ()

In [14]: type(y)
Out[14]: embellished('Nothing', ())

In [15]:
#

I'm surprised that it worked!

#

The only thing left is subclass checking

#

@zealous widget infected me

thin trout
#

Manifestly

formal sandal
#

It's actually lots of fun

#

I had to make a metametaclass for proper instance checking.

thin trout
#

I had to make a metametaclass for proper instance checking.
@formal sandal metametaclass, gosh you need to take a de-salting cure rn

formal sandal
#

Is there any way to pack the code into the eval command?

#

It's more than 2000 characters long even when minified

thin trout
#

I don't think so

#

You can't even pull it from the internet

formal sandal
#

Yep

thin trout
#

Maybe we should add a support of gists and pastes

#

You should open an issue lemon_pika

formal sandal
#

n-nope

#

!e

exec(__import__("gzip").decompress(__import__("base64").b64decode("H4sIAI7Twl4C/8VVwY6bMBA9h69gc8HOWii9Qr2STZKqqlpVam9RZLHE7KJNABmibhrx7x2bQEzI7qGq1ByIGXvevHmeGQSjnhDxthalKspKCM9JdnFVuWK5f5S7XVY9yy2PKxmIpMirWh2SulAij/cymDtbmbrycg5pMwFjlmd1VuQ4cCaMXt6dSYvNUX0spd6daAQhlCyVEIjjQMn6oHI3ndqwJ+6Pot+phrgnBn942uFG6Jo12cs6NpuUm3gjHKof7xHRunwMblFo3CA4U3gAjobI2S0y0uzjF2l73dJnQb2ZF3JDI7wllhAG5hGyEToboHelXgYB4jyRybNMXmA7Ip0FB4x26/BMLas6C2LkWi8c51uXjVOllN/i01KxRB6T/Q88h3fJ+ruErSwd4vZKDnITaJCkOXAGzeUv2F6SVxxE1K5RThjuqGtUo4wvDCsh7hcEokWYnBqMXrEzkbsRlUO5+xsun8gsaq06u53MUYTvqP7XmcdZJd2fQGWpFBSg9zlPCqVkUruxejrsZV67SXGAZ1oo11BwLU09bHCX40xX9HaSBoIsTaKdHCuERp2QTqFh/NOimcJhtMIQHoH7kqwwznJX5sBNxbVEv7PSKAe/vrs6ac6j6sdhrzP8Do0qVX0ELbp6y2pdAKSMFSQqtllSE00Vys23bNRah8zvpwKsL+1IvxW5bJGLFDDtLuZW2w6deBjRFtGvyl1WI8/38PrDJhwQWEcbOlKodSMcO2/VczqFudQeO48iK3TzMB3Ks4BASEfDY4FaUaoD6Iew329gW43OaZ9VULZPekqSF3k0pccorBxTgGw93/gZQBksaJKr2wEvbkDvQYp7qCS+FmyzZhsahf3wnEB/wCenrd4v8tgWL8PDjL7CgOlnYUuuBJFAV0NuFpHZbKFHi60Ax+GSMh2TnpouInPeGFH8348ouxDmGxhYff+8c9Fwtd2pxjUv1ie7ubppdJnHllI4mP8Btv3vV+0HAAA=")).decode("utf-8"))

class MaybeInt(SumType):
    Just.of(int)
    Nothing.of(())

j = MaybeInt.Just(42)
print(j)
print(type(j))
print(isinstance(j, MaybeInt))
print(isinstance(j, MaybeInt.Just))
night quarryBOT
#

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

001 | 42
002 | embellished('MaybeInt.Just', <class 'int'>)
003 | True
004 | True
formal sandal
#

pretty straight-forward solution

thin trout
#

Haha

formal sandal
#

pyminify->decrease tab size->gzip->base64

#

Another trick I used in codegolf: I encoded the same message with unicode characters that have a very high numeric value.

#

So technically that's a one-liner!

thin trout
#

:speechless:

edgy kelp
#

shame

SyntaxError: assignment expression cannot be used in a comprehension iterable expression
formal sandal
#

How did you get that?

edgy kelp
#

[_ for _ in(r:=range)(5000)] not really a char advantage either, but shame

rugged sparrow
#

!e ```
[_ for _ in [r:=range]0]

night quarryBOT
#

@rugged sparrow :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 | SyntaxError: assignment expression cannot be used in a comprehension iterable expression
rugged sparrow
#

Damn thought that might work around

formal sandal
#

Now for the real issue: is there any conceivable way to make my type system work with mypy?

#

Does mypy have no intersection types?

formal sandal
#

Well, I guess, I've just wasted lots of time.

dire linden
#

This might be the right channel for me... I'm trying to use an instantiated object (f) that has a __call__ method to act like a method on another class/object (p). Has anyone done this before? The problem is that when __call__ is called, the only arguments it gets are self (referencing f) and nothing that passes along p (which you would get if it was a normal method that had a self parameter)

formal sandal
#

Could you show an example?

dire linden
#

yeah! one sec

snow beacon
#

When you instantiate an object, all of the functions in the class definition become bound methods.

#

Actually, that might be when you make the class.

dire linden
#

is there any way to... uh, add a new bound method during runtime?

formal sandal
#

also... why use ; ?

#

Well, that problem is trivially solved with a metaclass!

snow beacon
#

You might want to give Parent a __new__ or __init__ that passes Func a reference to the Parent object.

#

Or metaclasses.

dire linden
#

survivor from ALGOL languages @typing 🤣

snow beacon
#

(It doesn't feel trivial though.)

formal sandal
#

Well, not necessarily metaclasses

snow beacon
#

By the way, because class definitions are just statements, everything is already done at runtime.

dire linden
#

so if I do something like define a new function and then add it to the Parent class it works

snow beacon
#

It probably wouldn't be bound, but you can work around that by passing it a reference to the Parent object.

dire linden
snow beacon
#

Oh, apparently it is bound.

dire linden
#

honestly this is why I'm confused as to why p.f behaves differently

#

I would've assumed that p.f() would also pass p as an argument

snow beacon
#

Oh, function vs object?

dire linden
#

yeah, technically f is an instantiated object itself, but it has a __call__ method... I just assumed it would be treated like a bound method itself when it was called

#

seems like Python doesn't like the nested selfs

#

I can probably get around not doing it this way, but it would have been super nice

formal sandal
#

Python supports multiple inheritance, co you could just create a mixin.

dire linden
#

the truth is I'm doing some monkey-patching so that's not really an option

snow beacon
#

You could do Parent.f = lambda self, *args, **kwargs: Func()(self, *args, **kwargs) or similar.

#

That way it would treat it like a function.

dire linden
#

oo

formal sandal
#

Maybe make a helper function like pass_self

dire linden
#

can you elaborate, @typing ?

formal sandal
#

And actually, there's no need to create a Func class.

#

Just create a function factory.

dire linden
#

also @snow beacon -- that MIGHT work... investigating. It works in my demo / IDLE env.

snow beacon
#
def make_function(callable_object):
    def function_version(self, *args, **kwargs):
        return callable_object(self, *args, **kwargs)
    return function_version
formal sandal
#

Well, then you can just use callable_object, can't you?

snow beacon
#

callable_object isn't a function.

formal sandal
#

oh

snow beacon
#

It won't bind properly unless you make a function out of it.

#

I suppose this is a decorator, but it's not very useful as one.

#

If you want to be more Pythonic you could use @wraps as well.

dire linden
#

also, sorry -- I am experimenting right now... might take me a couple minutes

#

trying out the lambda option first

formal sandal
#

well

#

if you want to be pythonic, this might not be the best channel :)

#

By the way, you can assign arbitrary attributes to a function.

#

!e

def f(): pass
f.hello = "world"
print(f.hello)
night quarryBOT
#

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

world
formal sandal
#

So you might not need to build a whole class just for that call method.

dire linden
#

@typing hahaha, I try to incorporate pythonic stuff as I can, but let's be honest, I use semi-colons and sometimes camelCase.

#

SO UPDATE, the lambda function worked. It seems that the biggest deal is just that it needs to be a function and not an object.

#

the lambda function instantiating an object as it's called, and then calling the __call__ method works great. And in this case the only reason for the Object is honestly just passing some additional information

formal sandal
#

<nitpick> Well, a function and an object, since it cannot be a non-object</nitpick>

dire linden
#

ahaha

#

also, that's a cool bot.

formal sandal
#

!e

def thisify(**attrs):
    def decorator(fn):
        f = lambda *args, **kwargs: fn(f, *args, **kwargs)
        for k, v in attrs.items():
            setattr(f, k, v)
        return f
    return decorator

@thisify(greeting="Hello")
def greet(this, name):
    print(f"{this.greeting}, {name}!")

greet("alice")
greet.greeting = "Guten Tag"
greet("bob")
night quarryBOT
#

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

001 | Hello, alice!
002 | Guten Tag, bob!
formal sandal
#

So if you don't have any complex logic, you can do this. But it still fits the channel, unfortunately.

rugged sparrow
#

if you wanted it to further fit this channel, hook __build_class__ and transform the class body into a function def

rugged sparrow
#

!e ```py
import functools
import sys
import dis

def hook(func, new_func=None):
def deco(nfunc):
@functools.wraps(func)
def hfunc(*args, **kwargs):
return nfunc(func, *args, **kwargs)
hfunc._hooked = func
if globals().get(func.name) is func:
globals().pop(func.name)
globals()[func.name] = hfunc
setattr(sys.modules[func.module], func.name, hfunc)
if new_func:
return deco(new_func)
return deco

def unhook(func):
if not hasattr(func, '_hooked'):
raise TypeError('func must be a hooked function')
orig = func._hooked
setattr(sys.modules[func.module], func.name, orig)

@hook(build_class)
def build_class(orig, *args, **kwargs):
func_body = args[0]
if kwargs.pop('function', None):
ret_op = dis.opmap['RETURN_VALUE'].to_bytes(1, byteorder='little')
patched_code = func_body.code
for inst in dis.get_instructions(func_body):
if inst.argval == 'ret' and inst.opname == 'STORE_NAME':
new_co_code = bytearray(patched_code.co_code)
new_co_code[inst.offset:inst.offset+1] = ret_op+b'\x00'
patched_code = patched_code.replace(co_code=bytes(new_co_code))
func_body.code = patched_code
return func_body
return orig(func_body, *args[1:], **kwargs)

class a(function=True):
ret = 1

print(a())

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

1
rugged sparrow
#

i still need to mod it to allow for the func to take in variables

dire linden
#

@formal sandal -- wait, on the 3rd line of thisify -- how does f get assigned to be a lambda function that calls the decorated function with itself as an argument?!

#

@rugged sparrow that's pretty awesome

rugged sparrow
#

thanks

#

!e ```py
import functools
import sys
import dis

def hook(func, new_func=None):
def deco(nfunc):
@functools.wraps(func)
def hfunc(*args, **kwargs):
return nfunc(func, *args, **kwargs)
hfunc._hooked = func
if globals().get(func.name) is func: # allows for hooking of functions imported into the global scope from module import func
globals()[func.name] = hfunc
setattr(sys.modules[func.module], func.name, hfunc)
if new_func:
return deco(new_func)
return deco

def unhook(func):
if not hasattr(func, '_hooked'):
raise TypeError('func must be a hooked function')
orig = func._hooked
setattr(sys.modules[func.module], func.name, orig)

@hook(build_class)
def build_class(orig, *args, **kwargs):
func_body = args[0]
if kwargs.pop('function', None):
ret_op = dis.opmap['RETURN_VALUE'].to_bytes(1, byteorder='little')
patched_code = func_body.code
for inst in dis.get_instructions(func_body):
if inst.opname == 'STORE_NAME' and inst.argval == 'ret':
new_co_code = bytearray(patched_code.co_code)
new_co_code[inst.offset:inst.offset+2] = ret_op+b'\x00'
patched_code = patched_code.replace(co_code=bytes(new_co_code))
func_body.code = patched_code
@functools.wraps(func_body)
def wrapped_body(**nkwargs):
for key in kwargs.keys():
if key not in nkwargs.keys():
nkwargs[key] = kwargs[key]
return eval(func_body.code, {}, nkwargs)
return wrapped_body
return orig(func_body, *args[1:], **kwargs)

class add(function=True):
ret = a + b

print(add(a=1, b=2))

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

3
rugged sparrow
#

keyword args work

#

tried manually patching the func code to implement args properly but kept getting segfaults

dire linden
#

@rugged sparrow is there a way to force writing to a read-only attribute?

rugged sparrow
#

depends on the context

#

what attribute are you trying to change?

dire linden
#

let's say it's a custom class with some attribute 'xyz' -- but after the class is instantiated I get errors saying 'xyz' is read only

#

(when I try doing setattr)

rugged sparrow
#

what class is it?

#

cause if its implemented in c you might need ctypes

dire linden
#

ah

#

it is

#

but I'm able to create the custom attribute

rugged sparrow
#

that makes it a bit more tricky to modify

dire linden
#

the problem is I can only set it once

#

I can set it at the class level

rugged sparrow
#

what class is this

dire linden
#

but not at the instance level

rugged sparrow
#

why are you trying to mod a socket instance

dire linden
#

I mean, this is esoteric python :p

rugged sparrow
#

im not saying its impossible, but it would prob be easier to restructure the code

dire linden
#

I feel like it's probably something stupider/simpler

snow beacon
#

It may depend on your use case: if you want to give thee socket to another function, then it might be sufficient to make a wrapper that behaves like a Socket barring one particular attribute. Otherwise, if you want the Socket itself to use a different value, then that's a C job.

dire linden
#

I've tried setting __slots__ but that doesn't work either :/

#

I'm wondering if I need to use dis

rugged sparrow
#

@dire linden what is your goal

formal sandal
#

You can use hax instead (:

rugged sparrow
#

@formal sandal do you know if its possible to do inline @hax in a function?
like ```py
@hax
def f():
x = 1
LOAD_VALUE('x')
RETURN_VALUE()

formal sandal
rugged sparrow
#

oh lol

#

i thought @hax required the entire body to be Instructions

#
from hook import hook

@hook(__build_class__)
def new_build_class(orig, *args, **kwargs):
    func_body, *args = args
    if '__func__' in func_body.__code__.co_consts:
        ret_op = dis.opmap['RETURN_VALUE'].to_bytes(1, byteorder='little')
        patched_code = func_body.__code__
        for inst in dis.get_instructions(func_body):
            if inst.opname == 'STORE_NAME' and inst.argval == 'ret':
                new_co_code = bytearray(patched_code.co_code)
                new_co_code[inst.offset:inst.offset+2] = ret_op+b'\x00'
                patched_code = patched_code.replace(co_code=bytes(new_co_code))
        func_body.__code__ = patched_code
        @functools.wraps(func_body)
        def wrapped_body(**nkwargs):
            for key, item in kwargs.items():
                if key not in nkwargs.keys():
                    nkwargs[key] = item
            return eval(func_body.__code__, {}, nkwargs)
        return wrapped_body
    return orig(func_body, *args, **kwargs)

if __name__ == '__main__':
    class add(a=1, b=2):
        '__func__'
        ret = a + b

    print(add(a=5, b=5))``` @formal sandal did you see my final build_class hook?
#
def hook(func, new_func=None):
    def deco(nfunc):
        @functools.wraps(func)
        def hfunc(*args, **kwargs):
            return nfunc(func, *args, **kwargs)
        hfunc._hooked = True
        if globals().get(func.__name__) is func: # allows for hooking of functions imported into the global scope `from module import func`
            globals()[func.__name__] = hfunc
        setattr(sys.modules[func.__module__], func.__name__, hfunc)
        return hfunc
    if new_func is None:
        return deco
    return deco(new_func)```
formal sandal
#

that's scary

#

I'll look into it tomorrow

rugged sparrow
#

hooking __build_class__ would allow for a custom metaclass that mutated the class's body

#

it would be even cooler if you managed to hook the class compilation

#

cause then you could literally make a metaclass that lets you write classes in a different language

snow beacon
#

The interior would still need to follow Python syntax, if not its semantics.

rugged sparrow
#

if you could hook the actual parser tho

snow beacon
#

How would you do that at runtime?

rugged sparrow
#

it would be very tricky

snow beacon
#

Given that code doesn't exactly run when it has a syntax error in the file...

#

There's the fuckitpy solution to import the broken file from elsewhere, presumably using an adapted __import__.

rugged sparrow
#

import hooks let you mutate a file before it is parsed right?

#

ive never used them before

snow beacon
#

I'm pretty sure fuckitpy ignores syntax errors in imported modules.

rugged sparrow
#

it just finds the lines that have errors and wraps them in try/except until it runs

snow beacon
#

So it seems.

#

Oh, it doesn't directly change the import hook, you instead call it on the filename you want to import.

rugged sparrow
#

yea

dire linden
#

@typing and @rugged sparrow -- hax is pretty insane, that's super cool.

#

I'm trying to see if I can inject new instructions now into existing code

#

(e.g., instructions I made using dis)

rugged sparrow
#

@dire linden you can but it can be tricky

#

if you're adding instructions, you need to be sure to fix all the jump location indexs

#

my build_class hook replaces instructions, which is easier

dire linden
#

ah, this is cool but it's not going to work for me from what I can tell

#

I tried overwriting the __code__ for socket.socket.__init__ but it still threw an AttributeError

#

I just don't get why I can't seem to set a new attribute in __init__ ... even if I add it to __slots__ it doesn't work

rugged sparrow
#

socket.socket is written in c i believe

#

youre gonna need to use ctypes to access and mutate the struct

brisk zenith
#

things written in C are very resistant to change, so you're not gonna have a great time

#

and when you do finally get it to work, it'll probably be unstable as all hell

#

it's probably possible to do what you want, but just be prepared for a lot of difficulty haha :D

dire linden
#

@rugged sparrow and @formal sandal -- tried overwriting the __code__ for the __init__ call, but it still fails with the same errors. Basically, I can't seem to add any new attributes to the instance when it is being instantiated?!?

#

so I don't think it's an issue with using dis or hax or generating bytecode

#

this is after adding the new attribute to __slots__ too

rugged sparrow
#

It's probably written in C so you will need to do more work to mod it

dire linden
#

but I'm modding the python subclass?

rugged sparrow
#

Then you need to mod the class before making an instance of it

dire linden
#

yeah, I've modded __slots__ and changed __init__

#

honestly I don't understand what I'm missing, feels like there's some voodoo

#

wait, you mean mod the base class?

#

I think I found a solution

#

if I subclass the original class 🤷🏻‍♂️

#

rather, the non-C++ original class

rugged sparrow
#
from ctypes import windll, c_char_p, c_char
import subprocess as sp
import time

EM_REPLACESEL = 194

def log(log_str, make_new=False):
    find = lambda title: windll.user32.FindWindowA(None, c_char_p(title.encode()))
    hwd = find("Untitled - Notepad") or find("*Untitled - Notepad")
    if hwd == 0:
        if make_new:
            sp.Popen(['notepad.exe'])
            time.sleep(0.05)
            hwd = find("Untitled - Notepad")
        else:
            return
    edit = windll.user32.FindWindowExA(hwd, None, c_char_p(b"EDIT"), None)
    b_log_str = log_str.encode() + b'\n\0'
    log_buf = (c_char*len(b_log_str))(*b_log_str)
    windll.user32.SendMessageA(edit, EM_REPLACESEL, True, log_buf)``` best log method
#

if the func is called and a new notepad window is opened it writes the log message there

snow beacon
#

I wonder how hard it would be to make this cross-platform.

rugged sparrow
#

it would prob need to be entirely different

#

one sec

#

could use applescript

rugged sparrow
#

but if you wanted to make a crossplatform debug window it would prob be easier to just make a simple window and write text there

snow beacon
#

If you aren't being esoteric, then you may as well just print it to stderr or something.

rugged sparrow
#

very true

brisk zenith
#

man i've had to use windll before

#

not the best experience

#

still haven't figured out a filehandle-related bug

#

utter shambles

#

</complaints>

rugged sparrow
#

some of the func names are mangled af but i havent found any real issues yet

#

what was your filehandle bug?

brisk zenith
#

okay so i'm making a module which opens a "file" (it's actually a device file but same thing)

#

using CreateFileW or whatever

#

and if i use the file handle in the same python script, it works fine.

#

however, if i call the function which does CreateFileW from a different script, the file handle suddenly stops working

rugged sparrow
#

what are you sending it for lpSecurityAttributes?

brisk zenith
#

oh shit is that it

#

i can't remember

#

might be NULL

rugged sparrow
#

it affects how child processes can use the file

brisk zenith
#

fuck

rugged sparrow
#

default is not at all

brisk zenith
#

glad that was clearly labeled on the documentation

rugged sparrow
#

uhhhh

brisk zenith
#

ohh i see

#

hmm okay

rugged sparrow
#

idk if that is your issue

#

but if python is trying to pass around the thread for some reason it could prob break your handle

brisk zenith
#

yeah that's what i was thinking

#

idk it's weird, i'll see if messing with that argument changes anything tomorrow

#

thanks for the idea

rugged sparrow
#

np

bitter iris
#

example output:

        └──Rule
           └──Rhs
              └──Alt
                 ├──NamedItem
                 │  └──StringLeaf("'a'")
                 └──NamedItem
                    └──Opt
                       └──Rhs
                          └──Alt
                             ├──NamedItem
                             │  └──StringLeaf("'b'")
zealous widget
#

nice

#

why'd they have this hidden away somewhere

bitter iris
#

it is an internal tool only for testing

zealous widget
#

they could've saved me a half hour or so

#

rude

last locust
#

How does the hash function work in Python? I was messing around with stuff and realised that the hash of a given value is only constant in the current execution (see below evals)

#

!e py for _ in range(5): print(hash("Hello World"))

night quarryBOT
#

@last locust :white_check_mark: Your eval job has completed with return code 0.

001 | 7196301540258645269
002 | 7196301540258645269
003 | 7196301540258645269
004 | 7196301540258645269
005 | 7196301540258645269
last locust
#

!e py for _ in range(5): print(hash("Hello World"))

night quarryBOT
#

@last locust :white_check_mark: Your eval job has completed with return code 0.

001 | 503698058124208995
002 | 503698058124208995
003 | 503698058124208995
004 | 503698058124208995
005 | 503698058124208995
last locust
#

Exact same code, but two different outputs for the two executions?

formal sandal
#

Well, yes, hash doesn't have to be the same between executions.

last locust
#

So the hashes are like randomly generated upon execution?

#

Rather than being a set value

#

Certain things it's always the same (e.g. for ints the hash is always just the number)

formal sandal
last locust
#

Source?

last locust
#

Thank you ;3

#

Another thing, how is 'NoneType' defined? If you do type(None) it gives <class 'NoneType'> but doing say print(NoneType) to access the class raises NameError: name 'NoneType' is not defined

#

!e py print(type(None)) print(NoneType)

night quarryBOT
#

@last locust :x: Your eval job has completed with return code 1.

001 | <class 'NoneType'>
002 | Traceback (most recent call last):
003 |   File "<string>", line 2, in <module>
004 | NameError: name 'NoneType' is not defined
formal sandal
#

Well, it's not in the __builtin__ module.

last locust
#

^

#

But why not?

formal sandal
#

!e

NoneType = type(None)
print(NoneType())
night quarryBOT
#

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

None
formal sandal
#

I don't now. Maybe because Python devs wanted to make the global scope smaller.

last locust
#

So basically the NoneType is just "hidden"?

#

As in you have to do type(None) to access the class

formal sandal
#

Yes, you can't even get it from types.

#

I don't know why you would ever need NoneType.

last locust
#

True, was just kinda curious

formal sandal
#

The only use case I can think of is when you have to pass some kind of list of classes for some pattern matching or something.

#

But in that rare case you'll have to type type(None).

last locust
#

Yea

formal sandal
#

I mean, they removed reduce from the global scope...

last locust
#

I guess it's kinda as you said, people don't really need to access NoneType so the devs didn't include it in the global scope

formal sandal
#

But for some reason compile and memoryview is in the global scope.

zealous widget
#

you can't get function types without importing them either

formal sandal
#

True.

#

But maybe typing.Callable makes more sense in most cases because of ducky

zealous widget
#

you can just use callable

#
In [3]: callable(lambda x:2)                                                                                                        
Out[3]: True
formal sandal
#

Except for the case I described earlier when you need to pass a class.

zealous widget
#

there's also types.FunctionType

#

it's a bit less general

#

shucks:

In [11]: class NoneMeta(type(None)): 
    ...:     pass 
    ...:                                                                                                                            
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-11-8ae85889f726> in <module>
----> 1 class NoneMeta(type(None)):
      2     pass
      3 

TypeError: type 'NoneType' is not an acceptable base type
#

python never lets me have any fun

formal sandal
#

You can't set it with .__bases__ = ... either

formal sandal
#

Now I'm kinda interested in an AST rewriter library.

In [10]: def fn():
...     logger.warn("Hello, world!", hello="world")
In [11]: fn2 = fn.replace_expr( 
    ...:     Call.where( 
    ...:         lambda call: matches( 
    ...:             call.func, 
    ...:             Attribute.where( 
    ...:                 lambda attr: 
    ...:                     attr.value == Name("logger") 
    ...:                     and attr.name in ["warn", "info", "debug", "error", "critical"] 
    ...:             ) 
    ...:        ), 
    ...:    lambda call: 
    ...:        call.with_keywords(Keyword.from_dict( 
    ...:            { "extra": call.keywords.as_dict() } 
    ...:        )) 
    ...:    ) 
    ...: )
In [12]: fn2.source()
def fn():
    logger.warn("Hello, world!", extra={"hello": "world"})
#

With simpler logic, it could be even shorter:

def fn():
    logger.warn("Hello, world!")
fn.replace_name("logger", "shmogger")
#

Because right now AST rewriting is a bit painful.

gloomy reef
#

Heyo!

#

I've just got a little thing that i'm not too sure how to get it to work

#
class Game:
  def __init__(self):
    self.x = gameobjecthere

  @x.event
  def anotherfunc():
    ...
#

The thing is, the example doesn't offer it in a class

#

the error here is that the x in @x.event isn't defined, and doing @self.x.event just says that self is not defined

#
self.x = gameobjecthere

@x.event
def anotherfunc():
  ...

is what i'm working off

#

(I didn't word this question well above)
With my code I want to have a function inside a class that is an event that is linked to a variable that I define in the __init__ of that class, which becomes a problem since it isn't defined

#

thoughts?

#

more debugging later, seems like i am able to define it outside the __init__() function and it works, i just won't be able to pass any arguments from the __init__() into it

earnest wing
#

Rewriting AST to make the following work could be fun. (And non-performant.)

@typed
def foo(a: int, b: list[str]) -> int:
  x: int = a + len(b)
  y = b[0] # y: str implicitly
  z: int = None # mismatched types, raise
  # doesn't return int, raise

foo(0, []) # valid
foo(0, "huh") # mismatched types, raise
thin trout
#

Well, mypy can do that

formal sandal
#

Well, argument signatures are trivial to verify.

rugged sparrow
#

@polar plover bet

sick hound
#

I don't understand any of this lol

rugged sparrow
#

abs = lambda x:(x,-x)[x<0]

sick hound
#

I do understand the def and the rest but not the ":"

rugged sparrow
#

map = lambda f,*i:(f(*q) for q in zip(*i))

zealous widget
#

whatever is after : is the return value

polar plover
#

what next? would sorted be possible, we would need to make a sorting algo with no function calls xD

rugged sparrow
#

prob could

sick hound
#

like x: int = a + len(b)

#

that i didn't get

zealous widget
#

need to get for or while as an expression not a statement

polar plover
#

that is essay, I have made many while loops as expressions

rugged sparrow
#

for in an expresion is easy

sick hound
#

I prefer the while loop, i don't tend to use for loop in python

rugged sparrow
#

while is a bit trickier without func calls

formal sandal
#

well, map still uses a function call

#

even two of them

rugged sparrow
#

well map has to contain one

#

zip can be recreated

polar plover
#

!e py (x:=0,y:=[0], [( y.append(0), x:=x+1, print(x) # just to show that is works. ) for _ in y if x <= 10])

night quarryBOT
#

@polar plover :white_check_mark: Your eval job has completed with return code 0.

001 | 1
002 | 2
003 | 3
004 | 4
005 | 5
006 | 6
007 | 7
008 | 8
009 | 9
010 | 10
011 | 11
polar plover
#

there a while ^

#

wait, no

#

I used append

formal sandal
#

y+=0,

rugged sparrow
#

wait it lets you change the iterable size mid loop?

formal sandal
#

I don't know if that would work

#

yep

rugged sparrow
#

thought that didnt work for some reason

polar plover
#

hm, is there a way to modify a list with a expression

#

y:=y+[0] would make a new list, so it would not work

formal sandal
#

hm

#

true

polar plover
#

y+=[0] is not a expression 😭

formal sandal
#

oh, i'm dumb

polar plover
#

idk if we can change a list (changing the list itself, not the varible to a new list)

formal sandal
#
list_ := (..., ..., ..., list_+[0])[-1]
#

something like that

zealous widget
#
In [81]: [x for x in [0] for y in [1, 2, 3, 4, 5,] for x in [x + y]]                                                                
Out[81]: [1, 3, 6, 10, 15]

you can accumulate

sick hound
#
array = [] #whatever the fuck it is
i = 0

while (i < len(array) + 1):
  i = i + 1
  j = i
  while (j < len(array) + 1):
    if (array[i] > array[j]):
       temp = array[i]
       array[i] = array[j]
       array[j] = temp
  j = j + 1
polar plover
#

the problem is that we need to change the list already passed to for

rugged sparrow
#

im trying to think of a way to make an infinite iterable without calling iter

polar plover
#

unless there is some other way for a while loop

sick hound
#

it does makes it ten times more difficult lol

polar plover
#

@rugged sparrow yhe that would work, we need a infinite iterable without function calls

formal sandal
#

Well, you can recreate function calls with map now :)

#
f(x) <=> [*map(f, [x])][0]
#

but that's cheating

#

right?

polar plover
#

is accesing atrributes okay like some_object.some_reason_this_is_a_infnite_iter ?

formal sandal
#

But if it is, then map is always cheating since it's a function call

rugged sparrow
#

@formal sandal i think that would count

#

since map requires a call for it to work as designed

#

but that makes all of this way easier

formal sandal
#

Yes, it's basically a long way of calling a function

stark fable
#

are we basically trying to do various things without calling functions?

formal sandal
#

yep

polar plover
#

yes

rugged sparrow
#

trying to recreate as many logical builtins without func calls

polar plover
#

or defining functions, like abs = lambda n: ...

rugged sparrow
#

obv stuff like compile and eval wont work

polar plover
#

itertools.dropwhile should be easy 🤔

stark fable
#

is creating a function and then calling it (i.e. (lambda x:...)(x)) allowed?

formal sandal
#

I don't think so

stark fable
#

are we doing no functions at all or just no builtin functions?

rugged sparrow
#

i think it is allowed

#

can use any funcs we create

#

but you cant use a builtin in any way

formal sandal
#

Are we allowed to call function arguments?

rugged sparrow
#

yes, as long as they are self defined

#

(lambda x:x()) would be ok as long as x isnt a builtin

formal sandal
#

I mean, given that you can't use any built-ins at all in any way

stark fable
#

so something like (lambda f:f(f))(lambda f:...) is fine?

rugged sparrow
#

ye

#

we can use recursion

#

for while

hollow patrol
#

what if we had

formal sandal
#

Is calling dunders prohbited?

#

and methods in general

rugged sparrow
#

calling methods is so yes

hollow patrol
#

(x := x + 1) while x < 3

polar plover
#

they are still built-ins in my bock

hollow patrol
#

a while expression

polar plover
#

like I would say no to list.append

formal sandal
#

You could 'box' the list.

polar plover
#

x:=x+[0] you mean?

formal sandal
#

No, wrap it as a function

#

Are def-definitions allowed?

rugged sparrow
#

nope

formal sandal
#

So you can call any functions that you create, right?

rugged sparrow
#

ye

stark fable
#

i found an infinite generator

#
inf = lambda: ((yield from x()) for x in [lambda: [0], inf])```
polar plover
#

YAY

stark fable
#

i'm not entirely sure how it works but it does apparently

formal sandal
#

Hm, that's like a linked list

#

Maybe we could recreate the iter function in the 2-argument form

polar plover
#

but would it not hit the reqursion limit at some point?

stark fable
#

good point, it actually only has 1996 elements

polar plover
#
---------------------------------------------------------------------------
RecursionError                            Traceback (most recent call last)
<ipython-input-6-a984fe978262> in <module>
----> 1 for i in inf():
      2     print(i)
      3 

<ipython-input-5-411632bd266f> in <genexpr>(.0)
----> 1 inf = lambda: ((yield from x()) for x in [lambda: [0], inf])

... last 1 frames repeated, from the frame below ...

<ipython-input-5-411632bd266f> in <genexpr>(.0)
----> 1 inf = lambda: ((yield from x()) for x in [lambda: [0], inf])

RecursionError: maximum recursion depth exceeded
``` yhe
#

but I think it should work for now

formal sandal
#

Is there some way to put nonlocal in a lambda?

stark fable
#

if we were allowed type then this would work py inf = type('',(),{'__next__':lambda*_:1})() but we're not

polar plover
#

oh yhe, defining a custom __next__ would be very good, we need to work on that

stark fable
#

i'm not sure if there's any way we can define classes

formal sandal
#

Well, we can use lambdas inside classes

stark fable
#

are class statements allowed?

formal sandal
#

I don't think so.

#

As well as defining dunders.

stark fable
#
class InfiniteGenerator:
    __next__ = lambda *_: 1```
rugged sparrow
#

nope that uses __build_class__ internally

stark fable
#

._.

formal sandal
#

Well, comprehensions use __next__ internally, don't they?

stark fable
#
  1           0 LOAD_FAST                0 (.0)
        >>    2 FOR_ITER                10 (to 14)
              4 STORE_FAST               1 (x)
              6 LOAD_FAST                1 (x)
              8 YIELD_VALUE
             10 POP_TOP
             12 JUMP_ABSOLUTE            2
        >>   14 LOAD_CONST               0 (None)
             16 RETURN_VALUE```
polar plover
#

is there a built in we can overwrite methods on? like this: py some_buil_in.__next__ = lambda *_: 1

vague hearth
#

can you make a merge sort using lambda recursion? idk if that would work better as it only needs to deal with 2 elements at once

rugged sparrow
#

iter = lambda f,s:x if (x:=f())==s else iter(f,s)

stark fable
#

uhh

#

if f() isn't s then it will just recurse forever

rugged sparrow
#

thats how iter(func, sentinel) works

#

although i need to change mine a bit

formal sandal
#

Can we assign to attributes and read attributes?

rugged sparrow
#

how would you do that in a lambda

formal sandal
#

valid point

stark fable
#

well reading attributes can be done in a lambda

formal sandal
#

But since we can't assign to attributes.that's a bit useless

polar plover
#

I made any..... ```py
any = lambda it: (x:False,[(x:=True)if i else None for i in it],x)[-1]

rugged sparrow
#

any = lambda i:[x:=False,[x:=j for j in i if j],x][2] my any

#

any doesnt actually always return True, if theres only one true item, it returns that item

polar plover
#

looking at it, it should return the last "True" item in the input right?

rugged sparrow
#

!e ```py
print(any([1]))
print(any([1,2]))
print(any([0,2]))
print(any([0]))

night quarryBOT
#

@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.

001 | True
002 | True
003 | True
004 | False
rugged sparrow
#

tf

#

i guess it does return True for only one element now

#

that explains why my one of my old oneliners stopped working

formal sandal
#

is it possible to define a list that contains itself?

rugged sparrow
#

(x:=[]).append(x)

formal sandal
#

Hm

rugged sparrow
#

oh wait that doesnt work

formal sandal
#

it doesn't

rugged sparrow
#

.append does tho

formal sandal
#

I mean, with current constraints.

rugged sparrow
#

i think we should allow using methods

formal sandal
#

I don't think you can modify a list at all.

#

Well, methods make everything much easier

#

Maybe we could switch to lazy linked lists.

#

It still won't allow modifying them, though.

#

Have we defined zip?

rugged sparrow
#

im trying to figure that out rn

#

i need len and range i think

#

but those are trivial

#

len = lambda i:[x:=0,[x:=x+1 for _ in i],x][2]

#

actually range with all of its capabilites would be very difficult

formal sandal
#

!e

# Maybe we could define some functions on lazy lists
y = lambda r:lambda x:r(r)(x)
q=y(lambda r:lambda L:(L or None)and(L[0],lambda:r(r)(L[1:])))
A = q([1,2,3])
print(A)
print(A[1]())
print(A[1]()[1]())
print(A[1]()[1]()[1]())
night quarryBOT
#

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

001 | (1, <function <lambda>.<locals>.<lambda>.<locals>.<lambda> at 0x7efd1b0ec0d0>)
002 | (2, <function <lambda>.<locals>.<lambda>.<locals>.<lambda> at 0x7efd1b0ec160>)
003 | (3, <function <lambda>.<locals>.<lambda>.<locals>.<lambda> at 0x7efd1b0ec1f0>)
004 | None
formal sandal
#

I think these would allow you to create a list that's inside itself

rugged sparrow
#

range = lambda n:[x:=-1,[x:=x+1 for()in[()]*n]][1]

#

theres range

#

it mostly works

#

acc adding start,stop, and step shouldnt be too hard

formal sandal
#

!e

y = lambda r:lambda *x:r(r)(*x)
inf = y(lambda r:lambda:(0,r(r)))
print(inf())
print(inf()[1]())
print(inf()[1]()[1]())
print(inf()[1]()[1]()[1]())
night quarryBOT
#

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

001 | (0, <function <lambda>.<locals>.<lambda> at 0x7fdfb91120d0>)
002 | (0, <function <lambda>.<locals>.<lambda> at 0x7fdfb91120d0>)
003 | (0, <function <lambda>.<locals>.<lambda> at 0x7fdfb9112040>)
004 | (0, <function <lambda>.<locals>.<lambda> at 0x7fdfb9112040>)
rugged sparrow
#

we could do something like that

#
range = lambda s,n,t:[x:=s-t,[x:=x+t for()in[()]*(n//t)]][1]
formal sandal
#

Is there a way to take just one element from a generator, like with next?

#

Without loading all the other elements.

rugged sparrow
#

maybe yield from?

zealous widget
#

x for x in iterable: break

#

rip

#

you can't even .send

snow beacon
#

Can we redefine the format for iterables? We could make them a tuple of (head, lambda:tail) to make things easier.

formal sandal
#

Yep, that's what I made above with lazy lists

#

Although they are immutable

#

The only way you can create a shareable mutable with these rules is via generator unpacking.

#

Lol, I think I've found a hack

#

I haven't

#

Well, you can still create a mutable value.

#

!e

mf = lambda:(1for _ in[1])
flag = mf()
print([*flag]==[1])
print([*flag]==[1])
night quarryBOT
#

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

001 | True
002 | False
formal sandal
#

It's a quantum mutable.

#

It's [1] until you have observed it, and [] after you have observed it.

#

I think it's the only way to make a mutable value right now.

#

That's a very cool idea for an isoteric language.

stark fable
#

hmm

#

if def was allowed then we could use += on a list

#

but it's not so ._.

rugged sparrow
#
tuple = lambda o=():(*o,)
list = lambda o=():[*o]
set = lambda o=():{*o}
dict = lambda *a, **w:{**{k:v for k,v in a},**w}
type = lambda o:o.__class__
str = lambda o:f'{o!s}'
repr = lambda o:f'{o!r}'
len = lambda i:[x:=0,[x:=x+1 for _ in i],x][2]
range = lambda s,n=None,step=1:[e:=n or s, s:=(s if n else 0),x:=s-step,[x:=x+step for()in[()]*((e-s)//step)]][3]
abs = lambda x:(x,-x)[x<0]
any = lambda i:[x:=False,[x:=True for j in i if j],x][2]
sum = lambda i,b=0:[[b:=b+j for j in i],b][1]
iter = lambda *a:[(yield (r:=a[0]())),r==a[1]][1] or (yield from iter(*a)) if len(a)>1 else (yield from a[0])
max = lambda *a, default=None, key=lambda a:a:[i:=(a[0] if len(a)==1 else a),m:=default or i[0],[m:=j for j in i if key(j)>key(m)],m][3]
min = lambda *a, default=None, key=lambda a:a:[i:=(a[0] if len(a)==1 else a),m:=default or i[0],[m:=j for j in i if key(j)<key(m)],m][3]
zip = lambda *i,j=0:((*[l[j] for l in i],j:=j+1)[:-1]for()in[()]*min([len(l) for l in i]))
enumerate = lambda i:zip(range(len(i)),i)
map = lambda f,l,*i:(f(*q) for q in zip(l,*i))
``` @formal sandal
formal sandal
#

wow

edgy kelp
#

Now do them with all the features of the class builtins

formal sandal
#

Does zip work with iterators?

#
x = (i for i in (1,2,3,4,5,6,7,8,9,10))
y = [*zip([1,2,3], x)]
#

I get a TypeError: 'generator' object is not subscriptable

edgy kelp
#

it should work with any iterable

#

not sure how you're getting the above error

rugged sparrow
#

yea i need to fix it

edgy kelp
#

ah

#

that zip

formal sandal
#

yep

edgy kelp
#

Well it should work with any iterable chilaxan 😛

rugged sparrow
#

yea i know

#

need to make a couple changes to fix it

formal sandal
#

type = lambda o:o.__class__

#

Aren't dunders prohibited?

#

Or it's just that we can't call them?

rugged sparrow
#

i couldnt think of any other way for that to work tbh

formal sandal
#

Is there any way to silence an exception with these constraints?

rugged sparrow
#

only if we allow calling type(type(()))()

#

and import

modern nova
#

@formal sandal dunders are methods. That lambda returns a function

#

Not a result

formal sandal
#

x.__class__ is not a method

#

!e

print(5 .__class__)
night quarryBOT
#

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

<class 'int'>
modern nova
#

Well color me stupid. Lol

edgy kelp
#

dunders are just names

rugged sparrow
#

zip = lambda *i,j=0:[(w:=[[*q] for q in i]),((*[l[j] for l in w],j:=j+1)[:-1]for()in[()]*min([len(l) for l in w]))][1]

#

this one can take generators