#internals-and-peps
1 messages Β· Page 145 of 1
if you don't want to suppress it, just ignore those arguments
but __exit__ will still run properly?
yes
π
omg i know tkinter
contextmanager has to care about those arguments because it's a very generic library function

i can't tell if this is a serious convo
hello, does anything need immediate moderation attention?
is this u
Yes he just posted a link with slurs and deleted it
yes it is me
tkinter is extremely sophisticated
fr
even python pros cant compete
fax
tkiner uis
my god...
epic
it's like i stepped into a time machine and went back to like iOS 3
that blue rounded button...
This isnt really appropriate for the channel
An interesting convo i was reading was interrupted for tkinter talk
This is spam at this point
no its not
@grave jolt if i do that ^^, how do i prevent someone from constructing an AtomicIntView on their own?
Try #user-interfaces if youre this excited
no
(even tho i enjoy it, it kinda is)
this is advanced
yes, but not advanced python π
im sharing my upper intellect in python
Share it elsewhere, this is offtopic for the channel
omg its advanced
thats what im saying
@astral gazelle cant u take jokes
@unkempt rock @unkempt rock This channel is for discussions about the Python language. If you want to discuss how awesome tkinter is, we have #user-interfaces .
Python language meaning the implementation (and ig language concepts, but libraries are not language concepts)
I know this was already brought up - but would you all say that iterators implement __next__ and are strongly recommended to implement __iter__ but don't have to?
I would argue that an iterator should always have __iter__, in the same way a mapping should always have a .items()
you can't
I actually don't know any libraries that force you to do that. Although it would be pretty nice.
if you want to enforce it, I'd return a separate object from __enter__ (as before)
but well, a number of things in python will not require the full protocol of whatever they operate on.
!mute @unkempt rock 3d you were already told to keep this channel on topic.
:incoming_envelope: :ok_hand: applied mute to @unkempt rock until <t:1635963331:f> (2 days and 23 hours).
is awesome
Hm, true
I guess it's a matter of the colloquial definition of an iterator to semantically what it needs and what it doesn't.
there are things in the stdlib that operate on iterators that do require __iter__, such as most of itertools
so I would argue it's more a matter of python being duck typed, so a function doesn't every actually take an iterator, it takes some object that has some methods, and for a lot of the stdlib, the methods are just __next__, and not __iter__.
hmmm... i can't have a secret param in __init__ or something, or set an instance attribute after calling __new__ manually before calling __init__?
or is that too unpythonic?
I hate this word
unpythonic?
yeah
(also is this not a little harsh of a punishment? 3 days is a long time)
some people just come here to shitpost π€·
well, idk i think it's something to live by, pythonic stuff is generally easier to understand too
>>> class a:
... def __init__(self):
... a.__init__ = None
...
>>> A = a()
>>> a
<class '__main__.a'>
>>> a()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'NoneType' object is not callable
>>> A.__init__
>>> A
<__main__.a object at 0x10520c7c0>
>>>
you could do this
that prevents __init__ being called again
i want to prevent a user from constructing a in the first place
(but my function still constructs it)
but i think i may be going about this the wrong way again :/
ohhhhh
nvm i see what it does (but still don't think it's what i want)
you can make __new__ return your single instance
hmm... can i steal __init__?
I would like to save the data passed to a variable in a function to be used later by the same function in a different state. how I can achieve this without using global variables. I have pickle library in my mind.
there is the slightly hacky option of
class A:
def __init__(self):
raise RuntimeError(f'cannot instantiate {type(self).__name__}')
@classmethod
def _create(cls, name):
self = cls.__new__()
self.name = name
@red solar why is important to prevent construction?
hmmm... would you say that's cleaner than stealing init?
class T:
def __init__(self):
pass
def _steal_init(self) -> Callable:
init = self.__init__
self.__init__ = None
return init
t_init = T()._steal_init()
def create_T():
t = T.__new__()
t_init(t)
return t
@rotund atlasyou can assign attributes to the function itself, e.g.
def counter():
counter.i = getattr(counter, 'i', 0) + 1
return counter.i
tnx let me try
it's complicated :/
I have AtomicIntView that's constructed from a buffer, but it absolutely cannot outlive the buffer, so i want it to only be useable inside a with statement, so I have a context manager function that returns an AtomicIntView on __enter__.... ugh
lemme think about it more and come back
https://github.com/doodspav/atomics/blob/devel-ffi/src/atomics/_impl/atomic/base.py#L52 i mean this is what i'm replacing rn
src/atomics/_impl/atomic/base.py line 52
class AtomicViewBase(PropertiesMixin, SupportedMixin):```
@red solar why would someone try to make one of these instances? Just because they shouldn't, doesn't mean you have to try to stop them. Maybe they just won't.
@red solar when i saw your code my first thought was to have a global datastructure and remove everything except maybe an ID from the classes to have pure @properties as API
from atomics import AtomicViewManager, AtomicIntView
i mean, with that naming it's not unlikely that someone would just create an AtomicIntView directly :/
i'm not quite sure what you mean?
name it _AtomicIntView
but like then people need to put a private type in their type hints
why do users of your code need to import that class, if they aren't making one?
You could make a function that takes an AtomicIntView. How would you type-hint it?
yeah that too
you could have a global _buffers {ID: buffer} that maps to the contents and the classes as a very thin layer for properties, maybe even with __slots__ for performance
OK, so they can import the class. that doesn't mean they will try to make one.
i don't want to store buffers anywhere i don't need to - ideally i handle buffers as lightly as possible for the least amount of time possible
like hot potato
i don't own the buffer, i have no control over what the user does with the buffer they provide me
so i'm trying to contain it in a with statement
π€·
@red solar using a with statement to manage object lifetime is good.
@grave jolt is it so bad for __enter__ to return self, and instead of type hinting telling the user they can't use an operation, it just raises an exception?
the only part about them that annoys me is that it's not a scope
just don't use the variable afterwards
ig, and i have an exception if they do, but just the fact that it's available...
seriously: why would they try to make one of these objects?
the end of the with block signals the "end" of the resource, if someone uses it afterwards it's really not your fault
give them a more convenient API that's the right way to do it.
I have AtomicInt which can be constructed as is, and used like a normal variable
I then have AtomicIntView which should only be obtained from AtomicViewManager in a with statement;
I feel it's too similar, and not obvious enough that View shouldn't be obtained the same way as non view
I think if you put it in a docstring, it's obvious enough
hmm... ok well i enjoy refactoring (no sarcasm), so i'll redo it with a manager, and then come back and you guys can tell me if it doesn't look obvious
What does an AtomicIntView do?
AtomicInt(width: int) allocates its own buffer
AtomicIntView(buffer) gets passed one, but after construction has all the same operations
(the view is more for shared memory scenarios)
(I was advised to get rid of AtomicInt and just have AtomicIntView, but i don't wanna do that)
Ohshit I'm glad that ned is here because if not I would've forgotten to try and reproduce that coverage bug π
While I see the benefits of PEP 671, it's growing in me the sentiment that step by step we are introducing more and more syntax to the language
I wonder if there's a middleground between syntax (as in just "operators") and statements, something a little more expressive by its own
honestly as annoying as it sounds the solution to this is just to make sure you get things right, and make sure your "base" syntax picks the best abstractions possible
in this case, 671 is literally just making up for a very weird wart in the language, so it's kind of a lose-lose situation
gotta keep up with the times, you know
are we talking about Rust and Kotlin
honestly I think Python did really well for its time
but 30 years down the road π₯΄
!pep 671
yeah tbh, for being like 5 years older than java, it's doing pretty well
syntax reminds me of Scala call by name
Rust does well for what it is but it's has a lot of different goals so I don't like to compare as directly
also ugly af
yeah, I was thinking in the sense that the designers put a lot of thought into the syntax and it's generally nice to write
just that the semantics (of lifetimes) complicate things
Yeah a lot of thought but a lot of language design real estate into things that only make sense if you care a lot about performance
what about it?
When we talk about syntax,.what kinds of things deserve good first class syntax, etc
import pkgutil
import importlib
modules_list = []
# Iterating through every module inside the classes package
for module in pkgutil.iter_modules(path=["./classes/"]):
# returning the module information that has 3 differnt attributes, but we need the whole information for now.
modules_list.append(module)
while True:
# Displaying the module alternatives
for count, e in enumerate(modules_list):
# e.name will return the module name
print(count, e.name.replace("_", " ").title())
print("X. Type 'x' or 'exit' to close the program")
usrInput = input("\nInput <<<: ")
if usrInput.lower() == "x" or usrInput.lower() == "exit":
exit()
elif usrInput.isdigit():
try:
# Trying to import the module specified by the user
module = importlib.import_module(f"classes.{modules_list[int(usrInput)].name}")
# Iterating through the module and trying to find the class name
for attr in dir(module):
if attr.startswith("bpPr_"): # bpPr_ being the prefix for my class names
pClass = getattr(module, attr)
# Calling the methods inside the class
pClass(int(usrInput)).option_output()
pClass.play()
except Exception as e:
print(f"Oobs... no such file...\n{e}")
else:
print("Oobs... must be a number!")
Is this well commented? Feedback? Any tips? Any "keywords" I should've used on a specific line when describing?
I don't think that's on topic for this channel, that's probably better for #python-discussion . But personally, I think that's over-commented. You should be writing comments to explain why a program does what it does, not just what it does. The code should be clear enough to tell the latter without too many comments.
^
code should be self-documenting
comments should be reserved for exceptional cases IMO
I think I've written one comment in the last month
and it was to explain why an unchecked cast was safe
Same, I rarely ever write comments that aren't docstrings
Hello! Is there a way to chain __init_subclaclass__ in multiple inheritance or is it only the first parent's __init_subclass__is run? Thanks!
Hello
you have to explicitly call the super init_subclass like with every other overriden method
One of the reasons __init_subclass__ was added is that unlike a metaclass it can play nice with inheritance. It's recommended that you write yours taking **kwargs, and then pass that up to the super call. That way each class can take off the args they need, and if there's any extra object.__init_subclass__() will reject them and raise the appropriate error.
I wouldn't mind if this syntax was used as a shorthand lambda syntax. maybe it can be done in a similar way to late-bound defaults (except lambdas have potentially more than one name on the parameter side). something like:
sort_on = lambda i: len(i)
sort_on = i => len(i)
flip_entry = lambda k, v: (int(v), k)
flip_entry = (k, v) => (int(v), k)
flip_entry = (k, v => (int(v), k))
hello
import socket
import ssl
hostname = 'www.python.org'
context = ssl.create_default_context()
with socket.create_connection((hostname, 443)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
print(ssock.version())
context obj created. how context obj connected with wrap_socket ?
context.wrap_socket(sock, server_hostname=hostname) - pls tell me the working of this line
my guide on that is the question "would my future self in 1 or more years take more than 1 minute to understand this code?"
I honestly canβt remember the last time I wrote a comment besides open source contributions, I usually just write docstrings since theyβre explanatory once
it creates new socket back that bundles the SSL/TLS settings from context, right? the context holds the SSL session config, like where to find certs, SSL version, what ciphets to use, what to verify, etc.
then you're either working with many well documented libraries that don't need lots of explaining on your side or you don't write very magical code in general or you're overconfident about what your future you will remember about that code π
Since Python 3.2 and 2.7.9, it is recommended to use the SSLContext.wrap_socket() of an SSLContext instance to wrap sockets as SSLSocket objects. The helper functions create_default_context() returns a new context with secure default settings. The old wrap_socket() function is deprecated since it is both inefficient and has no support for server name indication (SNI) and hostname matching.
Or my code is just self explanatory
Iβll write docstrings for every function usually tho
of course there's TODO / FIXME... and it never hurts to explain why you did something either, if it's not obvious, I think
What sucks is that sometimes flake8 will prevent me from committing a TODO note and Iβm sure there is a way to ignore it I just donβt know how
Since I want to finish it in a future commit
wow, that's crazy
is it because flake8-todo is installed?
Ahhh probably
there's also another plugin called flake8-todos, might be worth checking for that too
I was never big on "smart TODOs" showing up as problems in projects I've worked on. maybe it's helpful for some. but to me it's far from obvious the mere presence of a TODO indicates a bug
flake8-todo? never heard of..
Yeah that would be better
But still not quite there
while we're rethinking lambda syntax, we might also take into consideration more general ideas like callbacks/errbacks
async anonymous functions
You can already do this-ish by returning a coroutine in a lambda
- that's a question for a help-channel 2) that question doesn't really make any sense
My guide on comments is
If I come back to this code a few days or a week later, what doesn't instantly make sense to me?
I wrote it, it should make sense, so if it takes me any time at all to figure it out I try and comment it.
not a bad guide either
That's also why I switch from feature to feature, so I continually have to relearn the code π
Easy to question wtf I did and refactor when I come back to it and ends up being pretty damn good code if I do say so myself
well, i tend to dig deep into a particular part of the code to really wrap my head around all details so it also takes me a while to forget about the details, maybe 2-3 months, but basically i'm doing the same as you - work on different features or projects and then come back later with fresh eyes
after a few rounds of coming back to the same code, you get an idea of what kind of code needs commenting
can i ask a question here for school work ?
you can try, but if it's a simple question you might use one of the help-channels π
i mean i already asked in the general chat someone can toss me some tips on how to go about solving that question
its not : /
then go ahead
Ask in one of the available help channels, see #βο½how-to-get-help
you can post imagines in here, i think
you posted them twice
You should use an help channel if you feel the need to post an image
also hai amogor!
hey there!
@wide shuttle @surreal sun @feral cedar btw, i got a response on that python iterator vs iterable, changing iter behavior thing:
Unfortunately that isn't backwards-compatible. Some people may explicitly want their iterators to not be iterables to guarantee that people who want an iterator get a fresh/new one instead of reusing a live iterator.
I suppose that I could comment that such people have the option to implement their __iter__ function as throwing, actually
well, okay, they have the option to do that but it's still not backwards compatible
oh well
I didn't even consider that, actually. We discussed people who would want an iter implementation other than return self, but we didn't really consider that people would actually want iterators that are not iterable π€·ββοΈ
Hmm, so I guess inheriting from collections.abc.Iterator will do for now
yeah pretty much
inheriting from the correct ABC is generally a good choice for all kinds of reasons in any case
can some1 help me in Help corn
How should I type-hint a Union of the exact object of discord.embeds.Embed.Empty or a str. Embed.Empty is already initialized from discord.embeds._EmptyEmbed.
ooh, is that a new channel?
yes
cool!
ngl i find the hardest thing is writing pull requests, and issues
did i break PyCharm?
_init_AtomicIntView = AtomicIntView.__init__
AtomicIntView.__init__ = None
!e @static bluff re: "privacy" in Python, the closest thing you can get is using closures.
class Person:
def __init__(self, name, age):
my_name = name
my_age = age
def get_name():
return my_name
self.get_name = get_name
def set_name(name):
nonlocal my_name
my_name = name
self.set_name = set_name
def get_age():
return my_age
self.get_age = get_age
def set_age(age):
nonlocal my_age
my_age = age
self.set_age = set_age
p = Person("John Doe", 42)
print(p.get_name())
print(p.get_age())
p.set_age(24)
p.set_name("Jane Doe")
print(p.get_name())
print(p.get_age())
print(dir(p))
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | John Doe
002 | 42
003 | Jane Doe
004 | 24
005 | ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'get_age', 'get_name', 'set_age', 'set_name']
Not that any of this is a good idea, mind you. But that's a way to hide state that makes it harder to introspect and modify - not impossible, mind you, but harder.
isn't that just descriptors (@ property) with extra (or, well, maybe fewer) steps?
no - with descriptors, you usually still have a "private" attribute like _name or _age that is used by the property methods, and that shows up in dir() and that could be modified directly, out of contract
with this approach, the private state is not an attribute of the object, and is harder (though not impossible) to access directly.
(you need to get to it through p.get_age.__closure__[0])
ah he also asked about this in #c-extensions , was about to recommend an extension lol
yeah - I was following it there, but since this solution is language hacks instead of C extension hacks, I pinged him with this idea here.
there's a few things in the standard library that use a trick like this. @functools.cache does.
Lib/functools.py line 525
def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):```
I need help so my question is
I need to make a list of prime numbers up to 256 then from those prime numbers i need to sample of 3 values to XOR those numbers to get my hash value i have to
repeat this 16 times so far i got the code where it prints all the prime numbers up to 256
split your big problem into smaller problems, solve each one by one and win
i need help to start off with i have no clue about hashes and xor in python any example ?
!e print(True^False)
@verbal escarp :white_check_mark: Your eval job has completed with return code 0.
True
xor in python. read up on https://en.wikipedia.org/wiki/Hash_function
A hash function is any function that can be used to map data of arbitrary size to fixed-size values. The values returned by a hash function are called hash values, hash codes, digests, or simply hashes. The values are usually used to index a fixed-size table called a hash table. Use of a hash function to index a hash table is called hashing or ...
XOR is exclusive or, it is basically:
when you have True XOR True it'll give back False
if you have True XOR False it'll act like OR and give back True
if you have False XOR True it'll also give back True
and if you have False XOR False it'll be False
yea
What is a bitwise operation?
an operation that is defined based on the individual bits of an integer represented in binary.
!e ```py
a = 0b101
b = 0b011
print(bin(a | b), a | b)
print(bin(a & b), a & b)
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | 0b111 7
002 | 0b1 1
ok, so in decimal, the normal numbering system that you're used to, numbers have a ones column, and a tens column, and a hundreds column, and a thousands column, because it's base 10.
in binary, numbers have a ones column, and a twos column, and a fours column, and an eights column, because it's base 2
I've never learned about bases?
so the number 1011 in binary is 1 * 8 + 0 * 4 + 1 * 2 + 1 * 1
which is 11 in decimal.
it's not math, it's counting.
1 * 8 + 0 * 4 + 1 * 2 + 1 * 1 gave me a brain freeze
in decimal, after 9 is 10, after 99 is 100, after 999 is 1000. In binary, after 1 is 10, after 11 is 100, after 111 is 1000
counting from 0 to 10 in binary is:
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
in decimal, every time you try to go up from a 9 in a column, you carry a 1 to the left. In binary, every time you try to go up from a 1 in a column, you carry a 1 to the left.
that's because in decimal, 9 is the highest symbol, and in binary, 1 is the highest symbol.
and you know that 1010 in binary is 10 in decimal, because it's got a 1 in the eights column and a 1 in the twos column, and 8 + 2 is 10.
Oh I see, but how come it's not this then:
0000
0001
0010
0011
0110 instead of 0100
0111
1110
etc..
because 1 + 1 is 0 carry the 1, and 1 + 1 is 0 carry the 1, and so you've carried a 1 twice and gotten two zeroes, for 100
and because 011 is 3 (zero fours and one two and one one), and because 100 is four (one fours and zero twos and zero ones)
so what would 23 be in binary?
one sixteen plus one four plus one two plus one one
wait
10111
so the columns go like this:
1 2 4 8 16 32 64 128, etc...
ok lemme try to get the number 54 in binary
Hello guys, am new here, and i want to learn pyhton
!e 16+16
@unkempt rock :warning: Your eval job has completed with return code 0.
[No output]
!e print(16+16)
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
32
I am also
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
40
you can have at most one sixteen - you can't add 16 + 16
oh?
we're off topic in this channel, actually - let's move this over to #ot1-perplexing-regexing
sorry if my english so bad, but can you tell me if i want to learn pyhton what apk that i must have?
First of all you should make English language better because further you need most this language
okay then, where should i start??
Hi, I want to catch exceptions raised in the child process in a multiprocessing concept
How can I do it??
anyone available to help? I'm having issues separating and formatting multiple outputs from a for loop question in #help-pear
that'd be a better question for #async-and-concurrency
anyone good at AST module please help in #help-broccoli
Tail Recursion in python without introspection
wtf π
they use an exception to escape the stack and call the next function without recursion
i'm impressed and appalled at the same time
if that doesn't have a massive performance penalty..
The descriptor could probably hide the value in a similar obfuscated way to hiding it in a closure cell, if you'd take a different path from how you typically solve this issue. Another thing that would make it more difficult to access the value is to have a descriptor that has a __set__ method and "hides" the value in the instance dict under the same attribute name. It would still be available in the instance dict, but not on regular attribute access, as the descriptor overrides the access. In all cases, you'd have some searching to do, but you can still find a reference to the value somewhere. Closures is probably the easiest way to do this, although it's less reusable than a descriptor that hides the value somehow.
results = []
for x in range(100):
before = perf_counter_ns()
factorial_tail(x)
foo = perf_counter_ns()-before
results.append(foo)
print([f(results) for f in [min, max, median, mean, stdev]])
gives
[400, 1800, 500.0, 538, 193.73000059699874]
[1800, 130100, 61750.0, 63640, 36691.75450267878]
upper is reference to an lru_cached naive factorial function, the lower is the tail-recursive one
in nanoseconds
Counting on the descriptor to override the instance dict is clever, but isn't the attribute lookup order for data descriptors and non-data descriptors different? I vaguely recall that sometimes the instance dict is searched first and sometimes not.
i'm not sure if sacrificing performance for infinite recursion is a good idea..
Yes, that's why you'd have to have either a __set__ or __delete__ to ensure it's an 'overriding' descriptor (to use term Fluent Python uses for it, if I recall correctly)
It does make for an easy way to implement a cached property, were it not that we don't have to anymore
The docs call that a "data descriptor"
okay, that performance test is BS, i normalized it with 10000 calls and a factorial of 200 which gives ```
[100, 352700, 200.0, 224.02, 3529.757351192264]
[244400, 5153700, 263900.0, 320027.07, 123130.9109539044]
Yeah, that's in Hettinger's tutorial, right?
Or does it do so in the reference as well?
I'm looking at Hettinger's, but I believe the reference docs use the same term
Ah, yes,
Note, adding
__set__()or__delete__()changes the kind of descriptor to a βdata descriptorβ. See Invoking Descriptors for more details.
But I'm with you now, I missed the significance of __set__ on first read. This is a clever approach.
More work as a one off, but reusable, so that's cool.
Could be wrapped up into an @private_property
||What is @private_property ?||...
a thing that doesn't exist, but could be built using this idea.
actually - we don't even need a new decorator for it, really. We can just use @property as long as we always have a deleter, I think...
I've seen people use @propert but what does it really do?
type hinting?
the function or what?
property allows you to customize what should happen when a variable is accessed or set to, or deleted
Example:
If you only want to have a way to get the value
class Test:
@property
def value(self) -> int:
return 5
test = Test()
print(test.value)
>>> 5
test.value = 2
AttributeError: canβt set attribute value
If you want to be able to set it too, something like
class Test:
def __init__(self):
self._value = 5
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, value: int) -> None:
self._value = value
test = Test()
print(test.value)
>>> 5
test.value = 2
print(test.value)
>>> 2
and if you wanna be able to delete it
class Test:
def __init__(self):
self._value = 5
@property
def value(self) -> int:
return self._value
@value.setter
def value(self, value: int) -> None:
self._value = value
@value.deleter
def value(self) -> None:
print("value has been deleted!")
del self._value
test = Test()
print(test.value)
>>> 5
test.value = 2
print(test.value)
>>> 2
del test.value
>>> "value has been deleted"
print(test.value)
>>> error about how it doesnβt exist (like AttributeError: "value" is not an attribute or something)
How is this useful?
say you want to restrict the value of an attribute to specific values, you can do that with properties
Hereβs an example:
datetime.datetime uses properties for their attributes, so the user canβt change it and make the program go haywire. They technically can change via a βprivateβ attribute, but itβs not made known and most people will only interact with the βpublicβ attributes
Because if the user edits it to an hour that doesnβt exist like 42, datetime.datetime would want to restrict that
Ahh okay ty
No problem!
I'd like to evict some keys from an in-memory cache container and I was thinking to do this from a "worker" task, as in:
class Cache:
worker_interval: int = 86400 # 24 hours in seconds
worker: Optional[Task] = None
container: Optional[RedisDict] = None
@classmethod
async def run_worker() -> None:
await asyncio.sleep(cls.worker_interval)
await cls.evict_what_should_be_from_my_cache_container()
cls.worker = asyncio.create_task(cls.run_worker())
@classmethod
async def evict_what_should_be_from_my_cache_container() -> None:
"""
Replaces `container` with a deep copy that is just like the original minus the
keys that were too old to be worth keeping.
"""
Is there something fundamentally wrong with this design?
Sorry I wont be able to help u but what is "evict some keys"?
I've commented this function to address your question.
I don't think your task is correct
What you usually do is something along the line of
asyncio.create_task(main_task())
while True:
await side_task()
await asyncio.sleep(DELAY_BETWEEN)
Why is my task not correct?
Because you start by sleeping, then you clear the cache once and start your main task and never sleep or clear again
Oh wait, it is a recursive call
yup
Well, it doesn't work anyway as you don't run the worker at the same time
In point of fact, it works.
This is also recursion :p
Well are you already running that in another task?
Because if you really want to do this, you don't have to re-run run_worker in another task and you basically have the same code as me, but you fill up the stack overtime
the recursive call fills up the stack?
Yeah, each call is another stack frame
@unkempt rock Makes sense, thank you!
1000 frames iirc
I was hoping I would be able to use tail-recursion optimizations, but I see Python does not out of the box do tail-recursion optimizations.
!e
import sys
print(sys.getrecursionlimit())```
@unkempt rock :white_check_mark: Your eval job has completed with return code 0.
1000
I thought it was much more by default
I wonder if that'd get raised up by the one million PEP
:)
it can't go much higher before running out of space
Python doesn't do any form of static optimisation, to allow the level of introspection it has
Do you know how large a call frame is, num?
No idea.
Fair enough
It is an actually question, I don't know how large it is, heh
Not exactly, but they are fairly large iirc
This is just snekbox though?
We don't lower it in snekbox
Ah
a PyFrameObject is 48 bytes, InterpreterFrame is 80 bytes
The interpreter is pretty much running normally, it is just the kernel applying some limit on it
While you folks are here, may I ask a last "my python is more rusty than I thought" question?
Consider:
MyClass1(Mixin1, Base):
...
MyClass2(Mixin2, Base):
...
where Base is a subclass of ABC. Question: can I do something so that MyClass1 and MyClass2 will appear to my IDE's static type checker as instances of a single type, i.e. a type defined as constituted of any combination of Base + something?
They will both be a subclass of Base
You can't say anything else about them, there is no other common ancestor
Indeed but my static type checker does not see the attributes/methods inherited from their respective mixin.
what's your typechecker
Otherwise you have a Union[MyClass1, MyClass2]
Pyright.
But in either case, if you use an isinstance check it will work fine
duh
Of course.
Thanksies!
does isinstance narrow the variable type ?
Yep!
I think i shouldn't be here
which operating system is best for python
I don't think python really needs specific os
It all depends on user preferences
U can use what u prefer
one benefit of linux/unix is there's no need for a py.exe launcher
and the shebang (#!/usr/bin/env python3) at the top of python sources should just work, mostly
IME there are more minor bugs and caveats for the closer-to-OS stuff on windows, than linux
personally I find it easier to build python itself and extension modules than on Windows, too
maybe less than in the past
but I do remember qutie a few cases of going through a module like os, or subprocess, and there are things that seem more with linux in mind, and on windows theyd on't work, or don't work fully
What's everyone's fave piece of Python's syntax?
I know we take it for granted, but mine is probably python's flexibility in terms of arguments
Hmm, I really love match/case, but I haven't gotten to use it all too much
Second to that, iterable unpacking
ohh, you're asking that type
unpacking is really nice honestly
i would agree with arguments as it's pretty unique to python as well
one of the features i like is
one, two, *three_and_above = *[1,2,3,4]
We're learning C++, and the entire notion of a dictionary literal goes way beyond what it can do
So even just that is a win
that's not really true
C++ can do that stuff with libraries that use functions and lambdas, which is how most languages do it
it also has initializer lists built in
unordered_map x{{"hello", 5}, {"goodbye", 10}};
and so on
(sorry at first I was talking about comprehensions rather than literals)
comprehensions are pretty unique and neat
some other langs have them, but yeah they're great
werent they invented in python?
they're reminiscent of set builder notation from math. no idea if they first showed up in python
they are from math, and I think they were in some ML derivative first
oh, wow. there's a whole big wikipedia article about that - https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(list_comprehension)
List comprehension is a syntactic construct available in some programming languages for creating a list based on existing lists. It follows the form of the mathematical set-builder notation (set comprehension) as distinct from the use of map and filter functions.
Boo
A list comprehension is a syntactic construct available in some programming languages for creating a list based on existing lists. It follows the form of the mathematical set-builder notation (set comprehension) as distinct from the use of map and filter functions.
1969 in SETL
never heard of that before
hmm.. i know it's double-edged, but i think the whole idea of protocols and mapping syntax to methods is pretty nice
i think that was one of the things that made me fall in love with python in the first place
how clean and simple everything looks, hiding away complexity
while you still can get into the details if you really want or need
oh, and for-loops are absolutely amazing
if you come from a language like java that is one of those "OMFG HOW IS THAT EVEN POSSIBLE AND WHY CANT ALL LANGUAGES HAVE THAT!?!" features
java has for each loops though
i've ran from java a long time ago ^^
before java 5?
apparently so
just looking at the syntax, it's not nearly as nice as python for-loops though
for (Iterator it = hs.iterator() ; it.hasNext() ; )
System.out.println( it.next() );
that is not a foreach loop lol
you can just
for(var a: hs) {}
oh
ah
okay, whatever ^^
ever since i had to write uni exams in java by hand i hate it
yeah, i had hand-written java too. luckily my teacher let us abbreviate things (RightRectangularPrism π© )
in C, would for each loops be something like:
#include <stdio.h>
int main() {
int arr[] = {1, 2, 3, 4, 5};
for (int *pointer = arr; pointer < arr + (sizeof(arr) / 4); pointer++) {
printf("Value: %d", *pointer);
}
}
This sounds like a name that would be generated from a repl.it name generator
should be a band name
IndentationError: mixed use of tabs and spaces
You have got to be kidding me lmao
no, though if you do need a custom iterator, you do
for(SetIterator it = set_iterator(some_set); set_it_has_next(it); set_it_next(&it)) { puts(set_it_get(it)); }
Hm, is there a style guide for C?
you mean while-loops as for-loops?
there are several
I mean things like
array = [1, 2, 3]
for i in range(len(array)):
print(array[i])
ohh
yeah, that looks like it's written by someone coming from one of those languages
not having embraced the beauty of python's for-loop yet
Honestly, I will always love
for idx, _ in enumerate(array):
...
over
for i in range(len(array)):
...
if you want to get the 'index' in an array only
enumerate looks a lot nicer in most cases if I'm being frank
i'd prefer the second
at least it's clear what you're doing there
also.. why???
:p
hm, fair
but descriptive for loop variable names go a long way, so as long as you aren't doing something like
for a, b in enumerate(...)
or just overall random names, i wouldn't care too much
mostly a personal preference for enumerate
when do you ever need the index but not an element while iterating over something?
actually, fair point
I had a usecase for it a while back but I can't remember it
don't know where to put this but does anyone know any open source python algorithms that make use of neural networks to identify common road items{road, traffic signs etc}
see opencv? also #data-science-and-ml
@verbal escarp when you are only writing to elements
Sth like double all elements of a list
then i'd question whether a list is the best approach, numpy arrays would make this much nicer.. but okay, at least one use-case
!e @wide shuttle @static bluff Following up on Sebastiaan's idea from this morning, this does a decent job of hiding private state without being nearly as weird as the closure approach I proposed:
class Person:
def __init__(self, name, age):
self.__dict__["name"] = name
self.__dict__["age"] = age
@property
def name(self):
return self.__dict__["name"]
@name.setter
def name(self, name):
if not name:
raise ValueError("Name must not be empty")
self.__dict__["name"] = name
@property
def age(self):
return self.__dict__["age"]
@age.setter
def age(self, age):
if age < 0:
raise ValueError("Age must not be negative")
self.__dict__["age"] = age
p = Person("John Doe", 42)
print(p.name)
print(p.age)
p.age = 24
p.name = "Jane Doe"
print(p.name)
print(p.age)
print(dir(p))
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | John Doe
002 | 42
003 | Jane Doe
004 | 24
005 | ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'name']
It's not quite as hidden as the closure approach - instead of poking around in .__closure__ the user has to go poking around in .__dict__, which is a bit easier. But hopefully it's reasonably obvious that .__dict__ is private and shouldn't be messed with. If you're super paranoid, you could go with .__dict__["don't"]["touch"]["this"]["age"] π
How does this work?
How does Python access the property?
descriptors are looked up on the type, rather than on the instance. If the descriptor has a __set__ or a __delete__, it prevents the lookup from the instance dictionary from ever taking place.
Ah
which lets us use the same name in the instance dictionary for the "private" state.
So by looked up by type, you mean that it'll check for name in self via if it's a property? What if there are multiple property's?
no, I mean that getattr(obj, name) checks for type(obj).__dict__[name] and if it's found and is a descriptor with __set__ or __delete__, it is used instead of obj.__dict__[name]
https://docs.python.org/3/howto/descriptor.html walks through descriptors in great detail - if they're new to you, you should read through that.
ohhh
depends on where they are
wdym?
e.g what is obj.__dict__?
i thought variables couldn't start with a underscore?
with double underscores on both sides it's variable used by the interpreter that you generally don't interact with directly, with __dict__ you access the instance dictionary that stores all the instance attributes
They can have underscores anywhere
They can. In fact, single underscores are often used to indicate "private" variables.
ugh my confusion at 2am starts again
what is a "interpreter" and a "instance dictionary"
i hear them everyday, but I don't know what it is and what it does
The Python interpreter is what executes your Python code.
I see, so _variable name is like a private variable, but it does actually nothing right?
It doesn't have any special meaning in the interpreter, correct
Ah ok understood
but what did the double underscores on each side do?
and if u can please try to describe with like friendly english
Those are dunder methods, that's a whole other thing that I am definitely not qualified to explain.
No, it's not a hard concept, I just don't know how to explain them very well since I don't mess with them much.
Ah I see okay, thanks for trying tho π
you access the instance dictionary that stores all the instance attributes
wdym with this?
Has anyone heard any updates about the 3.11 speed updates being funded by microsoft?
it was basically an example of "dunder" (double underscore) functions and what that signifies
they're basically special cases in classes that u interact with in unique ways something like that
Have you learned classes yet?
!e If so, __dict__ is a dictionary that holds instance attributes.
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
john = Person("John Doe", 42)
print(john.__dict__)
print(vars(john))
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
001 | {'name': 'John Doe', 'age': 42}
002 | {'name': 'John Doe', 'age': 42}
That is, when you assign to self.foo, that's basically an assignment to self.__dict__["foo"] (at least, normally - there are exceptions)
@arctic ruin
I believe they're officially called magic methods, they allow you to have special behaviour. You already know that __init__() is called to initialize the class, well there's also __call__ that will make that class callable (like a function!).
What people have been messing around with above is the __dict__ attribute, this is a special attribute (as indicated by the __). Here is where Python stores all attributes, so when you do a.b that means that 'b' is looked up in a's __dict__ dictionary*.
*There's of course exceptions
aren't they officially called dunders
nah that's the sketchy name that misanthropes like me use
Basically Python itself has reserved all __names__ for its own use, you aren't supposed to use them except for where the language documents you can use them. They're used for customisation hooks all over, since they're reserved future versions can add additional ones without worrying about breaking existing code.
The docs use the term "special method" instead of magic, and describe dunders as System-defined names, informally known as βdunderβ names.:
https://docs.python.org/3/reference/lexical_analysis.html#identifiers
i guess i'm less edgy than i thought π€‘
Yep, they do so, and in 3.11 a lot of the optimisation effort is implementing infrastructure to cache results for more opcodes.
3.11 is implementing a 'specialising' interpreter, which records the types used in various opcodes, then if the types are consistent across multiple calls it swaps out the generic opcodes for more specialised ones (for instance BINARY_ADD_INT, CALL_FUNCTION_BULTIN_O, etc).
anyone familiar with XML interface using .xsd file type?
I fell a sleep and i wake up to this, i screenshotted everything ill look into it later π i cant even feel my heart beating yet, wai what
so something is a magic method (special method), there are different types of this method, two of them is init and dict, where you call init to initialize your class and dict is for accessing all attributes made in the class?
yeah pretty much, except __dict__ isn't a method, its just an attribute
oh so there are also cases where something can be attributes and methods?
btw hat is vars()? and hy do john-dict instead of john.name?
guys... since dictionary updates are atomic operations.... doesn't that mean it is kind of like a lock?
let's say I have a requests.Session() and I store it in a dictionary
every 10 seconds another thread will create a new session and then update the dictionary
so I think it is thread safe for the other thread to do like
sessions[key].post(url, data)
because of the dictionary update?
even if the session is not a threadsafe object, I think it is safe if the session is given to the dictionary and not used in the thread that created it
every cpython instruction is "atomic" unless the code it invokes releases the gil (in the case of instructions that run C code underneath) or runs some other code, but you'll find that most operations consist of more than one instruction
the dictionary save itself won't break anything if it's threaded, but you may need to consider that threads can switch between the object creation and item assignment, and the load can switch after looking up the dictionary key but before looking up the method
# Sets
# *args, **kwargs, packing and unpacking
# * and \ in function definitions
# Learning type hintings and mypy, doctstrings
# Annotations
# Inheritance
# List comprehension, slices and generators
# Mixins and collectons.abc
# Positional vs named arguments
# Walrus operator and match statements
# Contextlib
# Pdb, doctest and unittest
# Multithreading and asyncio
# Learn modules: collections and itertools
# Learn 3rd party libs (pandas and numpy)
# Generators, decorators
# Asynchronous programming
# Socketing
# Superclasses
# Metacasses
# Learn actual algorithms
# Datastructures
# Discrete math
# Testing frameworks
# Design patterns
# Devops and deployments
Could someone be kind and edit this list by sorting it from easier to learn to harder to learn?
my brain is broken, is this homework or prep to create homework?
Just what I need to learn in python
this is the final list:
# FUNCTIONS #
"1"| Positional vs named arguments
"2"| *args, **kwargs, packing and unpacking
"3"| * and \ in function definitions
# CLASSES/OBJECTS #
"1"| Inheritance
"2"| Superclasses
"3"| Mixins and collectons.abc
"4"| Metacasses
"5"| Design patterns
# LISTS/DICTS/SETS etc.. #
"1"| Datastructures
"2"| List comprehension, slices and generators
"3"| Learn modules: collections and itertools
"4"| Generators, decorators
"5"| Walrus operator and match statements
# OTHER #
"1"| Annotations
"2"| Docstrings and mypy
"1"| Socketing
"2"| Contextlib
"1"| Pdb, doctest and unittest
"2"| Testing frameworks
"1"| Multithreading and asyncio
"2"| Asynchronous programming
"1"| Discrete math
"2"| Learn 3rd party libs, pandas and numpy
"3"| Learn actual algorithms
"1"| Devops and deployments
why?
Why not?
is there a specific reason why you need to learn it or is it just something you want to learn?
hard to say what's difficult because it varies from person to person, could maybe comment on which things are more useful
datastructures alone can fill books
as well as sockets, multithreading, async
devops
algorithms
and even then depends on what you're doing, in some contexts asyncio is easily at the top of the list, in others you will never touch it
but there are some things that you almost always want like list/generator comprehensions and understanding why we care about generators
and "annotations" shouldn't be "other"
i think that's more important than walrus or match (both of which you really don't need that often, at all)
same as metaclasses
never really needed them in all those years
also the sooner you spin up pytest the better
unit tests definitely should be on that list
ah, it is (as "other")
@unkempt rock what do you want to do?
what do you need python for?
Computer Science, AI and Software engineering
so you're studying for a degree?
or do you have some concrete project in mind?
@unkempt rock ?
Studying for a degree
okay, that narrows things down
Yessir, I'm just 17 and I want get the basics of python down, and then focus on more (intermediate and advanced) stuff
well, you should stick to the basic syntax and wrap your head around the theory then before going to stuff you'll probably never need (like metaclasses)
datastructures, algorithms, maths
I never need those?
those are the theoretical underpinnings you'll need to wrap your head around
and advanced stuff like metaclasses you can safely ignore for now
But I've basically learned the basics in python
That's why I made a full list on what I should learn next
metaclasses in python just aren't really worth learning at this point
then try to implement those theoretical concepts you learn (datastructures, algorithms, maths) in python
it's very python specific, even for professional python developers it's usually used rarely
you should as amogorkon suggests focus more on general concepts that transcend all or at least most programming languages.
algorithms, data structures, can also look at things like classes, inheritance, data classes
im bad at maths 
learn it
no never
you don't need super advanced math to be good at programming, but at least knowing the basics well
knowing how to do complexity analysis, construct a basic proof
1 + 1 = 2, i'm not going further than this, i hate it
Also if you want to do AI or ML, that's basically all math
yup
shit.
Yeah
signal processing, language.. that's algebra and statistics right there
If you don't know calculus, linear algebra, or probability, you will never be more than a (sorry) code monkey in AI or ML, using existing packages on existing data, not really understanding why things work or don't work, messing around randomly
well, do your best then to turn that around, and avoid AI/ML. Also, we're pretty off topic at this point.
higher level computer science courses are very similar to a math class
maybe #career-advice
Math is funny when you understand it, if you dont, then it's probably the most boring thing in the world
same as programming ^^
https://bugs.python.org/issue33346 <- async comprehensions? oh man..
Ooh
#help-pineapple help me pls
mainmenu: https://paste.ofcode.org/CETuG6zgenvf7CepZBfT4N
Hello, I'm letting the user choose which class should be instanced by finding the class using prefix names and using the pkgutil and importlib modules. Now, how can I do this using subclasses and flags?
I was checking out the CPython implementation of generators and it's tempting to believe that generators (comprehensions) are almost always better than lists (comprehension), as it seems that the only argument for lists over generators is when you need to traverse iterables several times, which is seldom the case.
Do you folks agree with that?
@manic sundial str.join is slightly faster on a list than on a generator
Point taken, concatenations might be better on lists.
hm?
so concatenation-based operations, and sorting.
no there's no generality here, that's just how str.join is implemented in CPython π
I get that, but the generalization I think is warranted. actually I don't know.
Other way around? It's faster because list comprehensions are faster than generators
any1?
For a generator CPython needs to create a generator, then iterate and exhaust it normally as with any iterable/generator
This is slower than how CPython can optimize list comprehensions
A list comprehension is often slower on larger lists because it needs to allocate a giant list on the heap.
If str.join encounters something other than a tuple or a list, it creates an array out of it. So it's going to be strictly worse than a list.
Is it regarded as "Pythonic" to compose multiple generator functions, as in
with_it = lambda it: (x for x in it if predicate(x))
with_it2 = lambda it: (f(x) for x in with_it(it))
final_gen = (x for x in with_it2(my_iterable))
?
why not just user filter and map
To minimize memory footprint.
filter and map are lazy anyways
filter and map return iterators
Why not this? ```py
with_it = (x for x in my_iterable if predicate(x))
with_it2 = (f(x) for x in with_it)
final_gen = (g(h(x)) for x in with_it2)
Because then I cannot compose them using a regular higher-order function compositor.
It's nice to compose generator functions like any other function.
I think filter and map traverse the iterable once each time, i.e. twice overall.
that wouldn't work with generators or other iterators
A composition of generator functions I think traverse the iterable just once.
because you can't traverse them twice
!e
list(map(lambda x: print('map2'), map(lambda x: print('map1'), (1, 2, 3, 4, 5))))
!e
def f():
print('a')
yield 1
print('b')
yield 2
print('c')
yield 3
print(list(map(str, f())))
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | a
002 | b
003 | c
004 | ['1', '2', '3']
I'm not sure what you mean by this
!e
list(map(lambda x: print('map2'), map(lambda x: print('map1'), (1, 2, 3, 4, 5))))
@queen dust :white_check_mark: Your eval job has completed with return code 0.
001 | map1
002 | map2
003 | map1
004 | map2
005 | map1
006 | map2
007 | map1
008 | map2
009 | map1
010 | map2
What I mean is: with a composition of generator functions, the entire set of operations defined by each individual generator is applied on every item, one by one. I think that filter and map apply their operation sequentially, i.e. the iterable is entirely filtered, and then entirely mapped.
look at my code snippet, it's not the case
what do you mean by 'entirely'?
e.g. after a map the entire iterable is collected, then the next map is applied, i believe that's what they're saying
map is (almost) equivalent to this py def map(fn, iterable): return (fn(x) for x in iterable) and filter to this: ```py
def filter(fn, iterable):
return (x for x in iterable if fn(x))
they don't create intermediate lists if that's what you're asking
I see.
If you want to do this and e.g. test each function separately, do this. Although it's very strange to define functions by assigning a lambda, it's more common to use def.
def or lambda don't matter. What matters is code reusability, and generator functions are more reusable than generators.
That was what I had in mind.
they are functionally the same
def is more syntactic and more readable in my opinion
using builtins is usually the best and clearest bet for general use cases
...for 3 reasons:
- It's harder to refactor a lambda (e.g. split one line into two)
- lambdas are harder to trace through in a traceback (because instead of a proper name they'll have
foo.bar.<locals>.something - lambdas aren't picklable, although it's pretty minor
i don't understand how it's reusable though if its assigned to a lambda in local scope
i have a controversial opinion on this but lambda in Python is a bit of an afterthought (e.g. you can only use one expression), and that reflects how you should prioritize using lambda vs def
that's not at all controversial π
well the fact that lambdas suck lol people disagree with
python's lambdas do suck, and it's unfortunate. that does not change what idiomatic, mainstream python is.
oh yeah i agree
I think guido even has a post wher ehe says there's almost no reason to use a lambda instead of a local def. it's really just for places where the function is trivial and being passed directly to another function
I wish Python had more built-in tools for not writing lambdas. Like operator but better. I think there was a library that let you do X.foo + X.bar, but I doubt it works well with linters/typecheckers
hot take: I think Guido looked at C++ and Java and said "oh, the only reason people complain about not having lambdas here is because they can't define local functions", and that shaped things in python, I don't know if he understood all the cool things that could be done with them, probably because languages that did cool things with lambdas were not mainstream back then
like a compose function?
yeah, I guess
the problem IMHO is that people want special operators for composition, and they want currying, and they want partial, etc etc
and it still doesn't cover everything
whereas if you just have an awesome lambda syntax then you don't really need these other things
yeah functional programmers are bloodthirsty lol
...although this brings me to another point: all these functional things will not work well with IDEs/typecheckers
like compose with varargs, flatmap with varargs, currying etc.
honestly there's so little downside in writing a separate local function to put into the map that IDK why people struggle with obscure one-liners sometimes
that's not really a functional thing, it's more about variadic generics
and you can just have a binary compose
and then it works fine with type checking
IMO compose and currying are pretty fundamental general programming concepts
i'm not sure how currying can be considered a fundamental "general" programming concept
it's just a particular approach/technique, featured in a tiny fraction of overall programming languages
partial application of functions is pretty common, it's just not called currying
that doesn't seem to be making any inroads or convinced anyone outside of very FP languages that its valuable
partial application and currying are not the same
Can you do something like this with variadic generics? ```py
asyncio.pyi
def gather(*coros: Awaitable[X]) -> Awaitable[Tuple[...X]]:
...
yeah you're right
there's a PEP
C++ has variadics
I've done a lot of things with them there... it can get quite.... "fun" π
but it does let you do, in certain specific cases, incredibly useful things that are difficult to write in other languages
yeah currying is a bit meh in Python
I guess that's fair. that said, why would anyone do that.
Currying is probably the absolutely least successful idea to come out of FP
(auto-currying that is)
I guess it could be useful with decorator factories
excited for pattern matching tho!
idk, I have trouble imagining any situation where I'd want to use it.
I get really pissed off when I need to make a parametrized decorator tbh
jesus what are you guys using python for
hm?
i don't use python outside of interviews and basic scripts
i think fix just means that when you write a decorator that also takes arguments, which isn't that rare
you end up with triple nesting
yeah
it's a function returning a function that returns a function
it's quite a headache
beautiful
at that point I think maybe it's easier to write that decorator as a class?
I forget if that helps
nw π
IDK basically just curious what the scope of your python use is
because I have fairly limited range where I use Python and then I'm primarily a Go dev at work
in fairness you are in the advanced channel
so you can't be too surprised to hear that people are doing, well, moderately advanced things with python π
yeah it's understandable i'm just curious in general
#moderately-advanced-discussion
We use python pretty extensively. I work in high frequency trading, the actual strategy and such is all in C++, but there's a mountain of supporting python
ah gotchu
maintaining all kinds of metadata, generating configs for C++ applications, all the deployment stuff, alerting and monitoring, devops stuff, etc etc
and of course a lot of quantitative data analysis and modelling
are you a quant or more of a quant-adjacent SWE then
quant adjacent
I started as a quant, i was recruited after I finished grad school in physics
Oh, I remember what I miss from Haskell. Higher-kinded types and type aliases. Currently, there's nothing you can put in here py T = TypeVar("T") f: ??? = lambda x: x that will mean the same as py T = TypeVar("T") def f(x: T) -> T: return T so we would need something like ```py
T = TypeVar("T")
f: Forall[[T], Callable[[T], T]] = lambda x: x
I tried making a lens library and failed. Because I can't make polymorphic lenses.
and then i just decided I prefer to write code
are you at one of Cit/5rings/2s/Akuna? or something along those lines?
i've been pretty against working in HFT for a while because I like more customer-facing stuff but the work is growing more interesting to me
TL;DR if you have this py @dataclass(frozen=True) class Isomorphism(Generic[A, B]): atob: Callable[[A], B] btoa: Callable[[B], A] You can have these: py swap_int_str: Isomorphism[tuple[int, str], tuple[str, int]] swap_bool_list: Isomorphism[tuple[bool, list], tuple[list, bool]] swap_float_float: Isomorphism[tuple[float, float], tuple[float, float]] ... but you can't express an Isomorphism that works on all of these, in other words ```py
swap: Forall[[A, B], Isomorphism[A, B]]
Hah
Somewhat similar
nice that sounds fun
for me i'm basically torn between my interest in creating consumer-facing (ish) solutions and current disinterest in finance vs. my love of money lol
i might try to give it a run in a couple years to try it out and see if i like the culture/work
Hey @placid perch!
Uh-oh! It looks like your message got zapped by our spam filter. We currently don't allow .txt attachments, so here are some tips to help you travel safely:
β’ If you attempted to send a message longer than 2000 characters, try shortening your message to fit within the character limit or use a pasting service (see below)
β’ If you tried to show someone your code, you can use codeblocks
(run !code-blocks in #bot-commands for more information) or use a pasting service like:
Hey @placid perch!
It looks like you tried to attach a Python file - please use a code-pasting service such as https://paste.pythondiscord.com
yeah i don't have much interest in finance either fwiw
Hey so i need some help,know this isnt the right spot but looked like it
Im working on a project
where im splicing addons from company names
Like LTD and Limited in the uk and other addons in other countries
it works from a database with like 45 thousand company names
i have the basic idea on how to do it but im still looking for help
this isnt a help channel. see #βο½how-to-get-help
sorry
what are polymorphic lenses?
type-theory-discussion
Hi
"lenses" are basically getters and setters except for immutable values. For example:
>>> lens = item(1, attr("comments", item(0, key("posts", iden)))
>>> data = {"posts", [Post(comments=["nice work", "meh", "shared with my boss and he fired me"])]}
>>> lens.get(data)
'meh'
>>> lens.update(data, str.upper)
{'posts', [Post(comments=['nice work', 'MEH', 'shared with my boss and he fired me'])]}
>>> lens.set(data, "[REDACTED]")
{'posts', [Post(comments=['nice work', '[REDACTED]', 'shared with my boss and he fired me'])]}
A simple lens type looks something like this: Lens[S, A]. S is the overall structure type (here it's dict[str, list[Post]]), and A is the type of the element (in this case str because we're looking at/changing individual comments).
You could implement a lens like this:
@dataclass
class Lens(Generic[S, A]):
getter: Callable[[S], A]
setter: Callable[[S, A], A]
Then, for example, you could do this: ```py
@dataclass
class Post:
comments: list[str]
first_comment: Lens[Post, Optional[str]] = Lens(
lambda post: post.comments[0],
lambda post, new_comment: Post(([] if new_comment is None else[new_comment]) + post.comments[1:])
)
looks simple enough
how different is this from a property?
So the issue is: you can't typehint a lens that will get/set the first element of any tuple.
Properties are mutating the object. Sometimes you want to/have to work with immutable values.
(or, well, immutable by convention)
you could use a property that returns a new object
or a set-once property
i'm not sure i understand the question about types though
Something like this is illegal: ```py
first_element: Lens[tuple[A, B], A] = Lens(lambda tup: tup[0], lambda tup, first: (first, tup[1]))
Sure, but lenses work like setters as well
and, well, I can't make a property for all the possible use cases
especially if the object isn't under my control (like... a dict or a tuple)
My use case was a graphics library. In it I have to use immutable values because otherwise the multithreading will break. (basically it's a feature)
In the library, you create complex scenes by manipulating nested objects. Like, a pair of (a triangle, and a group with (a rectangle, a circle, a circle, a LaTeX).
So if you want to alter a deeply nested element, you have to really go out of your way. Say, you want to make the circle 3 times bigger. ```py
new_pair = Pair(pair[0], Group(pair[1].elements[:2] + [pair[1].elements[2].map_radius(3 .mul)] + pair[1].elements[3:]))
But with lenses it would be: ```py
new_pair = (first >> index(2) >> radius).change(pair, 3 .__mul___)
``` and you don't even need weird methods like `map_radius`
not even dict.something = property(lambda self: β¦)?
i stand by my remark. it looks overly complicated
it works well in reanimate, an animation library for Haskell
how else would you change a deeply nested structure in my case?
deeply nested.. ugh.. i'd probably try with a visitor or composition pattern
one sec
yea. idk why i thought it would. time to get some sleep
oh, I think I remember one thing
well, i don't know enough about your case to give you a good example, but to illustrate you can either go like ```python
class Geometry:
def init(self, children):
self.children = children # subclasses of Geometry
def mutate(self):
for c in self.children: c.mutate()
or you have the recursive structure fed into an external function which will operate on the tree of objects
https://decorator-factory.github.io/lanim if you want to read the code... it's not very pretty
I don't want to make the library user create a class every time they want to modify a pair
I think I don't completely understand your proposal
then the visitor pattern is probably better suited, which operates on the existing objects, recursively
I mean, preferably this operation should be one expression
I guess I could do pair.map_second(lambda group: group.map_index(2, lambda circle: circle.map_radius(3. __mul___)))
immutables.Map has this thing where you can do something like py my_map: Map[str, int] # immutable HAMT with something(my_map) as mm: mm["key"] = 42 mm["other_key"] = 24 for key in ("foo", "bar", "baz"): mm[key] += 1 print(mm.value) # new immutable value, with the modifications So I could do this: ```py
with mutate(pair) as mm:
mm.second.at_index(2).radius *= 2
hmm.. that does look nicer. but i'm not sure why your underlying lib doesn't support stuff like that?
@verbal escarp This? it looks horrible...
like, it would be pair.group[2].radius *= 2 in imperative code
i'd prefer .attributes over [] indexing
Only time I tried lenses was in Kotlin. They seem to work well enough.
I just think python is a strange language to try to make the whole thing work in.
Trying to do immutability in python is swim so hard against the current
if you're talking about the with statement, it wouldn't play well with types because e.g. Pair and Group are generic. Also, you can't "recursively" map a type, e.g. convert Group[Pair[Rect, Triangle]] into MutGroup[MutPair[MutRect, MutTriangle]] and back
I mean, at the type level
i disagree. it strongly depends on the context, imo
my overall conclusion though was that languages should provide a first class solution to this thing if they care about immutability
i mean, the way the current is going is just factual, I'm sorry.
All the built in data structures are mutable, python has very poor support for expression-oriented programming; you constantly need to create things and mutate them.
(poor lambdas are part of this)
In my case, it's not just my personal quirk (although I have a crush on immutability), it's just the way my architecture works to allow multithreading
tuples.
tuple isn't really a data structure, but, sure, ok
that's a quibble and I'm sure you know it
list, dict, set, all mutable
idiomatic python uses the built in data structures, that's just fact π€·ββοΈ
you can do a lot with tuples and namedtuples
but not everything
they're still not really data structures, they are more like pared down versions of data classes
a namedtuple is basically a dataclass
I think it's funny that CPython has a HAMT but in Python land it has to come from a library
anyhow, it's silly to argue that doing immutable stuff in python isn't going heavily against the grain. That's a separate discussion from whether or not it's worth it, but it clearly is against the grain.
I am not arguing that it isn't against the grain π
Even in languages like Kotlin which overall have faaaaar better support for this stuff, it's still against the grain, but not as much
not you π
me
you π
no u
π
I think I can do this in TypeScript π³ time to port
if you add a cookie in you just get your own cookie jar!
well, i'm arguing that it's up to your functions to not mutate in place but built new objects
functions not mutating their arguments is not the same as immutability
!e speaking of... one of my favourite WTFs in python
xs = ([],)
try:
xs[0] += [1]
except TypeError as e:
print(repr(e))
# damn this is a bad error. at least my application is in a consistent state
print(xs)
@grave jolt :white_check_mark: Your eval job has completed with return code 0.
001 | TypeError("'tuple' object does not support item assignment")
002 | ([1],)
yeah this has come up in here like dozens of times π
well, it's up to you to not eat the cake on the table :p
xs
your haskell is showing
yeah xs is 1 shorter than lst
π
I also took on the terrible habit of naming variables after their respective typevars. It's like... higher-order Hungarian notation
ints, strs, intlists, listlists
wasn't that abandoned.. in like.. the 80s?
I'm a retro guy
like, I could name Sequence[T] as ts if I'm super lazy and the function is very general
iirc there even was a memo in microsoft that explicitely forbid that practice
yeah I'm not a fan of the normal Hungarian notation
So in kotlin you have dataclasses, and you can set each individual property as val/var, basically whether that property can be reseated or not. THe issue is that if you make everything val, then you have this nested issue that lenses help with. if you make it var then things are nice but anybody can mutate your data class at any time. There's no protection even if you pass your data class into a function that it won't be mutated. So with a lens library and a bit more stuff I came up with this:
@optics data class Frob(val bar: Bar)
@optics data class Bar(val justBaz: Baz, val listBaz: FrozenList<Baz>, val mapBaz: FrozenMap<String, Baz>)
@optics data class Baz(val int: Int, val string: String)
var y = Frob(
Bar(
Baz(8, "17"), immutableListOf(Baz(5, "hello")), immutableMapOf("hello" to Baz(8, "there"))
)
)
y %= Frob.bar.listBaz { it + Baz(7, "goodbye") }
so you can see the better lambdas help., but IMHO it's still kinda awkward overall.
I use %= because in Kotlin, if you don't provide %= then y %= ... becomes y = y % .... π
a bit of a hack but I wanted to avoid repeating the immutable variable being "modified"
I still think that a fairly normal language (as opposed to hardcore FP languages) like Kotlin, Swift, etc could definitely do a better job supporting "immutable by default" without creating too much of a headache.
They are talking about it for the next Java I believe.
some kind of immutable data class type thing, believe it's called "value classes" but I could be wrong
can't you make dataclasses immutable?
You can, it's just that there's no syntactic sugar for working with them
In Haskell (GHC) there's an extension for everything that lets you do this: thing { foo = "bar" } (where thing is a record) which means: "all fields from thing except with foo being "bar"". Which would turn this [see reply] into
pair {second: pair.second {circle: pair.circle {r: pair.circle.r * 3}} }}
``` still not great though.
There's `dataclasses.replace` but it's untypable
well, there is a bit, but not much
hmm
the problem is basically once you have nested, immutable dataclasses
it's a disaster
nested is always hard
Right, so lenses exist largely to solve that problem
Frob.bar.listBaz above is a lens
...I guess I just have to wait for pyright to get a plugin system
...or maybe fork it π³ which I was planning to do, but I looked at the code and acquired existential dread
in this particular case, Frob.bar.listBaz is a function. That function takes a Frob, and it takes a lambda, the lambda needs to map from the type of the member (Frob.bar.listBaz, so FrozenList<Baz>) to that same type.
...that would be the giga chad python tool though
When the function is called, it gives you back a new Frob, that has had that nested member replaced, by calling the lambda on the old member and taking the result, and putting the result where that old member used to be
ok
But this is all a lot of ceremony, it can't really be done efficiently or maybe at all in-language so we have those annotations (@ in Kotlin) to do codegen to provide all this machinery
why is called "lense"?
...I know that erictraut wants there to be a standardized plugin system so that everyone can benefit. But it's so tempting.
it's also not very efficient or easy to optimize
because the lens focuses on a member of the class
and you compose lenses
to focus further and further in
In this case I'm actually composing two lenses effectively
@neat thunder #user-interfaces
there's a first lens that maps a Frob to a new Frob given a function that replaces the bar member
i see
and there's a second lens that maps a Bar to a new Bar given a function that maps the listBaz to a new listBaz
if you combine those two lens you get a new, "more powerful" lens that can map Frob to Frob by replacing the nested bar.listBaz member
there's a 2h lecture by Edward Kmett (creator of the lens Haskell package) if you're brave enough... I'm not, last time I gave up at 27:20 https://www.youtube.com/watch?v=cefnmjtAolY
i found nested <anything> is not really nice to work with in python, we should import more tools for those kinds of jobs
it's a fine idea but I think it's an important enough problem, if you really want to encourage immutability, that you should use language design real estate on it
well, if you do mutate then nested stuff is pretty nice to work on π
x.y.z = 5
x.y.z.append(10)
etc
*flashbacks to dotted trainwrecks when I tried to untangle endpoints that used a completely unrelated class stored in the aiohttp app parameters*
not even then. just thinking of xml parsed into 9 levels of dict-hell
I mean the language can't protect you from the basic complexity of your domain
In python, you can use something like pydantic, declare nested schemas, it will auto parse from json/xml into your dataclasses
verify/convert any dated in a recursive way
etc
this is about all the help you can really hope the language will give you
there has to be a better way :p
a cross and a little bit of holy water would suffice
but, there definitely is a lot of incidental complexity when it comes to changing nested, immutable stuff
so that could "easily" be fixed, i.e. you can imagine language features addressing this relatively straightforwardly
and an old priest and a young priest π
!d debug
__debug__```
This constant is true if Python was not started with an [`-O`](https://docs.python.org/3/using/cmdline.html#cmdoption-O) option. See also the [`assert`](https://docs.python.org/3/reference/simple_stmts.html#assert) statement.
why is this not used more often? I never have seen this in use except for checking the documentation
most of the time you don't run python with -O, and if you do most of the things you want to do with this you can do with assert
well yeah
but you wouldn't want to run the assert statements every time the code is ran, eh?
assert will also be skipped under -O
o
I tend to use it to setup logging, but pycharm is also annoying there where it pretends an if with it is dead code and will stop code inspection
It definitely could be used more as I've seen some weird solutions to determining if it's a debug environment, but maybe it's both not known that much and people don't want the other effects turning on the flag will do
isn't docstring elimination on -OO
It is
It's also pretty nice, I had unexpectedly large size improvements when distributing with the flag
do you have the docs to the flag?
!d -O
-O```
Remove assert statements and any code conditional on the value of [`__debug__`](https://docs.python.org/3/library/constants.html#debug__ "__debug__"). Augment the filename for compiled ([bytecode](https://docs.python.org/3/glossary.html#term-bytecode)) files by adding `.opt-1` before the `.pyc` extension (see [**PEP 488**](https://www.python.org/dev/peps/pep-0488)). See also [`PYTHONOPTIMIZE`](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONOPTIMIZE).
Changed in version 3.5: Modify `.pyc` filenames according to [**PEP 488**](https://www.python.org/dev/peps/pep-0488).
anyone down to code jam real fast?
@verbal escarp since you're a package management psychonaut now, have you seen this? https://pnpm.io/ could be interesting inspiration for justuse 2.0 π
Files inside
node_modulesare linked from a single content-addressable storage
i still want ipfs package distribution but that's another story
Thoughts on the proposed removal of the GIL?
i'm a what? π
funny, i was just contemplating about using IPFS or something like that in justuse
i made a simple game in a file and my main program is in different file
so i wanted that like when user gives input for game the main program should read from that game file and if not then it would leave that as it is
so how can i do that?
but it's gotten a bit more complex because we want to compile our dependencies into a single .py file for drop-in installation, so we can't really use non-pure python dependencies i guess
that sounds like a question for a help channel, but nevertheless - __main__.py is actually called first when you call something from the command line, so you can import different modules depending on the commandline arguments
although i'm not 100% sure that answers your question
somewhere between "meh" and "awesome, about time!"
i don't really care about the GIL on a daily basis, not sure how much it would impact my workflow, if at all
it may have an impact on how to approach parallelism and other naturally async problems
i'm wondering if our async protocol might make use of it somehow
if we're not constrained to run an event loop in the background anymore, maybe async could delegate transparently to threads in the future in some cases
(one of the reasons i find the idea of protocols awesome - free abstractions!)
Hey π guys just a question, it is possible to run Python from 2 different computers? I started to code on my desktop but when I move I would like to continue to code π¨βπ» on my laptop but I have to download and install all libraries and dependencies.. there is a smart way to have all-in-one??
hmm.. either you put your code and editor settings etc. in dropbox or some other cloud which will sync everything (which is what i do) or you can run a web-based IDE like pythonanywhere, vscode etc
you could also use docker to simplify your execution workflow
or pipenv to lock dependencies and stuff
s/pipenv/poetry
s/s\/pipenv\/poetry/
Not sure who was there yesterday for the conversation between map/filter vs generators but I've just jotted down a few lines to assess if there's a performance difference: https://goonlinetools.com/snapshot/code/#ssm1dv65tsofi0hxwu47w.
I do observe a slight difference (same memory usage but better speed for the functions using generators) but I am not sure this is outside of the error margin.
On Dropbox u can sync the scripts but no the libraries
Use git with a lock file like a normal bean?
What do y mean? Can y explain please
hu?
you mean the site-packages? you could copy that dir and add it to your PYTHONPATH