#internals-and-peps
1 messages · Page 84 of 1
all in all, very interesting
I can see this being used for some esoteric fun-ness
hey guys i am pretty good at python like arrays a nd stuff and i can do basic regressions can someone give me a plan path on how ot learn machine learning( i know linear algebra and calculus
hey guys i am pretty good at python like arrays a nd stuff and i can do basic regressions can someone give me a plan path on how ot learn machine learning( i know linear algebra and calculus
@spring jackal this is a channel for language discussion; try #data-science-and-ml or #career-advice.
oh okay thanks i just wanted some advice
that's the displayed return value
@gleaming rover ooh, oops.
The PEP seems to say it's not guaranteed that it won't be called with the class as an argument
Hey There! Currently I am making a Tic Tac Toe game using python's GUI(Graphical User Interface) i.e. Tkinter . Now I have made the game but, i wanted to add an entry login system to the game.I want to add it in such a way that the Entry Login window appears first and after providing the name input the game window shall appear. Here's the link of my Game(https://repl.it/@AdvaitJadhav28/TicTacToe-BETA#main.py) and here's the link of my Entry login system(https://repl.it/@AdvaitJadhav28/EntryLogin#main.py) P.S.:- Help me out ASAP . Before providing the solution first check whether it works. You can give me a GitHub link to access the solution.
Hey see #❓|how-to-get-help
Do you think += shouldn't have been designed to work as extend on lists?
i.e.
xs = [1, 2, 3]
ys = xs
xs += [4, 5]
print(xs, ys) # [1, 2, 3, 4, 5] [1, 2, 3]
``` instead of ```py
...
print(xs, ys) # [1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
@wide shuttle :white_check_mark: Your eval job has completed with return code 0.
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
There's a no-op assignment in addition to that, xs = xs, if you use +=, but it does use extend to do its work
oh
You meant it the other way around
Personally, I think it would make more sense to not use extend there, as what += should do is create a whole new list and set it to the variable there, not adjust the original.
I don't really see a scenario where this would be a huge problem if it made a new list rather than editing the original, although there probably is a reason behind using extend
It's the definition of __iadd__, though
Try to do it in place
The way it currently works to support implementation it with immutables is do an assignment with the return value of __iadd__ and have the convention that __iadd__ always returns self for mutable objects.
i.e., with this change, you'd get the "copy on iadd" behavior:
!e
class List(list):
def __iadd__(self, other):
return self + other
a = List([1, 2, 3])
b = a
a += [4, 5]
print(a, b)
@wide shuttle :white_check_mark: Your eval job has completed with return code 0.
[1, 2, 3, 4, 5] [1, 2, 3]
You meant it the other way around
Yep
reaches out to grab ctypes and patch the list type
>>> @patch(list, '__iadd__')
... def list_iadd(self, other):
... return self + other
...
>>> x = []
>>> y = x
>>> x += [1,2,3]
>>> x
[1, 2, 3]
>>> y
[]
>>> ``` @grave jolt so you think it should work like this?
yep
it seems a bit counterintuitive to me that xs += ys is not the same as xs = xs + ys
why do augmented assignments even have their own dunder methods?
wouldn't it be better to just make xs += ys a shorthand for xs = xs + ys?
you can imagine it like x += y does x = (type(x).__iadd__ or type(x).__add__)(x, y) it does the assignment at the end regardless of which dunder was called
which is why this works```py
x = ([],)
x[0] += [1,2,3]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
x
([1, 2, 3],)
calling the dunder succeeds, but the assignment fails
to be super specific, the INPLACE_ADD opcode succeeds, but the STORE_SUBSCR fails
More on how it roughly works (if it didn't change since then) can be found here https://www.python.org/dev/peps/pep-0203/#proposed-semantics, the operator does stuff and then returns a reference to an object
Hi, is it me or does !docs list.insert not work?
https://docs.python.org/3/tutorial/datastructures.html
It does not work, but we can probably discuss that in #community-meta
y, just wanted to move my message, realied too late
Does "Standards Track" on a PEP mean that it's accepted and will be actioned?
- A Standards Track PEP describes a new feature or implementation for Python. It may also describe an interoperability standard that will be supported outside the standard library for current Python versions before a subsequent PEP adds standard library support in a future version.
gotcha
Can i talk about software architecture here?
this is more for discussion about python itself
@bronze acorn you can talk about software architecture as it pertains to Python
I assume that's how one should structure a code base?
AFAIK, uml design is part of any software architecture, right?
@bronze acorn I've never known someone to make a uml diagram for a python program, but I've also never worked in industry
I've only made diagrams when they were required for homework and I find them to be a confusing way to conceptualize code. Especially ER diagrams for database design.
Idk one of our devs is strong advocate for ER diagram
And I suppose they make sense for complex DBs with many relations
We have some 140 tables that might grow to 150+ with some refactor and i must say, something like relation diagram can help s lot with db design
@oblique crystal how are you going to have a diagram with 150 tables that's easier to make and read than any other way of learning how the database works?
Again, I have no industry experience so take everything I say with a lamp sized rock of salt, but that sounds really complicated.
Different people find different ways of viewing things easier/harder I find
I had one colleague who could do it all in his head, but I need to see stuff diagrammed out a lot of the time to fully get the flow of things
I mean, that's his opinion, I wasn't advocate for it. But then it can really help, if you have many many-to-many relations and etc in DB. Imagine how you on-board new devs @boreal umbra
Like we had an old pipeline in snakemake that I had to generate the DAG for to fully wrap my head around
Whatever works for you I think
He was actually recently on boarded and it was not easy
We should probably continue this in #databases
Unless we can get back into Python territory
I actually have an unrelated python Q I was just considering. What is an actual use-case for the start parameter in sum?
You can use it for example to flatten nested lists
overall, when adding non-numeric things
Can you give an example?
There aren't that many cases where you do use it as there generally are better ways, but it could come in handy with custom types
sum([[1,2,3,],[3,5,5]],[])
Hmm I see. How efficient is that for flattening?
Not very, it's quadratic with iterables
In [7]: timeit chain.from_iterable([[1,2,3]]*10000)
38.6 µs ± 137 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [8]: timeit sum([[1,2,3]]*10000, start=[])
301 ms ± 2.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
For flatten I usually just do list comp
It works with add so new objects are being created at every step
Oh yeah I just found this on SO:
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' '[item for sublist in t for item in sublist]'
10000 loops, best of 3: 143 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'sum(t, [])'
1000 loops, best of 3: 969 usec per loop
$ python -mtimeit -s't=[[1,2,3],[4,5,6], [7], [8,9]]*99' 'reduce(lambda x,y: x+y,t)'
1000 loops, best of 3: 1.1 msec per loop
Looks like it's sloooowwwww
@safe hedge sum is just reduce for the plus operator, but you have to specify the starting point. I use it to combine a bunch of counters.
I'd never really thought of using it for more complex objects tbh
I don't ever combine many of those
Makes sense though I guess
Hmm I see. How efficient is that for flattening?
@safe hedge it’s basically the same as for strings (don’t do it)
You can't do it for strings...
sum errors if you give it strings
Even if you pass start=''
You can't do it for strings...
@safe hedge yes, because it’s O(n^2)
so there’s a special case check to prevent you from doing that.
but not for lists, even though you shouldn’t for exactly the same reason
which is why I said it’s the same as for strings (in terms of time complexity of iterative concatenation)
I get you now
👋
Ooo. That could be nice, though isn’t the real use case for lambdas the simplicity of them being short (except for #esoteric-python
)?
@spark parcel well, lambdas play different roles in different languages (since we're mentioning making a new language). I wouldn't say that anonymous functions should be universally avoided. For instance, in JS you could write something like this usingPromises:
const foo = () =>
fetch("https://something.com/", {"method": "GET"})
.then(someResponse => someResponse.json())
.then(({x, y}) => {
const z = x*x + y*y;
return x === "42"
? fetch(`https://foo.bar/${x}/${y}/${z}`)
: fetch(`https://foo.bar/${y}/${z}`);
})
.then(fooBarStats => fooBarStats.json())
.then(({foo, bar}) => ({foo, bar}));
... or you could rewrite this with async/await:
const foo = async () => {
const someResponse = await fetch("https://something.com/", {"method": "GET"});
const {x, y} = await response.json();
const z = x*x + y*y;
const fooBarStats =
x === "42"
? await fetch(`https://foo.bar/${x}/${y}/${z}`)
: await fetch(`https://foo.bar/${y}/${z}`);
const {foo, bar} = await fooBarStats.json();
return {foo, bar};
};
the basic idea is the same, but the first one uses lambdas, and the second one does not -- and I don't think it would really be appropriate to name any of the lambdas
The lambdas you’re referring to, are they the arrow functions?
yes
The lambdas you’re referring to, are they the arrow functions?
@spark parcel which are pretty 🙂 unlikelambda🤢
In JS, that seems to make total sense. However, I feel like python code is written differently, where multi line lambdas like that won’t be very useful. That may be a lack of using anonymous functions on my side. Maybe that’s a good thing or maybe is a bad thing. I’m not sure
In JS, they are very nice and useful
unless you use something like RxPy
@gleaming rover by 'lambda' I mean a function-as-a-value in general, not necessarily Python's idea of lambdas
I don't think there's a need for multiline anonymous functions
@gleaming rover by 'lambda' I mean a function-as-a-value in general, not necessarily Python's idea of lambdas
@grave jolt can you elaborate on that
didn't really get it
the only real usage I can think of is GUI stuff, and you can dot that with decorators
def setup(self):
button = self.add(Button())
@button
def onclick(ev): print('hello world')
@gleaming rover I used the word "lambda" in my message as a synonym for an anonymous function, maybe that was confusing
@gleaming rover I used the word "lambda" in my message as a synonym for an anonymous function, maybe that was confusing
@grave jolt isn't...that what it is?
😕
oh
@spark parcel which are pretty 🙂 unlike
lambda🤢
@gleaming rover I meantlambdain the sense of Python's lambda syntax
yes, I understand
Ah, yeah. That’s why you put code blocks there
but yeah I have always understood "lambda (function)" and "anonymous function" to be synonymous
When would you want to use a lambda, other than quick functions for things like map? I can’t see how multi line ones would be useful in python. If you have such a long function, maybe consider naming it
I'm not saying they would be very useful in Python
I’m mostly wondering if they would have any application
python doesn't really have a place for them, but they're great in languages with more functional characteristics and things like pattern matching
I’m mostly wondering if they would have any application
@spark parcel RxPy is the only thing I can think of, because it basically follows the above pattern (but does anyone even use RxPy?)
event handlers for GUIs would be a usecase for multiline lambdas
Didn't find any need for that when making gui apps
for example, you may want to set some text in 3 places, which is 3 lines. You can do it with decorators as well, so its not really a need, but there are cases where the name of the decorated function just seems meaningless
Hmm, I can see where you’re coming from. They may not justify a whole separate function yet aren’t a single line
I haven’t even heard of RxPy
@spark parcel it's basically like the above JS example with.thenand.catchbut on steroids
Ohh hahah
so something like
button = Button()
button.on_click(
lambda: (
self.a.set_text("a"),
self.b.set_text("b"),
self.c.set_text("c"),
)
)
```?
Wouldn’t it just be cleaner to allow code to be passed directly, using something like curly braces
button = Button()
button.on_click({
self.a.set_text("a")
self.b.set_text("b")
self.c.set_text("c")
})
)
Wouldn’t it just be cleaner to allow code to be passed directly, using something like curly braces
@spark parcel isn't that basically alambda
with no parameters
yeah, a 0-argument lambda is basically that
also that would be a set
Oh. How silly of me
Let’s get rid of sets and make people use set() to create them hahah
Wouldn’t it just be cleaner to allow code to be passed directly, using something like curly braces
smalltalk does that 🙂 (you don't need to add anything else if it takes 0 arguments)
Well if python had braces and semicolons, that'd be one of the few nice uses for them I can think of
Yep. That’s true
!e
from dis import dis
def chained_compare(n): return 5 < n < 6
print(dis(chained_compare))
@boreal umbra :white_check_mark: Your eval job has completed with return code 0.
001 | 2 0 LOAD_CONST 1 (5)
002 | 2 LOAD_FAST 0 (n)
003 | 4 DUP_TOP
004 | 6 ROT_THREE
005 | 8 COMPARE_OP 0 (<)
006 | 10 JUMP_IF_FALSE_OR_POP 18
007 | 12 LOAD_CONST 2 (6)
008 | 14 COMPARE_OP 0 (<)
009 | 16 RETURN_VALUE
010 | >> 18 ROT_TWO
011 | 20 POP_TOP
... (truncated - too many lines)
Full output: https://paste.pythondiscord.com/vikaguheke.txt
looks like a < b < c gets evaluated similarly to a < b and b < c but with whatever JUMP_IF_FALSE_OR_POP means as an alternative to short circuiting.
It does the same as the and but only evaluates the common expr of the conditions once
@peak spoke what do you mean by that?
in the chained form each of the expressions of the comparison is only evaluated once to get its value, but with the and b will be evaluated both for the first comparison and then for the second on if it didn't short circuit
print_ = __import__("functools").partial(print, end=" ")
print_("chained")
(1, print_(1)) < (2, print_(2)) < (3, print_(3))
print()
print_("and-ed")
(1, print_(1)) < (2, print_(2)) and (2, print_(2)) < (3, print_(3))
###
chained 1 2 3
and-ed 1 2 2 3
You are not allowed to use that command here. Please use the #bot-commands channel instead.
The bad effects of that can of course be avoided with assignment to a name that'd then be used in the comparisons at a negligible cost (unless you have some weird logic where the order they were evaluated in matters)
maybe easier to read version of the same example:
In [1]: def p(val):
...: print(val)
...: return val
...:
In [2]: p(1) < p(2) < p(3)
1
2
3
Out[2]: True
In [3]: p(1) < p(2) and p(2) < p(3)
1
2
2
3
Out[3]: True
I need someone to explain this pep https://www.python.org/dev/peps/pep-0593/
I don't get it
Does it allow like value range checks or something?
So I guess like value checking on top of type checking?
It basically adds metadata to a type, allowing for use-cases in static analysis/runtime checks
But like for what end
one suggested use case of it is x: Annotated[int, const] = 42 to indicate that x is an int that cannot be bound to another value, where the compiler would enforce that.
that suggestion was on a thread on python-ideas today.
Was that in the pattern matching thread?
Last time I looked at it people were trying to talk about adding constants
yeah.
because of how pattern matching works on constants.
the weirdness about whether it checks for equality to the constant, or assigns to the constant.
I haven't kept up with that PEP, but this chunk of the original PEP: https://www.python.org/dev/peps/pep-0622/#constant-value-patterns
Is isinstance not blocked on typing anymore?
Last type I tried to a List[int] in an isinstance it yelled at me
what do you expect that to do?
isinstance([1], List[int])
That would be true for checking it's a list and then I'd have to do a second to check content of list but I'm pretty sure u can't use isinstance on stuff from typing
So in 3.9 you can do it
I don't believe isinstance supports generic checks.
Since it's at a big runtime cost.
I thought they decided that you can't use isinstance like that because you could make a subclass of list where iterating over it has effects
and then you'd silently get unexpected behavior
!e
stuff = [1, 2, 3, 4]
result = isinstance(stuff, list[int])
print(result)
@boreal umbra :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 2, in <module>
003 | TypeError: 'type' object is not subscriptable
Also, most people don't expect instancechecks to be O(N).
huh, I thought snekbox was on 3.9
I wouldn't expect isinstance to do more than a simple type check in any case
are there any reactive libraries that allow me to make x=y (and x always updates to the current value of y)
@rose stream well, if x points to the same object as y, that won't be an issue
were you going to use immutable types?
Sweet, what library allows this
the language itself
I see
the solution that python offers will be a start though! - do you mind sharing?
@rose stream well, it's just a fundamental of the language. If you have two variables that point to the same mutable object, then they're pointing to the same mutable object
!e
a = [1, 2, 3, 4]
b = a
b.append(5)
print(a)
@boreal umbra :white_check_mark: Your eval job has completed with return code 0.
[1, 2, 3, 4, 5]
there are simple workarounds to emulate pointer-like behavior for types like int and str
class Ref:
def __init__(self, obj):
self.obj = obj
def get(self):
return self.obj
def set(self, obj):
self.obj = obj
this might be considered bad form, but it's putting a mutable wrapper around an object that can be immutable.
(it's bad form btw)
No one reads my code, i'm just out here for solutions, I'll give that a shot
as long as you have a reference to the Ref instance, the obj attribute will always be whatever you've set it to.
that's true of any attribute of any object. You could just as easily do:
class Ref:
pass
r = Ref()
r.obj = 42
Sweet, then this is a big win, thanks guys
And when I did look into reactive programming with python, in led me to things like rxpy
Use the __invert__ dunder for getting and the __imul__ dunder for setting and you've got almost the right syntax:
r = Ref(obj)
print(~r)
r*=newobj
You might be able to use __iter__ to override *r but that's only valid in some places
Sweet, i'll look into it
Miss me with that C code.
psh, C's a great language. 🙂
@raven ridge I was talking to one of my professors today. He's in his late 60s. He was saying that he hopes the CS department will start offering separate degrees for the different topics you can pursue with electives, in part so that data scientists don't have to learn system programming
And I'm pretty on board with that.
I'm generally on board with that, too. Software is definitely a wide enough field at this point that the fact that there's only 2 or 3 majors for it is weird.
At my uni, you can get a computer science degree, or you can get not that.
You can get a "concentration" in data science, cyber security, or software engineering if you want, but that requires your major to be CS
I guess you can get an IS degree, but again speaking in terms of my uni, there's only two programming classes, unless you count the excel class, and the rest is about business.
Computer Science, Software Engineering, and sometimes Computer Engineering...
but yeah, depends a lot on the school.
even though we can draw a distinction between CS and SE, I think some institutions pick one of the two names somewhat arbitrarily and teach whatever blend of CS theory and software design stuff they feel like.
I'm doing this with an n=2 sample of me and a former coworker of mine who was getting a SE degree online.
let's jump over to an OT channel - ot2!
wow, out-moderated by a helper
so I'm trying to figure out how to use dataclasses, however I've got classes that construct dicts with the attributes in the class
field(default_factory={the dict}) is throwing a TypeError and I can't use a lambda in this situation
am I going to have to pass it to a global constructor or am I missing something?
I don't quite get what you are trying to do. The default_factory would take any callable and call it with 0 arguments on every initalization. Maybe TypeError was caused because you passed a callable that requires more than 0 arguments?
@dataclass
class Item:
name: str = None
item_type: str = None
item_template: Dict = field(default_factory={"Name": name, "Item_type": item_type})
``` So this doesn't work because there's 1+ argument?
{"Name": name, "Item_type": intem_type} is not a callable is it?
def get_default_item_template():
return {"Name": name, "Item_type": item_type}
@dataclass
class Item:
name: str = None
item_type: str = None
item_template: Dict = field(default_factory=get_default_item_template)
If your item_template reflects the other values of the dataclass (should they stay in sync?), why don't you add a property that returns it on the fly?
I assume that name and intem_type have to refer to the actual values in the current instance of the class
But then that has the issue of name and item_type not being defined
As @wide shuttle says
Even if they shouldn't stay in sync (i.e. they're intended as some sort of cache of the original values) I would maybe use a functools.cached_property which you call once in an __post_init__
You need to initalize it on the __post_init__.
Or just set it as an attribute in the __post_init__ I guess?
If you want it to reflect the initial values, __post_init__ sounds like the good spot
what's a __post_init__?
If you want it to reflect the current values of self.name and self.item_type, a property would do nicely I think
It's a method on dataclasses which is used to do stuff after the __init__
Since that is normally auto-generated. So you can use it to do stuff you might do in an __init__ normally
so I'd redefine it to form the dict?
This all depends on whether you care if self.item_template changes if/when the other class attributes change
oh ok so make sure the var doesn't init, and the post init creates it after the rest of the values?
no ya the values aren't changing
If you want it to basically just be a dict repr of those two attrs at any given moment then use a property
If it should maintain it's starting values even if the other attrs change then use __post_init__
perfects thanks that works
Just consider the different approaches:
from dataclasses import dataclass
@dataclass
class Item:
name: str = None
item_type: str = None
def __post_init__(self):
self.item_template_attr = {'Name': self.name, 'Item_type': self.item_type}
@property
def item_template_prop(self):
return {'Name': self.name, 'Item_type': self.item_type}
myitem = Item('Dagger', 'Weapon')
print(myitem.item_template_attr)
print(myitem.item_template_prop)
myitem.name = 'AwesomeDagger'
print(myitem.item_template_attr)
print(myitem.item_template_prop)
...
001 | {'Name': 'Dagger', 'Item_type': 'Weapon'}
002 | {'Name': 'Dagger', 'Item_type': 'Weapon'}
003 | {'Name': 'Dagger', 'Item_type': 'Weapon'}
004 | {'Name': 'AwesomeDagger', 'Item_type': 'Weapon'}
I've actually got a couple of usages of properties already for my inventory/stats display
@property
def armour_list(self) -> List[Optional[ArmourType]]:
return [getattr(self.Armour, attribute) for attribute in self.armour_slots]```
but the items aren't mutating so I'm assuming I won't run into any troubles using __post_init__
is that something that's specific to dataclasses?
__post_init__?
AFAIK the implementation is unique to the dataclasses library in the stdlib
As in, a normal class would not have an __post_init__ method called automagically after its __init__
ah ok ya I can see why, there'd be no point
There probably wouldn't be any point in having it by default
But I have written base classes who's __init__ called some other method. Where the intention was that you wouldn't override the __init__ in a subclass but just put stuff in that other method.
that's what I mean, you can call other methods in the __init__, there's no need for a post init
Well dataclasses just call __post_init__ from the generated __init__ I think
So if you actually define __init__ yourself on the dataclass, __post_init__ won't be automagically called
that's what I meant earlier when I said I wasn't using dataclasses correctly, I was redefining the __init__ and treating it like a regular class
I think the default implementation of __init__ calls __post_init__ at the end. Edit: yes, the generated __init__ does call __post_init__.
also are there any mutable containers similar to namedtuple?
You might want to check out attrs, very similiar to dataclasses
but I don't quite like it, it feels a bit over abstracted since dataclasses is more than enough for me
I'll take a look at it but it seems a bit much ya
idk I've only got like 10ish lines per dataclass, I'm mostly just using them to assign predetermined values to objects
well, it's better than repeating yourself on both the parameter declarations of __init__ and the assignments in the body self.<field> = <value>
true but I think to an extent that can help with readability
yeah, kinda depends on the general structure. Sometimes typing stuff when the other parts of the same code base is untyped feels weird and also causes some changes in the core.
if your class is mostly reasoning about holding data, I think attrs and dataclasses were made for just that
I hope one day to be skilled enough to actually understand what's going on here
that's the dream
also cluegen in the same vain as dataclasses and attrs
maybe not the best place to ask, but im curious
when you're trying to read a file, as you read the file, your "position" in the file will be saved. how does python get back to this position without reading the entire file?
Python goes through the OS, which will work with the cursor of the file
oh alright
i read that in a filesystem's file description table, the position of an opened file is saved, so i imagine that's where it's reading from
at least on Unix
Hello gentlemen, ladies.
I am attempting to create two lists from one map operating on two iterables:
zip(*map(lambda item_a, item_b: (item_a.operation(), item_b.operation()), iterable_a, iterable_b))
What I obtain is two tuples. I am looking to produce two lists without casts.
so the output you want is [iterable_a_items], [iterable_b_items]? @unkempt rock
Indeed, @pliant tusk.
(You're going to suggest list comprehensions, I can feel it.)
then ```py
iterable_items = [[i.operation() for i in iterable] for iterable in [iterable_a, iterable_b]]
Right. I performed that (first option) and I think it's quite elegant, readable but I am trying to keep to map, filter, and other functional approaches, without list comprehensions (exercise).
(the operation's not the same on "a" and "b", so your previous code was fine)
I think the unpacking operator (*) returns just tuples, so yes "zip" will operate on those tuples.
zip can operate on any amount of iterables, but it only returns tuples
you could do smthing like [[i, j] for i, j in zip(lst1, lst2)] to unpack it
Well, thanks for the input @pliant tusk. I am comforted I came to your same conclusion, with list comprehensions. I'll be content with a list(tuple_a) and list(tuple_b).
for i, j in zip(lst1, lst2)
lst3.append([i,j])```
Yes, @signal tide, but I can't use list comprehensions. I could map the result of the zip, I suppose.
I can do this:
tuple(map(list, zip(*map(lambda item_a, item_b: (item_a.operation(), item_b.operation()), iterable_a, iterable_b))))
... and get two lists, by mapping the "list" constructor to the zip iterable which in turn unpacks the previous map.
It's ugly.
Thanks @coral sentinel, @pliant tusk.
Sorry, yes.
@unkempt rock that's surely for #esoteric-python 🙂
also #❓|how-to-get-help
!e
import typing as t
class Thing(t.Mapping[str, int]): pass
print(Thing.__mro__)
@boreal umbra :white_check_mark: Your eval job has completed with return code 0.
(<class '__main__.Thing'>, <class 'collections.abc.Mapping'>, <class 'collections.abc.Collection'>, <class 'collections.abc.Sized'>, <class 'collections.abc.Iterable'>, <class 'collections.abc.Container'>, <class 'typing.Generic'>, <class 'object'>)
I didn't know that this happened.
What does it mean? 😮
Like I get that it has all these things in its MRO but I'm not sure what functionality they're giving
the typehints are generic aliases to the abcs, and Mapping has all of the abc parents listed in the mro
I see
@peak spoke what about typehints for built-in classes, like t.List?
!e
import typing as t
class Thing(t.List[int]): pass
print(Thing.__mro__)
@boreal umbra :white_check_mark: Your eval job has completed with return code 0.
(<class '__main__.Thing'>, <class 'list'>, <class 'typing.Generic'>, <class 'object'>)
hmm
alias to the list, don't know how much it changed with 3.9 but I'd guess it's mostly there to provide the isinstance functinality
iirc, with python 3.9, it introduces __mro_entries__ for that purpose.
is it smart to install all versions of python? or is there a pyenv for Windows I should be using?
@desert peak it doesn't hurt, and on Windows you can use the py launcher to pick which version you want to use.
right
wasn't sure if there was any better way
at work I typically use whatever's in my build/runtime env, no need for multiple versions
well, once you activate a virtual environment, it will just be that version anywya
correct. what I guess I'm asking is if py.exe is the authoritative python version picker and if installing them all sxs is the only way to go
yes py launcher is the 'official' way to handle versions on python
installing them all is definitely not the 'only way to go' but if you want them all installed go for it 🤷♀️
Why is there no method in operator that emulates the unpack operators (*, **)?
While those technically are operators, they are a special case, as you can use them only in a handful of cases
And returning from a function is not one of them, so you really can't have that functionality in the operator module
I see. Thx!
Can I implement a custom class that supports * and/or ** unpacking?
Without inheriting from those that already support them
yeah, all you need is __iter__ (or __getitem__ that supports integer indices starting with 0 and throws an IndexError once out of range) for *, not sure about **
I believe you need __getitem__ and .keys for ** support
yup ^
K thx 😄
fun fact: if you make a function call without defining it, py_compile treats it just like a builtin such as print
what do you mean by treats just like a built-in?
yep
and it can't optimize getting print in print("Hello, world!") either -- it has to do a lookup of a global
hello, I am learning lists for the first time for Python!
I want to use a pairing, like (Variable_Name, Integer_Value) then evaluate the list to see which variable is the highest
can this be done?
oh, this might be the wrong place for this, sorry
Yeah you need a help-thread probably #❓|how-to-get-help @dawn timber
i consider myself pretty good at python, but even now i have no idea why people use classes
i already googled a million time still confused
why not just use functions?
there are both pros and cons
classes let you pretend that a bunch of individual pieces of data are one single piece of data.
but advantages of using classes are that it groups associated data with the methods that operate on them
🤔
(though you can argue about methods vs non-member functions)
say you wanted to represent a User in python
using classes lets you give it a username attr, a password attr, etc
and group that in one spot
compared to using like 5 different string variables
def create_user(username, password):
return whatever data
lol = create_user("test", "test")
``` how different than this
and it also lets you keep the methods for a User with the data itself
what's whatever data?
a named tuple?
it returns a user object after it was created
list*
say you had 10 different attrs for a user
whats attrs
attributes
like first name,middle name, last name, interest, email, password etc
are you going to keep that all in a single list/tuple?
k
think about opening a file - you call open() and you get a file object back. That file object has a bunch of stuff inside it - an id that can be used to retrieve more data from the operating system, a flag indicating whether the file is open or closed, an integer indicating what the position in the file is, a buffer of data that has been read from the operating system and not yet returned from the Python caller, the encoding used for the data in the file, and more.
Every file you've ever opened has all of those things inside of it, but you probably had no idea about half of them. And that's the advantage of classes.
They let you create one object that encapsulates a lot of data, and exposes only the interface that you want to that data.
still bit confused
or, in fact, a list is a good example, too. A list is internally implemented as a single block of memory. If you keep adding new items to the list, eventually you run out of memory in that block, and you need to allocate a new block and move the existing data over to the new block. You, as a user of a list, have no idea that this is the case. A list holds data that allows this to work - it knows how big its block of memory is, it knows how full it is, and so it knows when it is full and needs to be re-allocated. You, as a user of the list class, don't need to know anything about any of that.
still confused -_-
im utterly stupid
ok can you give me more use examples of classes?
so far i never needed classes for anything
but i feel like they're useful if i understand them
you use them all the time, because everything in Python is an object, and every object is an instance of a class.
some of the classes are implemented in the C code instead of in the Python code, but they're all classes. int() isn't a function, it's a class constructor that returns new instances of the int class.
one question
dict is a class, list is a class, set is a class, the files returned by open() are one of around 5 different classes depending on the flags you pass...
if i call a class does it act like a function ? like affect code execution or will it run in its own thread and continue execution regards ?
classes and threads are completely distinct concepts. calling a class is just calling a function - two, actually. When you call SomeClass() to make a new instance, Python calls SomeClass.__new__ and SomeClass.__init__
i seen people create init in classes and i understand its ran once class is called but what is new ?
also while we are at it
what is self ?
is it only used with classes?
basically, __new__ makes an empty object, and __init__ fills it in. More or less. Most people never change __new__, because they don't need to change how empty objects are created - they instead change __init__, which lets them control how the new object is filled in.
and self is just the name for the object that the method is acting on.
so
when they do self.name = "john"
the class now has a variable called name and can be called from other functions in same class ?
or can it be called somehow outside aswell
it can be used outside as well. it can even be created outside, though that's less typical.
how come
i thought self referred to object (class) and if its outside class how can it be claled
@raven ridge :white_check_mark: Your eval job has completed with return code 0.
John
normally, attributes are set in __init__, because part of the object-oriented programming paradigm is that a class is responsible for managing (encapsulating) its own data.
so, setting an attribute on the instance from anywhere other than an instance method is a bit strange. But it's completely possible; instance methods aren't particularly magic, and the self in the instance method is the same as the object that the method is called on - if you can do self.name = "John" in a member function, you can do obj.name = "John" on that same object outside a member function.
!e
class test:
def __init__():
self.name = "John"
obj = test()
print(obj.name)```
You are not allowed to use that command here. Please use the #bot-commands channel instead.
why not open a help channel and ping me there - we can keep chatting there, and you will be able to use !e in a help channel.
k
(but that code would work fine, and would print John)
"why use classes" raymonds latest talk is all about that, essentially https://www.youtube.com/watch?v=8moWQ1561FY
PyCon Estonia 2020 was the biggest virtual conference in the nordics aimed at promoting the use of Python language.
In this talk, keynote speaker Raymond develops object oriented programming from scratch in several different ways. Each way should give a fresh insight into wh...
@unkempt rock ^
Looking at typehinting and I pass credentials in dicts where they are expected to have certain keys.
Am I right in thinking I should create TypedDict objects for this?
!pep 589
Am I right in thinking I should create
TypedDictobjects for this?
@safe hedge yes
Hmm. It's not clear to me from the docs if a TypedDict would complain if the passed dict had extra keys
Looks like it will? https://github.com/python/mypy/issues/4617
By default, all keys must be present in a TypedDict. It is possible to override this by specifying totality. Usage:
class point2D(TypedDict, total=False):
That's the opposite problem though
ah, yeah. in that case, https://www.python.org/dev/peps/pep-0589/#supported-and-unsupported-operations says:
Extra keys included in TypedDict object construction should also be caught. In this example, the director key is not defined in Movie and is expected to generate an error from a type checker:
Ugh. Back to the drawing board I guess. That feels like an odd decision. It doesn't seem like it would be uncommon to be passing a dict which must have certain keys but extra ones are ignored
How is that we can declare something as an instance of the list class using []?
and can we do that for normal classes?
No it's just a feature of the language as far as I'm aware
Can't create custom object declaration
how do you paste code into the chat?
terribly inaccurate simulation of mars and earth drive by using newtons law of gravity
You should showcase your project in #python-discussion
cant post videos/pictures there :/
Well, you put a link to a YouTube video or so
Either way, this channel isn't the right place for that
is there anything wrong with leaving assert <test>, <info> within a module? I've read that they can be skipped with -0, but I don't see why this really matters
the only thing I can really think of is that using raise instead of assert enables one to raise a particular error message, but it's more verbose than using assert
assert <test>, <info>
vs
if <test>:
raise( ... )
actually it doesn't really make much difference, maybe I should just use raise
If they're important to the user of the lib then it should be a normal raise
It depends on your use.. If you have people using your module and they want to give a nice error message then you should use raise
you can have a nice error message with the <info> of an assertion tho no? I'm happy to use raise... just never really feel that motivated to do so
if there are several assertions in a row then that will be quite a few more lines if converted to raise instead, which puts me off a bit, that might be a poor reason tho
assert throws a AssertionError, which isn't the best in terms of ux
better to throw a specific error
Asserts are removed when the -O option is passed to the interpreter too
They aren't made to be any kind of general check shortcuts
yeah but i never ever use -0
that case is always given, but I don't think i care about it
so it's very unsatisfying when it's given as a reason imo
Still, you shouldn't rely on it since it *can* be disabled
using double the code for something that'll never ever happen in my use case
ok no, that is not remotely compelling for me
I can completely write off the -0 usage
And AssertionError is pretty much meaningless
not really - there's a message given with it
assert <test> , <info>, it's pretty clear when you look at the info
so still struggling to motivate not using it, imo it's not worth it for me atm so will just use assertion
if you're writing the code for e.g. data transformation and have full control over running the code then I think they're fine to use
yea, raise is just more code for exactly the same thing, and -0 doesn't matter at all for my use case
for e.g. a package on pypi you would probably want to throw an error that more closely matches the situation that happened, type vs value error etc
then I think your use case is why the keyword exists
it's convenient
what error makes more sense: valueerror or a generic assertionerror
if you're the only one reading it, it probably doesn't matter
yeah but i never ever use -0
@magic python if you're the only one who runs your code, that's fine. If you distribute your code and other people ever run it, then you don't know whether -O will be used, so you don't want your program's behavior to change if it is.
For your own code that you're the only one who will ever run, using assert rather than raising your own exceptions is fine. It's just a bad habit to get into, because it doesn't work for code that is shared.
@sacred yew doesn't matter imo - there's an error and a message about it, so equally clear
My understanding is that assert is for developer / logic errors, to be detected for "fail fast".
@raven ridge not the only one, but it's not a distributed open source package either
My understanding is that assert is for developer / logic errors, to be detected for "fail fast".
sure, but it works - afaict people just change things because "that's how it's meant to be done" instead of what actually makes sense in their scenario
@sacred yew doesn't matter imo - there's an error and a message about it, so equally clear
@magic python depends on if anyone would ever want to catch the error, too.except AssertionError:would be insane
good point re the catching of them @raven ridge
imo just use custom exception ¯_(ツ)_/¯
@mint forge it's more code for the same thing tho
wdym?
exactly what i said
it's double, yes, 2 lines instead of 1
You can write it on one line, if that matters to you.
If the errors can be handled or do anything more than giving you the traceback and stopping the execution then you're taking out a lot of info and usability with the AssertionError encompassing them all
anything more than giving you the traceback and stopping the execution then you're taking out a lot of info and usability with the AssertionError encompassing them all
fair - the usage atm is just catching inconsistencies in data which need to be cleaned and stuff.
having the option of (sensibly) try-catching things is a good point tho
I used an assert recently where I wrote a function that should be producing floats in some range, e.g. [0, 1] and I just wanted to work with the assumption that it does
It is more about intention than line count. Convention for readability. Usually, assert if it is something the user should not try to handle. They should change their code to fit the precondition. https://stackoverflow.com/a/945135
so I put assert 0 <= n <= 1
if it fails, there's a bug in my code that I must fix
if it doesn't, nice
you should almost always create your own Exception classes
i've heard exactly the opposite
that one should use base exceptions as much as possible
@sacred tinsel very similar stuff here too
it's perfectly readable imo
another case that I can think of is pulling data from a database, and wanting to work with similar assumptions
really just trying to figure out whether we need to write logic for specific cases, or not
if it fails at some point, we do
it's just a "please tell me if this is wrong"
it's just a "please tell me if this is wrong"
yeah
Hey guys, odd question. Is there any reason why a module can't see a function?
Hey @prisma cypress, see #❓|how-to-get-help
Would that not be under overall design of the language or use cases?
I'm just coming across an odd bug and wanted to hear people's thoughts on it.
because 99.99% of the time its not a language issue
@magic python sure, but sometimes baseexceptions can't fully describe what you're throwing
like what makes sense for requests.exceptions.TooManyRedirects?
@sacred yew but the fact that sometimes they can't fully describe a scenario isn't (to me) reason to discard them in the cases for which they can
true
i agree with using base exceptions mostly unless they don't work for the usecsae
sorry I was referring to assertion use, but yeah in the case of Exceptions - I can't recall the talk that it was on, they were stressing that adding loads of custom things made things worse rather than better though
And yes you guys are completely correct.
I tracked it down and there was a mismatch between pip and github's version.
Thank you guys so much.
so anyone got any explaination for this? 👀
@narrow pasture in CPython, integers from -5 to 256 are cached, so all 256s are the same object
In a regular python file, literals would also be cached
what happens with 257?
A new integer object is created
oh so its checking if object c is not object d?
yes
Yeah, is is for checking identity (whether or not they're the same object), while == is for value testing
For cached integers and interned strings they effectively do the same thing, but it's an implementation detail and is not guaranteed
wdym by cached integers btw?
-5 through 256, as fix error mentioned above
The internation of strings also varies based on the implementation of python
hm ok got it
in the case of Exceptions - I can't recall the talk that it was on, they were stressing that adding loads of custom things made things worse rather than better though
@magic python it depends - there's pros and cons to both approaches. Taking a relatively trivial example, let's say you own a library that has this interface:
def int_to_hex(x: int) -> str:
"""Convert an int to a base 16 string"""
def int_to_bin(x: int) -> str:
"""Convert an int to a base 2 string"""
def int_to_dec(x: int) -> str:
"""Convert an int to a base 10 string"""
def hex_to_int(x: str) -> int:
"""Convert a base 16 string to an int"""
def bin_to_int(x: str) -> int:
"""Convert a base 2 string to an int"""
def dec_to_int(x: str) -> int:
"""Convert a base 10 string to an int"""
And built on top of that you've got:
def convert_base(x: str, inbase: int, outbase: int) -> str:
if inbase == 2:
xval = bin_to_int(x)
elif inbase == 10:
xval = dec_to_int(x)
elif inbase == 16:
xval = hex_to_int(x)
else:
raise ValueError(f"invalid inbase {inbase}")
if outbase == 2:
outval = int_to_bin(xval)
elif outbase == 10:
outval = int_to_dec(xval)
elif outbase == 16:
outval = int_to_hex(xval)
else:
raise ValueError(f"invalid outbase {outbase}")
return outval
And someone is using your library:
def base_converter_bot(api, command):
if command[0] == '!convertbase':
val, inbase, outbase = command[1:]
try:
api.send_message("Result: " + conversions.convert_base(val, inbase, outbase))
except ValueError as e:
api.send_message(str(e))
Or something like that.
Now, what happens if you realize you can optimize your convert_base function by avoiding the hop through an intermediate int representation, by translating directly from one str to another. You need dedicated functions to do that, but you might make them, and then you can replace your entire convert_base function with:
def convert_base(x: str, inbase: int, outbase: int) -> str:
if inbase == outbase:
return val
return {
( 2, 10): bin_to_dec,
( 2, 16): bin_to_hex,
(10, 2): dec_to_bin,
(10, 16): dec_to_hex,
(16, 2): hex_to_bin,
(16, 10): hex_to_dec,
}[(inbase, outbase)](x)
the valid inputs and outputs remain unchanged - inbase and outbase still need to be 2, 10, or 16. But now, if the user of the bot passes a base like 8, the bot does the wrong thing - it was expecting a ValueError, and now it's getting a KeyError.
that is: you can argue that just using regular Python exceptions here violates encapsulation. It exposes the user of your library to implementation details of how your library works. It makes your library more fragile, and makes it harder to maintain backwards compatibility as you make changes over time.
Hi, i have written a C Extension and i want to use .pyi [stub] files for Type Hinting.
I've been added the <package-name>.pyi to the same folder as setup.py, and tried to install the module by pip install package-name but the type hinting doesn't want to appear :(
Any ideas please?
I think the point the talk mentioned was making was that you shouldn't create your custom exception subclasses and just the builtin exceptions most of the time (if I saw the same talk)
@soft bone your package needs a py.typed file in it - does it have one?
@soft bone your package needs a
py.typedfile in it - does it have one?
@raven ridge Does it have to be named so?
yes - it's an empty file that tells mypy that the package has type hints.
yes - it's an empty file that tells mypy that the package has type hints.
@raven ridge i don't need it for MyPy, i need it for IDE such as Pycharm, etc. which understands .pyi files.
if your package doesn't have a py.typed file, it isn't telling tools that it has type hints, and they should be ignoring any .pyi files in it.
I think the point the talk mentioned was making was that you shouldn't create your custom exception subclasses and just the builtin exceptions most of the time (if I saw the same talk)
@flat gazelle I think I've seen the same talk. And I think I've just offered a compelling counterexample, where using the builtin exceptions makes it harder to maintain API compatibility and exposes implementation details of your library.
if your package doesn't have a
py.typedfile, it isn't telling tools that it has type hints, and they should be ignoring any.pyifiles in it.
@raven ridge well, my directory looks so:
package-name/
file.c
package-name.pyi
tests/
...
setup.py
type-hinting-test.py```
in type-hinting-test.py i do have:
`from <package-name> import func`
and it shows the type hints well!. the problem only starts when i do install the package and trying to see the type hints. I can't see them.
I mean, you could try except that keyerror and raise a valueerror instead @raven ridge
sure. What if the evolution was in the reverse order? What if you started off with the dict lookup, and moved to individual if checks. Raise a KeyError even though there was no lookup performed on any mapping?
the problem only starts when i do install the package and trying to see the type hints. I can't see them.
@soft bone right. Because you're not packaging them properly, because you don't have apy.typedfile, and tools that look in packages for type hints should only do it if the package contains apy.typedfile. Either you're not packaging the.pyifiles, or you are and they're being ignored because you haven't packaged the flag file that says they should be read.
@soft bone right. Because you're not packaging them properly, because you don't have a
py.typedfile, and tools that look in packages for type hints should only do it if the package contains apy.typedfile. Either you're not packaging the.pyifiles, or you are and they're being ignored because you haven't packaged the flag file that says they should be read.
@raven ridge
ok, i've added an empty py.typed file to the root directory of the project, what should i do next?
it shouldn't be in the root of the project, it should be inside the package. So, in package/package-name/
And, in your setup.py, you need:
package_data = {
'package-name': ['py.typed', 'package-name.pyi'],
},
Thank's, i will try it out!
also - wait, does this mean that you have only a module, not a package?
i want to install it by python setup.py install later so it will be a package.
I don't mean "package" in the PyPI sense, I mean it in the Python import system sense - an importable directory containing an __init__.py
I don't mean "package" in the PyPI sense, I mean it in the Python import system sense - an importable directory containing an
__init__.py
@raven ridge no i don't need__init__.pybecause the entire module is written in C, i just need setup.py.
@soft bone then it's not possible to distribute type hints for this package. PEP 561 says:
This PEP does not support distributing typing information as part of module-only distributions. The code should be refactored into a package-based distribution and indicate that the package supports typing as described above.
o
and then, I'm past my depth. I have no idea if it's possible to get IDEs to read type stubs for a module-only distribution. I know that mypy won't, and IDEs shouldn't either, but who knows if they're following the standard or not.
it may be best to refactor it into a package, instead.
Well, that package exists in PyPI as well if it matters.
it doesn't. The point is, the way to say that a Python package supports type hints is to add a flag file into the package. That only works for packages, because it needs to be a directory.
Your just-a-C-file distribution doesn't have anywhere to put that file, because it doesn't contain any directories.
Your just-a-C-file distribution doesn't have anywhere to put that file, because it doesn't contain any directories.
@raven ridge actually that's the package, i guess it's possible to use type hints there, no?
the only __init__.py I see there is in the tests
the only
__init__.pyI see there is in the tests
@raven ridge right, because i don't need another one that package works fine.
I'm not sure what to tell you. You're supposed to tell tools that you have type hints if you want them to pick it up, and you can only do that for packages with an __init__.py (and you do it by writing a py.typed file next to the __init__.py)
@raven ridge thank you for the example ( which is here #internals-and-peps message if others are interested, in response to this #internals-and-peps message ).
You mention:
you can argue that just using regular Python exceptions here violates encapsulation
I'm not too sure that I follow (perhaps because I don't typically work with oop), encapsulation to me is just a bunch of data and functions that make sense to be in the same place, I've not considered how error messages factor into this though (or - how having an illogical error message might break it).
@magic python I should probably have said "violates information hiding" or "violates abstraction" instead. Closely related to encapsulation and OOP, but not exactly the same. The idea behind exposing a function to users is to provide them with some functionality, and they shouldn't know (or be able to depend on) how you choose to implement that functionality. When you decide to change from multiple if statements to a dict lookup (or vice versa), you want that change to be invisible to your users. The contract you maintain with them shouldn't change because of how you choose to implement your function, so called "implementation details".
but, using builtin exception types directly - at least in the case where they are directly raised by the operations you perform, rather than raised directly by you with a raise statement - exposes the user to implementation details about how you do what you do.
and leaves you in a nasty position. Like @flat gazelle said, in the example I gave you could do:
try:
return {
( 2, 10): bin_to_dec,
( 2, 16): bin_to_hex,
(10, 2): dec_to_bin,
(10, 16): dec_to_hex,
(16, 2): hex_to_bin,
(16, 10): hex_to_dec,
}[(inbase, outbase)](x)
except KeyError:
raise ValueError("invalid base")
``` But if you don't do that, you've broken users. And if you do do that, you've lost an advantage of just using the builtin exception types.
and, the reverse case is even more alarming - let's say you started with the dict lookup version, and so users would get a KeyError if they ever tried to convert to or from an unsupported base. And later you decide that was a premature optimization, it's not all that much faster, and it's more complex than just a couple of if statements, and so you change to this version:
def convert_base(x: str, inbase: int, outbase: int) -> str:
if inbase == 2:
xval = bin_to_int(x)
elif inbase == 10:
xval = dec_to_int(x)
elif inbase == 16:
xval = hex_to_int(x)
else:
raise ValueError(f"invalid inbase {inbase}")
Now you've got a choice to make. Do you raise ValueError like this? If so, you'll break any users who designed their code around your previous interface, and who were expecting a KeyError. Or, do you raise KeyError(...) yourself, even though there is no longer any key being looked up, and it's no longer the right type of exception?
What is the downside of adding custom exceptions supposed to be?
I guess my point in a nutshell is that the exceptions that can be raised from your function are part of your public interface, and failing to maintain backwards compatibility for them over time can and will break users.
What is the downside of adding custom exceptions supposed to be?
@gloomy rain I think that it takes more work, requires extra documentation, and might obscure information that would be obvious if builtin exceptions were used (though exception chaining takes the wind out of those sails, I think)
@scarlet cave #❓|how-to-get-help
or maybe #algos-and-data-structs
okay
What do you think about naming attributes the same way as some builtin? Like:
@dataclass
class SolutionTest:
input: str
output: str
Is it considered bad for some reason?
or other common things, like type or id (which probably shouldn't be in the prelude anyway?)
I do it with no remorse. id is too useful a name to not use (and too useless a builtin to worry about shadowing)
I try to avoid local variables that shadow builtins, but function parameters or object attributes I don't mind.
@grave jolt since they're always attached to a namespace (self), I think it's fine.
right, because they can't clash
thanks, I'll keep the input then
one good (I think?) thing in JavaScript is that you can use keywords as attribute names
anyone know a good way to run an async fn in a ctor?
I googled that last week and stackoverflow said "don't".
I need to evaluate the coroutine results
like, if a Student has a class, no need to dance around that with klass or class_
restructure the code so the async stuff is done elsewhere.
you can make a lazy async method, for example
well, the async stuff is part of the class
it's a thin wrapper around aiohttp.ClientSession
doing it in a member function or classmethod is fine, but it can't be done in the constructor.
you can even make an async def create_my_session(). But it can't be done in the ctor
you can make a lazy async method, for example
class Connection:
def __init__(self):
self._socket = None
async def socket(self):
if self._socket is None:
self._socket = await make_socket_somehow()
return self.socket()
Don't create unexpected interfaces, you can make an alternate method to construct the object or schedule it to be ran inside of it
it needs to be part of the class, it doesn't make sense outside of it
it refreshes credentials from a vault for integration to an API
class Connection:
def __init__(self, sock):
self._socket = sock
@classmethod
async def create(cls):
return cls(await make_socket_somehow())
so you're suggesting a factory instead of a ctor
yep. free function or classmethod, but yeah.
well, someone here made a metaclass for that
but that's an unexpected interface, and a typechecker might hate you
unfortunately, there are no private ctors in Python
I guess you could also have a metaclass for async init.
or not unfortunately...
You could also make Connection awaitable, but that's kind of weird?..
well here's what I have so far:
unfortunately, there are no private ctors in Python
@grave jolt psh, just useinspectto check who called you and raise if it wasn't your factory! /s
class Connection:
def __init__(self, sock, *, THIS_IS_A_PRIVATE_CONSTRUCTOR):
self._socket = sock
@classmethod
async def create(cls):
return cls(await make_socket_somehow(), THIS_IS_A_PRIVATE_CONSTRUCTOR="I understand")
/s * 1024
Also, doesn't the thing you are wrapping use __aenter__ to do its async stuff rather than the constructor
you can make it use an async init with a metaclass as lakmatiol mentioned, but that's just confusing
import asyncio
import ujson
from aiohttp import BasicAuth, ClientSession
from pydantic import BaseModel, stricturl
from . import config
class Client(BaseModel):
refresh_lock: asyncio.Lock
session: ClientSession
uri: stricturl(tld_required=False, allowed_schemes={'https'})
def __init__(self):
settings = config.get_settings()
super().__init__(
refresh_lock=asyncio.Lock(),
session=ClientSession(auth=$DO_AUTH, json_serialize=ujson.dumps),
uri=sesttings.api,
)
$DO_AUTH is my async fn
@grave jolt I have made constructors that do:
def __init__(self, *_args):
self.thing1 = _args[0]
self.thing2 = _args[1]
``` before. At least keep the private stuff out of the signature, and hint that it's private.
@desert peak yeah, so - change the ctor to take auth as a parameter, and add a factory for creating the thing.
creation of the object also happens in a sync-ctx before running the framework, however
then I think you're stuck with a different contract. Make them call await client.initialize() before using it, or lazily initialize on first use.
then maybe the lazy async-hydration as I proposed eariler? or use it as an async context manager (so it performs the async stuff in __aenter__)?
so leave the session uninitialized until first-use essentially?
or rather, without auth initialized
that is doable
question about tuple assignment a,b = stk.pop(), stk.pop()
which variable gets the top of stack of the original stack (stk is a list)
@rustic bone You should claim a help channel for that :D #❓|how-to-get-help (It would be a, though)
how od you guys feel about zip being okay with iterables of different lengths?
What's the issue with it?
it doesnt seem consistent
normally you get an error for sequences of varying lengths
It's just consuming two iterators until one of them yields no more items
yeah.
yeah but the behaviour itself isn't consistent
think about something like unpacking
!e
a, b = [1, 2,3]
You are not allowed to use that command here. Please use the #bot-commands channel instead.
You get a value error
Because that's not the same
name any other example of python being okay with sequences of varying lengths
Why does that matter though? Unpacking and zipping are different operations
theyre pretty much polar opposites
Haskell for example also is fine with zipping with different lengths:
Prelude> let x = [1..5]
Prelude> let y = [1..8]
Prelude> zip x y
[(1,1),(2,2),(3,3),(4,4),(5,5)]
so having consistency in how they deal with varying lengths makes sense
Why though? Then you've removed a huge portion of zips usage
not everything zip works on has a length
^Also a very good point
Why though? Then you've removed a huge portion of zips usage
@late widget how so?
if in unpacking youre supposed to be aware of lengths
why not in zipping?
i agree a lot of people use zip like this
Again you're trying to draw a parallel between two different operations which just isn't really helpful
but what im saying is that python is inconsistent here
Also @flat gazelle's point of they don't need a length
okay? just check if one exhausts before the other
you can't do that
im not saying it has to have a dunder len
how can you not?
the only way to check if there are more items is to try to get the next one
Unless you have a copy of the original before consuming its elements
the only way to check if there are more items is to try to get the next one
@flat gazelle exactly.
and if you do that, you now wasted an element of the iterator
if you see that one generator raised an error but another didnt
then you should raise a ValueError
>>> a = (x for x in range(5))
>>> b = (x for x in range(11))
>>> [*zip(a, b)]
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)]
>>> [*zip(a, b)]
[]
!pep 618 throwing this out here
for your example, I would expect
a = iter([1,23,4,5])
try:
[*zip(a, [1,2,4])]
except ValueError:
print([*a])|
```to print [5]
going to read that, brb
thats a great feature
although, its still optional
still seems slightly inconsistent but 🤷♂️
How would you handle infinite iterables if it weren't optional?
Purely practically speaking, I've had great use with zip being able to zip elements based on the shorter sequence, and zip longest dealing with the larger sequence.
I'd happily take the practicality of those features over trying to be pure for the sake of pursuing purity
im not saying i havent made use of zip like that, i have quite a lot of times. it just seems inconsitent.
there would also be the odd issue of
u = zip([12,23,34],[1,23,4,5])
a, b, c = next(u), next(u), next(u)
```not erroring
Anyone familiar with Celery workers?
while I agree that zip shouldn't check lengths by default
there is this kinda weird behaviour
>>> a = iter([1, 2, 3])
>>> b = iter([1, 2, 3, 4])
>>> list(zip(a, b))
[(1, 1), (2, 2), (3, 3)]
>>> list(b)
[4]
>>> a = iter([1, 2, 3, 4])
>>> b = iter([1, 2, 3])
>>> list(zip(a, b))
[(1, 1), (2, 2), (3, 3)]
>>> list(a)
[]
which stems from the fact that you can only check if a generator is exhausted by actually trying to get a value from it
it's never been a problem for me but 🤷♂️
In the doc it says "zip() should only be used with unequal length inputs when you don’t care about trailing, unmatched values from the longer iterables."
I think the primary reason as to why it's odd is due to the fact that iterators have implicit internal state that's basically a one-way trip
def checkname():
name = input("What is your name: ")
while name = "Aziel Solomon":
continue
if name == "Aziel Solomon":
print("You may continue")
else:
print("This is not Aziel Solomon")
return name
checkname()
Can someone tell me what's wrong here?
@fathom cobalt notthe correct channel for that see #❓|how-to-get-help
I think the primary reason as to why it's odd is due to the fact that iterators have implicit internal state that's basically a one-way trip
@brave badger yeah, precisely
the result of there being no peek functionality
but there are languages with more complex implementations for which that wouldn’t happen shrug
Suppose one wanted to initialise a 2d-matrix (lists of lists) ... My first instinct was to use the "*" operator, to be even more succinct than a list comprehension. So something like:
matrix = [[(0, 0, 0)] * 5] * 6
I realised that the rows of the matrix though all actually point to the same list, so matrix[0][1] = (255, 255, 255) for instance, will assign that tuple to all the rows in column #2.
I vaguely understand why that happens. The "*" is not invoking the list constructor, I assume, like a list comprehension would do. But I am not too clear about it.
Also, what would be an alternative syntax to achieve the same result, without recurring to: matrix = [[(0,0,0)] * 5 for column in range(6)] ?
hi, it is explained here https://www.geeksforgeeks.org/python-using-2d-arrays-lists-the-right-way/
Thanks, @dawn patio. Having a read.
if u mess with builtins.pyi will it affect how your code will run?
To answer my own question, this is how one could go about it without using list comprehensions: matrix = list(map(lambda _: [(0, 0, 0)] * 5, range(6))).
pyi files are type stubs and aren't executed by anything when you run python normally on the py file
ohh, i thought if i changed something there then it would change the entire python complier lol
You can also do it like this: [[(0, 0, 0) for _ in range(5)] for _ in range(6)], which also works for mutable entries. I’d probably advise against doing list-map-lambda: a list comprehension is usually clearer.
any ressource to learn the binary tree I got stuck with it can't understand it very well
@tame pollen try #algos-and-data-structs
thaank ya
I fully agree. List comprehensions are definitely clearer. I keep away from them as an exercise.
I am having a bit of an issue now. I am trying to define a class attribute that references a class object itself. Something like:
class Point:
origin = Point(0, 0)
def __init__(self, x, y):
self.x = x
self.y = y
The Point constructor won't probably run before the class is specified.
you need to define the class before the class is called
Due to how Python code is executed, yes, at that point (setting class-level attributes and methods), the class itself isn't defined yet
I understand, @dawn patio. That approach is rather common in other programming languages. I am almost certain there's a way to achieve the same result ... The problem is how much syntax is required for it.
put it outside the class?
What would you suggest? Defining a global (!!) object named "origin" that holds a Point instance?
if you're init'ing the origin within the class, it'll recursively call it
Yes, absolutely. I understand. You suggested putting it outside the class ... but I mean to access "origin" in Point's class methods. Where would you put it?
!e
@unkempt rock What you could do is stacking property and classmethod together.
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
@property
def origin(cls):
return cls(0, 0)
p = Point.origin
print(p.x, p.y)
@brave badger :white_check_mark: Your eval job has completed with return code 0.
0 0
what's cls?
The first argument for classmethods, similar as to how self is for regular instance methods
That's pretty interesting @brave badger. I would be returning a new instance of Point though, for each call to origin, right?
Yes, but you could implement caching/singletons in a fairly trivial manner
alternative approach:
>>> from __future__ import annotations
>>>
>>> class Point:
... origin: Point
... def __init__(self, x, y):
... self.x = x
... self.y = y
...
>>> Point.origin = Point(0, 0)
>>>
>>> Point.origin
<__main__.Point object at 0x7fcb6a224580>
I will look into that. Thanks @brave badger.
but I'd just leave it in module namespace probably
Alright, @sacred tinsel. The problem becomes finding the right scope where to assign the class attribute.
class Point:
origin = None
def __init__(self, x, y):
self.x = x
self.y = y
Point.origin = Point(0, 0)
i'm a bit confused, could anyone briefly explain origin: Point?
class PointMeta(type):
origin = None
def __call__(self, x, y):
if x == y == 0:
if PointMeta.origin is None:
PointMeta.origin = super().__call__(0, 0)
return PointMeta.origin
return super().__call__(x, y)
class Point(metaclass=PointMeta):
...
The type annotation will instruct the IDE, linter, etc. that origin should store a "Point".
oh, got it, thanks
Thanks, @deft pagoda. You will agree that's a lot of syntax for a very simple idea! I will look into meta-classes.
yes, its optional, you can just assign the attribute without annotating it first
>>> class Point:
... ...
...
>>> Point.origin = Point()
but having the annotation will help your IDE know that the attribute is expected to be there, so that it can autocomplete for you
there's other, arguably nicer, ways to cache
I'm not sure how type checkers would deal with it
like with a decorator, for instance
(I love this channel, lots of feedback and insightful comments. Thanks, folks.)
In [5]: def cacher(*match_args):
...: def deco(cls):
...: cache = None
...: def wrapper(*args):
...: if match_args == args:
...: nonlocal cache
...: if cache is None:
...: cache = cls(*args)
...: return cache
...: return cls(*args)
...: return wrapper
...: return deco
...:
...: @cacher(0, 0)
...: class Point:
...: def __init__(self, x, y):
...: self.x = x
...: self.y = y
...:
In [6]: Point(0, 0) is Point(0, 0)
Out[6]: True
you could stack that decorator to cache whatever Points
what about something like this
>>> class Point:
... @property
... @classmethod
... def origin(cls):
... if hasattr(cls, _origin):
... return cls._origin
... cls._origin = Point()
... return cls._origin
...
>>>
>>> Point.origin
<property object at 0x7f3e1b11c090>
>>> Point.origin
<property object at 0x7f3e1b11c090>
that works
wait why didnt that error for me
it should be a string hasattr(cls, "_origin") right
i think your decorators are backwards
ah I'm looking at the func objects
wait, is it even possible to have a classmethod property
that's a 3.9 thing
actually speaking of classes but not really, how do you docstring dataclasses?
You typically add them right after the declaration; documentation generators should be to parse that as docstrings for the __new__ and __init__ functions as well iirc
see I tried that but the args are undefined
idk if that's just pycharm but I can't get a preview
Might be more appropriate to ask in #tools-and-devops
ah for sure
If you don't care about being able to access the class property on an instance, you can also define it in a metaclass. But, yeah, it will only be available on the class object, not an instance of the class. That would give you < 3.9 compat.
!e
class PointClass(type):
_origin = None
@property
def origin(cls):
if cls._origin is None:
cls._origin = cls(0, 0)
return cls._origin
class Point(metaclass=PointClass):
def __init__(self, x, y):
self.x = 0
self.y = 0
def __repr__(self):
return f"Point(x={self.x!r}, y={self.y!r})"
o1 = Point.origin
o2 = Point.origin
print(o1)
print(o1 is o2)
@wide shuttle :white_check_mark: Your eval job has completed with return code 0.
001 | Point(x=0, y=0)
002 | True
The origin is cached at the type level by the way, the metaclass _origin is just a convenient default value
nice yeah that makes sense
(and we'll hope that noone mutates Point.origin
)
Unless people start messing with Point._origin (which is on them, obviously; there's a _ for a reason), you can't do it on the property itself
But, if consenting developers want to mess with the origin, they can, yeah
right, that's true
I think it makes sense to make points immutable
does NameTuple work with a custom metaclass?
!e
from typing import NamedTuple
class PointClass(type):
_origin = None
@property
def origin(cls):
if cls._origin is None:
cls._origin = cls(0, 0)
return cls._origin
class Point(NamedTuple, metaclass=PointClass):
x: float
y: float
I don't know! Let's try.
@grave jolt :x: Your eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File "<string>", line 13, in <module>
003 | TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
noup
!e
ah, but dataclass should work because it just mutates the class
from dataclasses import dataclass
class PointClass(type):
_origin = None
@property
def origin(cls):
if cls._origin is None:cls._origin = cls(0.0, 0.0)
return cls._origin
@dataclass(frozen=True)
class Point(metaclass=PointClass):
x: float
y: float
p = Point.origin
print(p)
p.x = "I like mutable state so much!!!"
@grave jolt :x: Your eval job has completed with return code 1.
001 | Point(x=0, y=0)
002 | Traceback (most recent call last):
003 | File "<string>", line 17, in <module>
004 | File "<string>", line 4, in __setattr__
005 | dataclasses.FrozenInstanceError: cannot assign to field 'x'
yep
!e
class AutoDict(dict):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self['__auto_attrs__'] = []
def __missing__(self, key):
if key.startswith('__'): raise KeyError(key)
self['__auto_attrs__'].append(key)
class qMeta(type):
def __prepare__(name, bases): return AutoDict()
class q(metaclass=qMeta):
def __init_subclass__(cls):
attrs = [attr for c in reversed(cls.__mro__) for attr in getattr(c, '__auto_attrs__', [])]
args = (', ' if attrs else '') + ', '.join(attrs)
init_header = f'def __init__(self{args}):\n'
init_body = '\n'.join(f' self.{name}={name}' for name in attrs) if attrs else ' pass'
repr_header = 'def __repr__(self):\n'
repr_body = ' return f"{{type(self).__name__}}({})"'.format(', '.join(f'{name}={{self.{name}!r}}' for name in attrs if name != 'func'))
loc = {}
exec(init_header + init_body, loc)
exec(repr_header + repr_body, loc)
cls.__init__ = loc['__init__']
cls.__repr__ = loc['__repr__']
class Point(q):
x, y
print(Point(0, 0))
@deft pagoda :white_check_mark: Your eval job has completed with return code 0.
Point(x=0, y=0)
How can I install a package with data files using setuptools? I built source distribution, it includes the package data but when installing the package it ignores the data. I used package_data attr of setup() and MANIFEST.in, none worked. The data files are inside a subfolder of the python package folder.
Could also do
def bind_instance(attr_name, *args, **kwargs):
def decorator(cls):
setattr(cls, attr_name, cls(*args, **kwargs))
return cls
return decorator
@bind_instance('origin', 0, 0)
class Point:
origin: Point
def __init__(self, x, y):
self.x = x
self.y = y
(bit late to the party though)
@tacit hawk That question would be better asked in one of the help channels
Maybe even
def bind_instance(attr_name, fn):
def decorator(cls):
setattr(cls, attr_name, fn(cls))
return cls
return decorator
@bind_instance('origin', lambda Point: Point(0, 0))
class Point:
origin: Point
def __init__(self, x, y):
self.x = x
self.y = y
because some classes can contain themselves recursively, like Cons(1, Cons(2, Cons(3, Cons.Nil)))
I like that a bit more than doing 0, 0 in the call args
It worked, I forgot to remove old builds, the changes in setup.py was not taking effect
Add data files to MANIFEST.in and set include_package_data=True in setup()
Not sure how to extend this to mutual recursion, maybe something like this? But it looks pretty confusing.
@mutrec_bind_instance('origin', lambda Point, Shmoint: Point(Shmoint(1, 2), Point(3, 4)))
class Point:
origin: Point
def __init__(self, x, y):
self.x = x
self.y = y
@Point.__mutrec__('origin', lambda Point, Shmoint: Point(Shmoint(1, 2), Point(3, 4)))
class Shmoint:
origin: Shmoint
def __init__(self, x, y):
self.x = x
self.y = y
I would rather just do ```py
Point.origin = Point(Shmoint(1, 2), Point(3, 4))
why does the __and__ dunder make use of & rather than and?
i.e.:
class Foo:
def __and__(self, other):
return True
# __and__ handles this:
Foo() & 2
# rather than this:
Foo() and 2
Because the logical and operator will operate on boolean values and won’t use any dunder
actually, it seems like a question more suited to #❓|how-to-get-help
I felt like this was more of a theorethical relatively advanced question so I used this channel rather than the help channels
I just wonder why limit and to only work with bools and implement a whole new & operator if you can simply use and
I understand, you should check out the channel topic then
This channel is for discussions, but not for helping
But I'm not really asking for help, I'm just curious as to why it was implemented this way
I thought help channels were meant for questions that requires long answers
yeah, I mean I understand if I have to switch to help channel, but this isn't exactly something I'd requre help about, it seems to fit the channel description since it's an advanced topic and I'm only curious behind the reason of implementing & over making use of and
It can operate on any value, you only get boolean outputs with boolean values, thhoug
Alright my bad, seems like a good topic for here
True, but that’s because of optimization
Optimization?
Yup, you just return the last item on the stack instead of fetching True from the scope again
Well, it isn’t really fetched from the scope, is it?
!e
import dis
dis.dis('True')```
I thought the point of and was to work for any value and return the last truthy value
@undone hare :white_check_mark: Your eval job has completed with return code 0.
001 | 1 0 LOAD_CONST 0 (True)
002 | 2 RETURN_VALUE
or the first falsy value
(Yeah, it is loaded as a constant)
Don’t quote me on that, but iirc it was first because of optimization, and it finally made into the langauge as an actual feature
!e
import dis
dis.dis('a and b')```
@undone hare :white_check_mark: Your eval job has completed with return code 0.
001 | 1 0 LOAD_NAME 0 (a)
002 | 2 JUMP_IF_FALSE_OR_POP 6
003 | 4 LOAD_NAME 1 (b)
004 | >> 6 RETURN_VALUE
Do you see how this is way more optimised than if you had to load True and False onto the stack?
hmm, I see, I suppose that makes sense
help me please, i have problems with a code for a question from my university, i run the program but there is no interaction box at all.
please
Is a and b basically equivalent to b if a else a, though the latter is less optimized?
@undone hare :white_check_mark: Your eval job has completed with return code 0.
001 | 1 0 LOAD_NAME 0 (a)
002 | 2 POP_JUMP_IF_FALSE 8
003 | 4 LOAD_NAME 1 (b)
004 | 6 RETURN_VALUE
005 | >> 8 LOAD_NAME 0 (a)
006 | 10 RETURN_VALUE
Yup, that's less optimized, you load a twice here
is there a way to notate that an arg can only be optional if the other isn't?
like at least one can't be None?
@raw jetty Please don't dump memes in any of the channels, especially the on-topic ones like this one
@signal tide I don't think there's a way. If you really want type safety, you could do
def f(x: int, arg: Union[Tuple[float, None], Tuple[None, str]]):
...
another option is to not create a complicated interface, and do just this:
def f1(x: int, arg: float):
...
def f2(x: int, arg: str):
...
why not make it the second variant?
Can you show your function?
I could but it would overcomplicate it a bit
I'll try to figure it out
spliting it* lol
def unequip_item(self, item: Optional[str], slot:Optional[str], index: Optional[bool]) \
-> Tuple[bool, Binary, Binary]:
"""Unequip item in weapon slot
:param Optional[str] item: item name
:param Optional[bool] index: item index (1 or 2)
:return: (unequip was successful, invalid identifier, bag full """
if self.bag.not_full:
if slot in ["weapon1", "weapon2"]:
selected_item = getattr(self.Weapons, slot)
self.bag.put(selected_item)
return (True, 0, 0)
else return
for weapon_slot in self.weapon_slots:
selected_item = getattr(self.Weapons, str(weapon_slot)).name
if selected_item == item:
setattr(self.Weapons, str(weapon_slot), None)
self.bag.put(selected_item)
return True
else:
setattr(self.Weapons, str(weapon_slot), selected_item)
return False
else: return -1
else: return None```
I realize the returns don't match
those inline else blocks though
I had to reformat it or the bot would've picked up on it
raise exception when both are missing? 😮
does overloading not have a 3.9 implementation?
Does that have something to do with function overloading? I'm semi afk or I'd look
ya, the decorator is there but I can't use before/after
pip'ing it gets the 3.8 vers
Does it use type annotations?
I have no clue
I'm opposed to function overloading btw. Just wondering
I don't have enough meaningful experience with other languages to know but isn't most function overloading where you have one master version of the function and the rest are just transforming other data types for use in the master version?
Because in python that pretty much does away when any numeric or iterable type would do.
idrk if I should be using it or not, it was fix-error's idea, but I've got a method that's got 2 optional args where they can't both be none
so I've now got 1 overload per arg and the default for the invalid case
Can't you do "if x is none and y is none: raise"?
that's what I had give or take..
Sounds fine to me
idk anymore if anything it looks more like I know what I'm doing ¯_(ツ)_/¯
I mean my weapon bag is a queue so it's not like I'm doing things efficiently
I guess I'd have to see it but usually I foam at the mouth when I hear design patterns I don't like and I'm not getting that.
i mean you can take a look https://github.com/The1Divider/__insert_name__-rgp, i'm not sure if that's functional tho I had to change a bit and I started working on the second restruc so I can't push anything
also rip my frequency graph
Are we talking about typing.overload or something else?
Cause I handle that case the way Stelercus suggests: having the function check if the arguments are mutually consistent, and raising TypeError if not, and using typing.overload to document what combinations are valid
typing.overload is nice for documenting/type checking Union return types but I'm not too fond of mypy not type-checking the implementation of the overloaded function unless the return type is specified
I'm not too fond of mypy 😄
something about mypy specifically, or static type checkers in general?
Hard to say. mypy is what my team uses at work, and I'm constantly finding new bugs and limitations. I haven't tried out any of the alternative static type checkers.
But I do think static type checking in Python is relatively low value, at least within a module. Correct annotations are useful at module boundaries as a form of documentation, but within a module they do less than automated tests would do to verify code's correctness. I'd rather feed the actual function my actual parameters and see whether they work than have a type checkers check whether the declared types of the arguments I'm providing match the declared parameter types of the functions I'm calling.
my go-to example of something that I find limiting is that the sentinel object idiom for a sentinel. Before the introduction of type hinting, it was relatively common to do something like:
_CONFIG = {...}
_RAISE = object()
def get_config_value(key, default=_RAISE):
value = _CONFIG.get(key, default)
if value is _RAISE:
raise KeyError(key)
And - imagining that the value for each key is meant to be a str, let's say, there's no correct way to type hint that, because there's no way to say that the default must be an instance of str or the specific instance of object() that is _RAISE
this bothers me because it was a very common idiom, and it's a place where code that was idiomatic needs to be rewritten in order to type hint it.
Bro thats some #esoteric-python thats way over my head
hm. it's not at all esoteric. It's a way to make a default value for an argument that is distinct from all possible valid values.
maybe not to you LOL
normally you'd just use None as the value for the default case, and do something special if default is None to indicate that the user didn't provide that parameter
but you can't do that if None is a valid value that the user might legitimately want to pass.
oooh ok
ok
I think I see
Well I feel like you need a singleton pattern in this case
@raven ridge what would you think of a "null argument" special value that serves no purpose but to be the default argument sentinel
how would it tie into the actual language, as opposed to typing?
Like if you really want to check for the exact instance of _RAISE and not its type, why not make _RAISE a special singleton
the singleton pattern is a hack to get globals into pure OOP languages.
Well what else r u supposed to do
making a singleton is indeed the only thing that works for this case, but it's real yucky. Now you need to declare that this thing takes default: Union[int, None, _SpecialValue]=_RAISE and do _RAISE = _SpecialValue()
and your type hints, which are most useful as a form of documentation, now indicate that this parameter can take any instance of type _SpecialValue, but there is and will ever only be one instance of _SpecialValue
Ehh
Im trying to remember if you do __repr__ if that will get replaced in the help
I mean your points are valid imo
But again, this is trying to add static type checking to a dynamic language, the fact we even get this close is kinda amazing
a special __repr__ will work in Sphinx - I think it works in help() and pydoc as well.
yeah... I dunno. Refer to my first point: if you have a good test suite, every bug that would ever be caught by mypy will also be caught by your tests. And if you don't, you'd be better served by writing a good test suite than by adding type annotations
So we've come full circle. Fair enough. Good Talk.
heh. I see your point that it's impressive that we get close. But I'm more frustrated by the gaps in expressiveness, when I hit something that I think is easy to use but impossible to describe to typing, than I am pleased by the mostly working
randomheart = (random.randint(goodheart1,goodheart2,goodheart3,goodheart4,goodheart5,goodheart6))
how do you choose a random one from all of them?
@unkempt rock this is not the correct channel for that question.
See #❓|how-to-get-help.
ok well then I'm definitly using it wrong, how do you do this?
tbh I might just split the method into separate ones for each arg
oh nvm that's what fix-error was talking about, I thought it was the same as PEP 3124
@raven ridge Have you tried Pyright? I liked it better than mypy
it still has a lot of limitations which are pretty hard to express given Python's dynamic nature, though
mypy is not so smart and evil
I haven't tried pyright yet, though I do want to try
it even supports recursive type aliases 
that's... too much to ask, I guess 🙂
do
do
level_type: LevelType = LevelType.DEFAULT``` and mypy be like _expected LevelType, got int_
pyright does't support type-level functions either (like Add: (Type[Nat], Type[Nat]) -> Type[Nat], because it would need to actually run arbitrary code at typecheck time, and it's a whole can of worms
@cloud crypt is it an Enum?
yes but I wrote my own enums implementation because I wanted to alter things
fucking sunders was my main concern
yes, I am weird, no pun intended
well, it's totally reasonable that a typechecker is unable to introspect some of the magic stuff 🙂
dataclasses, namedtuples and enums are all hardcoded
mmm awesome
Do you all prefix "private" vars with underscore?
Yep
I was thinking if I should copy data structs with public fields when receiving them throught object constructors to avoid indirect changes of private vars
Sometimes that's a good idea. It leads to a more functional-programing style of updating-via-copying. I happen to like it for small enough objects.
an alternative would be to just pass an immutable object from the start 🙂
list -> tuple
set -> frozenset
dict -> immutables.Map
@tacit hawk attrs supports that style with evolve
attr.s(slots=True, frozen=True)
class Coordinate:
x: float= attr.ib()
y: float = attr.ib()
z: float = attr.ib()
c1 = Coordinate(5.5, -0.3, 1.0)
c2 = attr.evolve(c1, z=c1.z * 3.0)
I wonder how lisp compilers are able to generate fast (albeit large) binaries while python apparently can't be optimized the same way
well, for example, Clojure runs on the JVM, which might explain it
There are plenty things to do to speed up (c)python like the ones suggested in the faster-cpython proposition or nuitka for example gets nice performance gains while the project is still not completed and can be optimized more
I don't think there's that big of a push for performance in python or projects improving it compared to cpython and cpython itself would see more requests and contributions regarding it
Hey, I have an issue that haven't been answered for hours and I have googled for 12 hours without a solution.
I want to modify the memory of a process (.exe program) and I have a static pointer but I'm uncertain on how I would get the base address?
Are you sure the OS will allow you to do that?
I'm certain that it's possible at least, cause I tested it a while ago with the address that I need to find and it worked out fine.
I've tested pymem but I'm unsure on how I would find the base address of the program. I tried base_address but it returns: pymem.ressources.structure.MODULEINFO object at 0x0000023684ECCA48 (23684ECCA48) while I expected it to print something like 23D9D097BE0
@paper echo you like attr over dataclasses?
@swift imp many people prefer attrs
Why may I ask?
I guess its bc of attr.validators? That's actually interesting. I was just using my own my descriptors with field like
from dataclasses import dataclass, field
class Descriptor:
def __init__(self):
pass
def __set_name__(self, owner, attr):
self.attr = attr
def __get__(self, instance, types):
return getattr(instance,f"_{self.attr}")
def __set__(self, instance, value):
setattr(instance, f"_{self.attr}", value)
@dataclass
class Foo:
bar: int = field(default=Descriptor())
Then I just build around that
Actually ive done quite a bit of validator stuff
Wish i checked out attrs llol
some people prefer pydantic.BaseModel, I suppose 
@swift imp i don't know the details, but attrs does more, and some people don't like that attrs was copied to make dataclasses in the stdlib.
Anyone have familiarity with atexit and what exactly it doesn't handle? If I register functions will they be executed if an exception is occured or if the user kills the script with ctrl c from the terminal?
if an exception occurs, yes. If the user kills it with ctrl-c, and it raises a KeyboardInterrupt, then yes.
if the script changes the handler for ctrl-c so that it doesn't raise a KeyboardInterrupt but instead immediately kills the process, then no.
if the user kills it from the task manager (or with kill on Unix), then no.
(hopefully this is obvious but) if the computer crashes or loses power, it won't get run.
if you use os.exec* or os._exit, it won't get run.
@swift imp backward compat to 3.6 is somewhat nice, more functionality in general, slots=True and better performance
if you use sys.exit it will.
Thanks
Anyone tried getting pycharms linter to work with automaticly generated _init_ methods?
Everything appears as unexpected arguments, though the code runs fine
Should I ask in a help channel
It's not really a python issue, just linter
Sure I posted there
Hello everyone,
This will be a vaugue question but please try to answer to the best of your knowledge.
I am making a nearly-identical image detection algorithm (not from the scratch) for my firm. I am new to the industry.
So I will be processing thousands of images and have used LSH algorithm for it (which uses dhash for calculating signatures I guess)
This is my internship project and I have not "studied" on Machine Learning/Deep Learning.
Now would this be a good approach for image recognition? Or should I go to Tensorflow?
Thanks a bunch. Any response would be valuable to me (:
Regards,
Mortis
@ me. Cheers!
)?