#esoteric-python
1 messages · Page 86 of 1
wdym when you say Combinator
i use this one:
Y = lambda f:(lambda x: f(lambda z:x(x)(z)))(lambda x:f(lambda z:x(x)(z)))
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
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
actually, that is the Z combinator, is it not?
pretty sure Z combinator is Y combinator adjusted for strict langs
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
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
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.
i tried to implement it for a subclassed set i had, but it wasn't reliable
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
iirc the changes made here guarantee __del__'s invocation as much as any context manager
@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
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.
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?
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
@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.
this let's you know if the object is ready to be deleted
i.e. still being referred to somewhere
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.
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
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
[]```
ye, python lets you use most unicode letters
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
pretty sure it will since python is interpreted
pretty sure python uses UTF-8 pretty insistently
some editors may not like it though
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
γκουντ τζομπ
"good job"
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.
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)
@bitter iris what if you don't want everything that dataclasses do?
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.
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?
Docs suggest not:
Performing
list(d)on a dictionary returns a list of all the keys used in the dictionary, in insertion order (if you want it sorted, just usesorted(d)instead).
https://docs.python.org/3/tutorial/datastructures.html#dictionaries
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 usesorted(d.keys())instead).
Backwards compatibility I believe
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
Yeah, it's not clear at first glance that dict's __iter__ only goes through keys, although most people learn after the first try.
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
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 
Is literal_eval safe?
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.```
There are bunch of errors it might raise, if you catch them all and have a maximum input length. It is safe~ish.
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 ^^
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.
You already have dataclass which is similar
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.
Is there a way to get hold of the current stack being used by the internal VM, without modifying cpython?
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
You can def do it with ctypes. It'll just be tricky probably
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}
""")
@edgy kelp :white_check_mark: Your eval job has completed with return code 0.
Hello, world!
I seem to recall a coding that allows escape sequences in code without the exec.
we need to go deeper https://paste.pythondiscord.com/exuxayaraf.py
how deep can we go
probably about 10MB is the limit of what you can trivially paste
@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
Nice
!e
m = 4
e = 2.5
print([e**i/(sum([e**j for j in range(m)])) for i in range(m)][::-1])
@hushed chasm :white_check_mark: Your eval job has completed with return code 0.
[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
!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)])
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
[]
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)])
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
[1.5394088669950738, 0.6157635467980296, 0.24630541871921183, 0.09852216748768473]
!e py m,e=range(4),2.5;print([e**i/(sum(e**j for j in m))for i in m][::-1])
@stark fable :white_check_mark: Your eval job has completed with return code 0.
[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
@formal sandal that's 4 characters shorter than yours and it actually works
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
!e ```
*m,e=3,2,1,0,2.5;print([ei/sum(ej for j in m)for i in m])
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
[0.6157635467980296, 0.24630541871921183, 0.09852216748768473, 0.03940886699507389]
@formal sandal @stark fable cut some length off by getting rid of the [::-1] at the end by removing the range
true, but this solution is not enterprise-ready as it doesn't scale well!
(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)
I don't think any of those solutions are "enterprise ready"
@proper vault you could __import__('sys').stdin.read(1)
Then I would have to filter out newlines
@proper vault but it depends on the implementation
Then i would have to filter out newlines
Afaik it does that by default
does it? ```pyimport 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']```
Depends on the implementation afaik
My python app on my phone does it
But just in case you could always just .replace
?
its all g
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__
that sounds difficult ```py
import dis
dis.dis('debug')
1 0 LOAD_CONST 0 (True)
2 RETURN_VALUE```
It isn't an actual constant during the parsing step, it becomes a constant when compiler throws tree into ast optimizer. https://github.com/python/cpython/blob/master/Python/ast_opt.c#L565-L568
It was also possible to assign it, at least for a while, with using walrus https://bugs.python.org/issue36052
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()
)```
Is v like a global object?
@hollow patrol i still think you should have used ctypes to push the vars into the local scope
it would be tricky but the end result would be clearer
Chains aren't immediately evaluated, they're functions
And I'm not sure how I would do that
That would be very tricky
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)
yeah
but that would require a lot of ctypes magic
and v.a is simpler for me to do
actually wait i have an idea
!e ```py
def f():
import inspect
inspect.currentframe().f_locals['a'] = 1
print(a)
f()
@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
dang
It's a bit more complicated than that
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.
that works
^
@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
ofc for mine to work youd actually need sys._getframe(1)
cause youd need to update the outer scope
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
1
@rugged sparrow That won't work on other python implementations
I think it should work on CPython and pypy.
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())```
@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
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?
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
there is the dumb way of
lambda l, i: l.__setitem__(i, new_value) or l
Add two slices to the new item?
that is akin to iterating over the whole list
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.
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
is there a way to pass the module a class comes from into the __prepare__ method of its metaclass
might it be possible to get it from cls.__module__?
that's a name of the module
ahhh
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
prepare only recieves a string
of the class name
not the class itself
i can use that string to search modules
yes, that was what I thought. It can't receive an unconstructed class ?
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
hahaha, just posted that solution
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
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
this strategy worked pretty well with __new__ managing everything
is there a maintained pretty printer for AST trees? i can only find old ones
astpretty is active
Also ast.dump itself got indent option recently for pretty printing
i thought about making one with bars | if it doesn't exist yet
How would it will look
I guess, like this
parent
|
+--- child
|
+--- grandchild
|
+--- grandchild(hello="world")
Hmm, interesting. Never seen such a printer for python's AST
something like that, but prettier
actually i could just wrap astpretty, would be easiest
You could also export into graphviz.
But it's such a pain in the ass... At least from my experience
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
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>
I would perhaps prefer an image for this like antlr4 does
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
That looks way better than the standard printer.
i'm about to sleep, i can post the code if someone wants to tinker with it in the mean time
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.
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
lol
hehehe
!e
def python(head, tail):
yield head
while 1: yield from tail()
tail = lambda: snake
snake = python(1, tail)
print(*snake)
@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
huh
i've never seen that error message
same
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
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.
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
@zealous widget man this printer looks sexy 
thanks, i'll bugcheck it in 12 hours or so
the gist above has all the updated code, gn for now
gn
gn
gn
snake("gn for now", "gn")
eheheh
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
@zealous widget you can generate AST from code objects right?
yep
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
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
true
i wonder if inspect could use console history support to implement getsource for the console
well, it's probably fine, if you defined something in the console, you have easy access to the text
where does the console store the history and can get access to it
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
🐍 f'{foo bar}'
File "<fstring>", line 1
(foo bar)
^
SyntaxError: invalid syntax
why does it convert
the {} to ()?
just what it places the expression into
It has no comma so it isn't a tuple, but if it had squiggly brackets it would be a set.
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'
I see this channel has been moved
you're a real channel now
its like a promotion
!e ```py
import os
os.close(0)
@rugged sparrow :warning: Your eval job has completed with return code 0.
[No output]
!e ```py
import os
os.close(0)
print(1)
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
1
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)
!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))
@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
This channel been moved?
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
Get string ids and you have nice randomness on top of that
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
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
yea that was more an attempt for something close enough to random that doesnt need any imports
hi, i am new to python . I will be glad if anyone can put me through in creating obfuscating letter
||A||
interesting
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
You could wrap the func with contextlib.redirectstdout
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
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.
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?)
@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
@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'])
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
<module 'sys' (built-in)>
!e ```py
print(help.call.globals['sys'].modules.keys())
@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'])
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__)
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)```
@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)
Unfortunately, I think dataclasses use __init__
ok lru cache didnt work on __new__
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)```
@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
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)```
@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)
it would be easier to do with a @classmethod
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
it would be easier if dataclass was something you subclassed not a decorator
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
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
i think so
!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
@river idol :warning: Your eval job has completed with return code 0.
[No output]
if it wasn't a dataclass you could define a meta with your caching __call__
right, I'll look into that, although metaclasses scare me
but dataclasses can be fragile if you start poking them too much
so i think the decorator is probably the best
Thanks 😃
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)
@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
It's like the usual Y-combinator, but it executes something on each step.
you could def minimize that using iter and some mutable to carry state instead of recursion
!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))
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
(<class 'ZeroDivisionError'>, ZeroDivisionError('division by zero'), <traceback object at 0x7f6b1b422900>)
!e ```py
def x():
print(1)
x(*[print(2)]*0)
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
001 | 2
002 | 1
@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
is this where i ask how to rename certain statements or at least make an alias for them
@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.
im pretty sure renaming statements to owo faces aren't practical
Then ask away.
How do I rename/alias common statements like if/elif/for/in to something else like OwO/UwU/XwX/^W^
The easiest way is to define functions that perform those functions.
Or you could use a site coding.
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.

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.
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)
@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'>}
this is amazing
!e
factorial = lambda x:{1<2:lambda:1,x>0:lambda:x*factorial(x-1)}[1<2]()
print(factorial(6))
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
720
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)
@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>)
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
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
haha @formal sandal
>>> _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))
>>> 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
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)
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```
Yeah I copied the wrong thing wait a minute
!e
print(0if 1else 1)
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
0
But why 0or 1 doesn't work?
!e ```py
print(0or 1)
@formal sandal :x: Your eval job has completed with return code 1.
001 | File "<string>", line 1
002 | SyntaxError: invalid octal literal
!e
print(0o731)
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
473
yes, I get 'invalid token' with 3.6
And invalid octal with 3.8
@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?
Woah
!e ```py
1 or ()()
@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?
There isn't anywhere else for it to go.
It makes more sense if you put brackets around the ()().
!e ```py
Makes more sense here:
my_list = [
(1, 2),
(3, 4),
(5, 6)
(7, 8),
(9, 0)
]```
@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
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.
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
Manifestly
It's actually lots of fun
I had to make a metametaclass for proper instance checking.
Too long to paste here, so: https://gist.github.com/decorator-factory/b2fd85ef8248c9230835461c1ec24597
I had to make a metametaclass for proper instance checking.
@formal sandal metametaclass, gosh you need to take a de-salting cure rn
Is there any way to pack the code into the eval command?
It's more than 2000 characters long even when minified
Yep
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))
@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
pretty straight-forward solution
Haha
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!
:speechless:
shame
SyntaxError: assignment expression cannot be used in a comprehension iterable expression
How did you get that?
[_ for _ in(r:=range)(5000)] not really a char advantage either, but shame
@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
Damn thought that might work around
Now for the real issue: is there any conceivable way to make my type system work with mypy?
Does mypy have no intersection types?
Also, It seems that I can't make a function parameter covariant? https://github.com/python/mypy/issues/7049
Well, I guess, I've just wasted lots of time.
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)
Could you show an example?
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.
is there any way to... uh, add a new bound method during runtime?
You might want to give Parent a __new__ or __init__ that passes Func a reference to the Parent object.
Or metaclasses.
survivor from ALGOL languages @typing 🤣
(It doesn't feel trivial though.)
Well, not necessarily metaclasses
By the way, because class definitions are just statements, everything is already done at runtime.
so if I do something like define a new function and then add it to the Parent class it works
It probably wouldn't be bound, but you can work around that by passing it a reference to the Parent object.
Oh, apparently it is bound.
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
Oh, function vs object?
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
Python supports multiple inheritance, co you could just create a mixin.
the truth is I'm doing some monkey-patching so that's not really an option
You could do Parent.f = lambda self, *args, **kwargs: Func()(self, *args, **kwargs) or similar.
That way it would treat it like a function.
oo
Maybe make a helper function like pass_self
can you elaborate, @typing ?
And actually, there's no need to create a Func class.
Just create a function factory.
also @snow beacon -- that MIGHT work... investigating. It works in my demo / IDLE env.
def make_function(callable_object):
def function_version(self, *args, **kwargs):
return callable_object(self, *args, **kwargs)
return function_version
Well, then you can just use callable_object, can't you?
callable_object isn't a function.
oh
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.
also, sorry -- I am experimenting right now... might take me a couple minutes
trying out the lambda option first
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)
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
world
So you might not need to build a whole class just for that call method.
@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
<nitpick> Well, a function and an object, since it cannot be a non-object</nitpick>
!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")
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
001 | Hello, alice!
002 | Guten Tag, bob!
So if you don't have any complex logic, you can do this. But it still fits the channel, unfortunately.
if you wanted it to further fit this channel, hook __build_class__ and transform the class body into a function def
!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())
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
1
i still need to mod it to allow for the func to take in variables
@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
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))
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
3
keyword args work
tried manually patching the func code to implement args properly but kept getting segfaults
@rugged sparrow is there a way to force writing to a read-only attribute?
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)
that makes it a bit more tricky to modify
what class is this
but not at the instance level
why are you trying to mod a socket instance
I mean, this is esoteric python :p
im not saying its impossible, but it would prob be easier to restructure the code
I feel like it's probably something stupider/simpler
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.
I've tried setting __slots__ but that doesn't work either :/
I'm wondering if I need to use dis
@dire linden what is your goal
You can use hax instead (:
@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()
This works, doesn't it?
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)```
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
The interior would still need to follow Python syntax, if not its semantics.
if you could hook the actual parser tho
How would you do that at runtime?
it would be very tricky
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__.
import hooks let you mutate a file before it is parsed right?
ive never used them before
I'm pretty sure fuckitpy ignores syntax errors in imported modules.
it just finds the lines that have errors and wraps them in try/except until it runs
So it seems.
Oh, it doesn't directly change the import hook, you instead call it on the filename you want to import.
yea
@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)
@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
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
socket.socket is written in c i believe
youre gonna need to use ctypes to access and mutate the struct
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
@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
It's probably written in C so you will need to do more work to mod it
but I'm modding the python subclass?
Then you need to mod the class before making an instance of it
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
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
I wonder how hard it would be to make this cross-platform.
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
If you aren't being esoteric, then you may as well just print it to stderr or something.
very true
man i've had to use windll before
not the best experience
still haven't figured out a filehandle-related bug
utter shambles
</complaints>
some of the func names are mangled af but i havent found any real issues yet
what was your filehandle bug?
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
what are you sending it for lpSecurityAttributes?
it affects how child processes can use the file
fuck
default is not at all
glad that was clearly labeled on the documentation
uhhhh
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
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
np
@zealous widget you might like this https://github.com/python/cpython/blob/master/Tools/peg_generator/pegen/grammar_visualizer.py
example output:
└──Rule
└──Rhs
└──Alt
├──NamedItem
│ └──StringLeaf("'a'")
└──NamedItem
└──Opt
└──Rhs
└──Alt
├──NamedItem
│ └──StringLeaf("'b'")
it is an internal tool only for testing
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"))
@last locust :white_check_mark: Your eval job has completed with return code 0.
001 | 7196301540258645269
002 | 7196301540258645269
003 | 7196301540258645269
004 | 7196301540258645269
005 | 7196301540258645269
!e py for _ in range(5): print(hash("Hello World"))
@last locust :white_check_mark: Your eval job has completed with return code 0.
001 | 503698058124208995
002 | 503698058124208995
003 | 503698058124208995
004 | 503698058124208995
005 | 503698058124208995
Exact same code, but two different outputs for the two executions?
Well, yes, hash doesn't have to be the same between executions.
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)
Source?
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)
@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
Well, it's not in the __builtin__ module.
!e
NoneType = type(None)
print(NoneType())
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
None
I don't now. Maybe because Python devs wanted to make the global scope smaller.
So basically the NoneType is just "hidden"?
As in you have to do type(None) to access the class
Yes, you can't even get it from types.
I don't know why you would ever need NoneType.
True, was just kinda curious
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).
Yea
I mean, they removed reduce from the global scope...
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
But for some reason compile and memoryview is in the global scope.
you can't get function types without importing them either
Except for the case I described earlier when you need to pass a class.
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
You can't set it with .__bases__ = ... either
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.
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
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
Well, mypy can do that
Well, argument signatures are trivial to verify.
@polar plover bet
I don't understand any of this lol
abs = lambda x:(x,-x)[x<0]
I do understand the def and the rest but not the ":"
map = lambda f,*i:(f(*q) for q in zip(*i))
whatever is after : is the return value
what next? would sorted be possible, we would need to make a sorting algo with no function calls xD
prob could
need to get for or while as an expression not a statement
that is essay, I have made many while loops as expressions
for in an expresion is easy
I prefer the while loop, i don't tend to use for loop in python
while is a bit trickier without func calls
!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])
@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
y+=0,
wait it lets you change the iterable size mid loop?
thought that didnt work for some reason
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
y+=[0] is not a expression 😭
oh, i'm dumb
idk if we can change a list (changing the list itself, not the varible to a new list)
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
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
the problem is that we need to change the list already passed to for
im trying to think of a way to make an infinite iterable without calling iter
unless there is some other way for a while loop
it does makes it ten times more difficult lol
@rugged sparrow yhe that would work, we need a infinite iterable without function calls
Well, you can recreate function calls with map now :)
f(x) <=> [*map(f, [x])][0]
but that's cheating
right?
is accesing atrributes okay like some_object.some_reason_this_is_a_infnite_iter ?
But if it is, then map is always cheating since it's a function call
@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
Yes, it's basically a long way of calling a function
are we basically trying to do various things without calling functions?
yep
yes
trying to recreate as many logical builtins without func calls
or defining functions, like abs = lambda n: ...
obv stuff like compile and eval wont work
itertools.dropwhile should be easy 🤔
is creating a function and then calling it (i.e. (lambda x:...)(x)) allowed?
I don't think so
are we doing no functions at all or just no builtin functions?
i think it is allowed
can use any funcs we create
but you cant use a builtin in any way
Are we allowed to call function arguments?
yes, as long as they are self defined
(lambda x:x()) would be ok as long as x isnt a builtin
I mean, given that you can't use any built-ins at all in any way
so something like (lambda f:f(f))(lambda f:...) is fine?
what if we had
calling methods is so yes
(x := x + 1) while x < 3
they are still built-ins in my bock
a while expression
like I would say no to list.append
You could 'box' the list.
x:=x+[0] you mean?
nope
So you can call any functions that you create, right?
ye
i found an infinite generator
inf = lambda: ((yield from x()) for x in [lambda: [0], inf])```
YAY
i'm not entirely sure how it works but it does apparently
Hm, that's like a linked list
Maybe we could recreate the iter function in the 2-argument form
but would it not hit the reqursion limit at some point?
good point, it actually only has 1996 elements
---------------------------------------------------------------------------
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
Is there some way to put nonlocal in a lambda?
if we were allowed type then this would work py inf = type('',(),{'__next__':lambda*_:1})() but we're not
oh yhe, defining a custom __next__ would be very good, we need to work on that
i'm not sure if there's any way we can define classes
Well, we can use lambdas inside classes
are class statements allowed?
class InfiniteGenerator:
__next__ = lambda *_: 1```
nope that uses __build_class__ internally
._.
Well, comprehensions use __next__ internally, don't they?
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```
is there a built in we can overwrite methods on? like this: py some_buil_in.__next__ = lambda *_: 1
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
iter = lambda f,s:x if (x:=f())==s else iter(f,s)
Can we assign to attributes and read attributes?
how would you do that in a lambda
valid point
well reading attributes can be done in a lambda
But since we can't assign to attributes.that's a bit useless
I made any..... ```py
any = lambda it: (x:False,[(x:=True)if i else None for i in it],x)[-1]
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
looking at it, it should return the last "True" item in the input right?
!e ```py
print(any([1]))
print(any([1,2]))
print(any([0,2]))
print(any([0]))
@rugged sparrow :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | True
003 | True
004 | False
tf
i guess it does return True for only one element now
that explains why my one of my old oneliners stopped working
is it possible to define a list that contains itself?
(x:=[]).append(x)
Hm
oh wait that doesnt work
it doesn't
.append does tho
I mean, with current constraints.
i think we should allow using methods
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?
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
!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]())
@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
I think these would allow you to create a list that's inside itself
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
!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]())
@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>)
we could do something like that
range = lambda s,n,t:[x:=s-t,[x:=x+t for()in[()]*(n//t)]][1]
Is there a way to take just one element from a generator, like with next?
Without loading all the other elements.
maybe yield from?
Can we redefine the format for iterables? We could make them a tuple of (head, lambda:tail) to make things easier.
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])
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
001 | True
002 | False
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.
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
wow
Now do them with all the features of the class builtins
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
yea i need to fix it
yep
Well it should work with any iterable chilaxan 😛
type = lambda o:o.__class__
Aren't dunders prohibited?
Or it's just that we can't call them?
i couldnt think of any other way for that to work tbh
Is there any way to silence an exception with these constraints?
@formal sandal :white_check_mark: Your eval job has completed with return code 0.
<class 'int'>
Well color me stupid. Lol
dunders are just names



