#internals-and-peps

1 messages · Page 84 of 1

tawdry gulch
#

Oh, that explains it

#

all in all, very interesting

#

I can see this being used for some esoteric fun-ness

spring jackal
#

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

gleaming rover
#

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.

spring jackal
#

oh okay thanks i just wanted some advice

raven ridge
#

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

hot vault
#

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.

undone hare
grave jolt
#

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
#

It does work like extend

#

!e

xs = [1, 2, 3]
ys = xs
xs.extend([4, 5])
print(xs, ys)
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
wide shuttle
#

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

deep bramble
#

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

wide shuttle
#

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)
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

[1, 2, 3, 4, 5] [1, 2, 3]
grave jolt
#

You meant it the other way around
Yep

#

reaches out to grab ctypes and patch the list type

pliant tusk
#
>>> @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?
grave jolt
#

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?

spice pecan
#

It acts that way if __iadd__ isn't defined

#

just takes __add__ and rolls with that

pliant tusk
#

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

peak spoke
gusty lichen
wide shuttle
gusty lichen
#

y, just wanted to move my message, realied too late

grave jolt
#

Does "Standards Track" on a PEP mean that it's accepted and will be actioned?

peak spoke
#

They're used to propose something new for python or cpython

#

PEP 1 should describe it

grave jolt
#
  1. 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

bronze acorn
#

Can i talk about software architecture here?

sacred yew
#

this is more for discussion about python itself

boreal umbra
#

@bronze acorn you can talk about software architecture as it pertains to Python

#

I assume that's how one should structure a code base?

bronze acorn
#

AFAIK, uml design is part of any software architecture, right?

boreal umbra
#

@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.

oblique crystal
#

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

boreal umbra
#

@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.

safe hedge
#

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

oblique crystal
#

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

safe hedge
#

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

oblique crystal
#

He was actually recently on boarded and it was not easy

boreal umbra
#

Unless we can get back into Python territory

safe hedge
#

I actually have an unrelated python Q I was just considering. What is an actual use-case for the start parameter in sum?

peak spoke
#

You can use it for example to flatten nested lists

flat gazelle
#

overall, when adding non-numeric things

safe hedge
#

Can you give an example?

peak spoke
#

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

flat gazelle
#
sum([[1,2,3,],[3,5,5]],[])
safe hedge
#

Hmm I see. How efficient is that for flattening?

peak spoke
#

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)
oblique crystal
#

For flatten I usually just do list comp

peak spoke
#

It works with add so new objects are being created at every step

safe hedge
#

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

boreal umbra
#

@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.

safe hedge
#

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

gleaming rover
#

Hmm I see. How efficient is that for flattening?
@safe hedge it’s basically the same as for strings (don’t do it)

safe hedge
#

You can't do it for strings...

#

sum errors if you give it strings

#

Even if you pass start=''

gleaming rover
#

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)

safe hedge
#

I get you now

gleaming rover
#

👋

grave jolt
#

Ooo. That could be nice, though isn’t the real use case for lambdas the simplicity of them being short (except for #esoteric-python lemon_enraged )?
@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 using Promises:

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

spark parcel
#

The lambdas you’re referring to, are they the arrow functions?

grave jolt
#

yes

gleaming rover
#

The lambdas you’re referring to, are they the arrow functions?
@spark parcel which are pretty 🙂 unlike lambda 🤢

spark parcel
#

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

gleaming rover
#

unless you use something like RxPy

grave jolt
#

@gleaming rover by 'lambda' I mean a function-as-a-value in general, not necessarily Python's idea of lambdas

gleaming rover
#

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

flat gazelle
#

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')
grave jolt
#

@gleaming rover I used the word "lambda" in my message as a synonym for an anonymous function, maybe that was confusing

gleaming rover
#

@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 meant lambda in the sense of Python's lambda syntax

grave jolt
#

yes, I understand

spark parcel
#

Ah, yeah. That’s why you put code blocks there

gleaming rover
#

but yeah I have always understood "lambda (function)" and "anonymous function" to be synonymous

spark parcel
#

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

grave jolt
#

I'm not saying they would be very useful in Python

spark parcel
#

I’m mostly wondering if they would have any application

peak spoke
#

python doesn't really have a place for them, but they're great in languages with more functional characteristics and things like pattern matching

gleaming rover
#

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?)

flat gazelle
#

event handlers for GUIs would be a usecase for multiline lambdas

spark parcel
#

I haven’t even heard of RxPy

#

@flat gazelle in what way?

peak spoke
#

Didn't find any need for that when making gui apps

flat gazelle
#

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

spark parcel
#

Hmm, I can see where you’re coming from. They may not justify a whole separate function yet aren’t a single line

gleaming rover
#

I haven’t even heard of RxPy
@spark parcel it's basically like the above JS example with .then and .catch but on steroids

spark parcel
#

Ohh hahah

peak spoke
#

so something like

button = Button()
button.on_click(
    lambda: (
        self.a.set_text("a"),
        self.b.set_text("b"),
        self.c.set_text("c"),
    )
)
```?
spark parcel
#

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")
    })
)
gleaming rover
#

Wouldn’t it just be cleaner to allow code to be passed directly, using something like curly braces
@spark parcel isn't that basically a lambda

#

with no parameters

grave jolt
#

yeah, a 0-argument lambda is basically that

gleaming rover
#

also that would be a set

spark parcel
#

Oh. How silly of me

#

Let’s get rid of sets and make people use set() to create them hahah

grave jolt
#

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)

peak spoke
#

Well if python had braces and semicolons, that'd be one of the few nice uses for them I can think of

spark parcel
#

Yep. That’s true

boreal umbra
#

!e

from dis import dis
def chained_compare(n): return 5 < n < 6
print(dis(chained_compare))
fallen slateBOT
#

@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

boreal umbra
#

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.

peak spoke
#

It does the same as the and but only evaluates the common expr of the conditions once

boreal umbra
#

@peak spoke what do you mean by that?

peak spoke
#

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
fallen slateBOT
#

You are not allowed to use that command here. Please use the #bot-commands channel instead.

peak spoke
#

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)

raven ridge
#

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
swift imp
#

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?

brave badger
#

It basically adds metadata to a type, allowing for use-cases in static analysis/runtime checks

swift imp
#

But like for what end

raven ridge
#

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.

swift imp
#

Was that in the pattern matching thread?

#

Last time I looked at it people were trying to talk about adding constants

raven ridge
#

yeah.

swift imp
#

Hah

#

That would be the day

raven ridge
#

because of how pattern matching works on constants.

#

the weirdness about whether it checks for equality to the constant, or assigns to the constant.

swift imp
#

Is isinstance not blocked on typing anymore?

#

Last type I tried to a List[int] in an isinstance it yelled at me

raven ridge
#

what do you expect that to do?

swift imp
#

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

raven ridge
#

you can't, but List is deprecated anyway.

#

as of 3.9, you can just use list[int]

swift imp
#

So in 3.9 you can do it

radiant garden
#

I don't believe isinstance supports generic checks.

#

Since it's at a big runtime cost.

boreal umbra
#

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)
fallen slateBOT
#

@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
radiant garden
#

Also, most people don't expect instancechecks to be O(N).

boreal umbra
#

huh, I thought snekbox was on 3.9

peak spoke
#

I wouldn't expect isinstance to do more than a simple type check in any case

rose stream
#

are there any reactive libraries that allow me to make x=y (and x always updates to the current value of y)

boreal umbra
#

@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?

rose stream
#

Sweet, what library allows this

boreal umbra
#

the language itself

rose stream
#

Well, I want to choose between em

#

some will be mutable, some wont

boreal umbra
#

I see

rose stream
#

the solution that python offers will be a start though! - do you mind sharing?

boreal umbra
#

@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)
fallen slateBOT
#

@boreal umbra :white_check_mark: Your eval job has completed with return code 0.

[1, 2, 3, 4, 5]
boreal umbra
#

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)

rose stream
#

No one reads my code, i'm just out here for solutions, I'll give that a shot

boreal umbra
#

as long as you have a reference to the Ref instance, the obj attribute will always be whatever you've set it to.

raven ridge
#

that's true of any attribute of any object. You could just as easily do:

class Ref:
    pass
r = Ref()
r.obj = 42
rose stream
#

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

radiant garden
#

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

rose stream
#

Sweet, i'll look into it

boreal umbra
#

Miss me with that C code.

raven ridge
#

psh, C's a great language. 🙂

boreal umbra
#

@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.

raven ridge
#

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.

boreal umbra
#

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.

raven ridge
#

Computer Science, Software Engineering, and sometimes Computer Engineering...

#

but yeah, depends a lot on the school.

boreal umbra
#

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.

raven ridge
#

let's jump over to an OT channel - ot2!

boreal umbra
#

wow, out-moderated by a helper

signal tide
#

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?

true ridge
#

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?

signal tide
#
@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?
safe hedge
#

{"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)
wide shuttle
#

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

safe hedge
#

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__

true ridge
#

You need to initalize it on the __post_init__.

safe hedge
#

Or just set it as an attribute in the __post_init__ I guess?

wide shuttle
#

If you want it to reflect the initial values, __post_init__ sounds like the good spot

signal tide
#

what's a __post_init__?

wide shuttle
#

If you want it to reflect the current values of self.name and self.item_type, a property would do nicely I think

safe hedge
#

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

signal tide
#

so I'd redefine it to form the dict?

safe hedge
#

This all depends on whether you care if self.item_template changes if/when the other class attributes change

signal tide
#

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

safe hedge
#

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__

signal tide
#

perfects thanks that works

safe hedge
#

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'}
signal tide
#

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?

safe hedge
#

__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__

signal tide
#

ah ok ya I can see why, there'd be no point

safe hedge
#

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.

signal tide
#

that's what I mean, you can call other methods in the __init__, there's no need for a post init

safe hedge
#

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

signal tide
#

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

wide shuttle
#

I think the default implementation of __init__ calls __post_init__ at the end. Edit: yes, the generated __init__ does call __post_init__.

signal tide
#

also are there any mutable containers similar to namedtuple?

true ridge
#

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

signal tide
#

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

true ridge
#

well, it's better than repeating yourself on both the parameter declarations of __init__ and the assignments in the body self.<field> = <value>

signal tide
#

true but I think to an extent that can help with readability

true ridge
#

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.

cloud crypt
#

if your class is mostly reasoning about holding data, I think attrs and dataclasses were made for just that

plush patrol
#

I hope one day to be skilled enough to actually understand what's going on here

signal tide
#

that's the dream

deft pagoda
#

also cluegen in the same vain as dataclasses and attrs

boreal rune
#

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?

peak spoke
#

Python goes through the OS, which will work with the cursor of the file

boreal rune
#

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

unkempt rock
#

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.

pliant tusk
#

so the output you want is [iterable_a_items], [iterable_b_items]? @unkempt rock

unkempt rock
#

Indeed, @pliant tusk.

#

(You're going to suggest list comprehensions, I can feel it.)

pliant tusk
#

then ```py
iterable_items = [[i.operation() for i in iterable] for iterable in [iterable_a, iterable_b]]

unkempt rock
#

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)

pliant tusk
#

zip cant return lists, due to how it works

#

it returns an iterable of tuples

unkempt rock
#

I think the unpacking operator (*) returns just tuples, so yes "zip" will operate on those tuples.

pliant tusk
#

zip can operate on any amount of iterables, but it only returns tuples

signal tide
#

you could do smthing like [[i, j] for i, j in zip(lst1, lst2)] to unpack it

unkempt rock
#

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).

signal tide
#
  for i, j in zip(lst1, lst2)
    lst3.append([i,j])```
unkempt rock
#

Yes, @signal tide, but I can't use list comprehensions. I could map the result of the zip, I suppose.

signal tide
#

if you can do it with list comp, you can unflatten it

#
  • I think (pretty sure?)
unkempt rock
#

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.

coral sentinel
#

what

#

you mean @signal tide ?

unkempt rock
#

Sorry, yes.

grave jolt
desert peak
boreal umbra
#

!e

import typing as t
class Thing(t.Mapping[str, int]): pass
print(Thing.__mro__)
fallen slateBOT
#

@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'>)
boreal umbra
#

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

peak spoke
#

the typehints are generic aliases to the abcs, and Mapping has all of the abc parents listed in the mro

boreal umbra
#

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__)
fallen slateBOT
#

@boreal umbra :white_check_mark: Your eval job has completed with return code 0.

(<class '__main__.Thing'>, <class 'list'>, <class 'typing.Generic'>, <class 'object'>)
boreal umbra
#

hmm

peak spoke
#

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

grand crag
#

iirc, with python 3.9, it introduces __mro_entries__ for that purpose.

desert peak
#

is it smart to install all versions of python? or is there a pyenv for Windows I should be using?

boreal umbra
#

@desert peak it doesn't hurt, and on Windows you can use the py launcher to pick which version you want to use.

desert peak
#

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

boreal umbra
#

well, once you activate a virtual environment, it will just be that version anywya

desert peak
#

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

unkempt rock
#

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 🤷‍♀️

fresh cargo
#

Why is there no method in operator that emulates the unpack operators (*, **)?

spice pecan
#

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

fresh cargo
#

I see. Thx!

#

Can I implement a custom class that supports * and/or ** unpacking?

#

Without inheriting from those that already support them

spice pecan
#

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

flat gazelle
#

yup ^

fresh cargo
#

K thx 😄

heady mauve
#

fun fact: if you make a function call without defining it, py_compile treats it just like a builtin such as print

cloud crypt
#

what do you mean by treats just like a built-in?

raven ridge
#

It has to. Consider:
in bar.py:

def func():
    my_print("func called")

In foo.py:

import bar
bar.my_print = print
bar.func()```
grave jolt
#

yep

#

and it can't optimize getting print in print("Hello, world!") either -- it has to do a lookup of a global

dawn timber
#

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

safe hedge
unkempt rock
#

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?

sacred yew
#

there are both pros and cons

raven ridge
#

classes let you pretend that a bunch of individual pieces of data are one single piece of data.

sacred yew
#

but advantages of using classes are that it groups associated data with the methods that operate on them

unkempt rock
#

🤔

sacred yew
#

(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

unkempt rock
#
def create_user(username, password):
  return whatever data
lol = create_user("test", "test")
``` how different than this
sacred yew
#

and it also lets you keep the methods for a User with the data itself

#

what's whatever data?

#

a named tuple?

unkempt rock
#

it returns a user object after it was created

sacred yew
#

uh

#

how do you create an object without an constructor

unkempt rock
#

list*

sacred yew
#

say you had 10 different attrs for a user

unkempt rock
#

whats attrs

sacred yew
#

attributes

#

like first name,middle name, last name, interest, email, password etc

#

are you going to keep that all in a single list/tuple?

unkempt rock
#

k

raven ridge
#

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.

unkempt rock
#

still bit confused

raven ridge
#

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.

unkempt rock
#

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

raven ridge
#

you use them all the time, because everything in Python is an object, and every object is an instance of a class.

unkempt rock
#

w-what

#

😵

raven ridge
#

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.

unkempt rock
#

one question

raven ridge
#

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...

unkempt rock
#

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 ?

raven ridge
#

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__

unkempt rock
#

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?

raven ridge
#

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.

unkempt rock
#

so

#

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

raven ridge
#

it can be used outside as well. it can even be created outside, though that's less typical.

unkempt rock
#

how come

#

i thought self referred to object (class) and if its outside class how can it be claled

raven ridge
#

!e ```python
class Class:
"""Create an empty class."""

obj = Class()
obj.name = "John"
print(obj.name)

fallen slateBOT
#

@raven ridge :white_check_mark: Your eval job has completed with return code 0.

John
raven ridge
#

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.

unkempt rock
#

!e

class test:
    def __init__():
      self.name = "John"

obj = test()
print(obj.name)```
fallen slateBOT
#

You are not allowed to use that command here. Please use the #bot-commands channel instead.

raven ridge
#

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.

unkempt rock
#

k

raven ridge
#

(but that code would work fine, and would print John)

unkempt rock
#

@raven ridge i lost the help channel i was in

#

lol can u mention it

smoky turret
raven ridge
#

@unkempt rock ^

safe hedge
#

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

fallen slateBOT
#
**PEP 589 - TypedDict: Type Hints for Dictionaries with a Fixed Set of Keys**
Status

Accepted

Python-Version

3.8

Created

20-Mar-2019

Type

Standards Track

gleaming rover
#

Am I right in thinking I should create TypedDict objects for this?
@safe hedge yes

safe hedge
#

Hmm. It's not clear to me from the docs if a TypedDict would complain if the passed dict had extra keys

raven ridge
#

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):
safe hedge
#

That's the opposite problem though

raven ridge
safe hedge
#

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

mint forge
#

How is that we can declare something as an instance of the list class using []?
and can we do that for normal classes?

amber nexus
#

No it's just a feature of the language as far as I'm aware

#

Can't create custom object declaration

marble lava
#

how do you paste code into the chat?

plucky steeple
undone hare
plucky steeple
#

cant post videos/pictures there :/

undone hare
#

Well, you put a link to a YouTube video or so

#

Either way, this channel isn't the right place for that

magic python
#

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

peak spoke
#

If they're important to the user of the lib then it should be a normal raise

wind patio
#

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

magic python
#

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

sacred yew
#

assert throws a AssertionError, which isn't the best in terms of ux

#

better to throw a specific error

undone hare
#

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

magic python
#

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

undone hare
#

Still, you shouldn't rely on it since it *can* be disabled

magic python
#

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

undone hare
#

And AssertionError is pretty much meaningless

magic python
#

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

sacred tinsel
#

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

magic python
#

yea, raise is just more code for exactly the same thing, and -0 doesn't matter at all for my use case

sacred tinsel
#

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

sacred yew
#

what error makes more sense: valueerror or a generic assertionerror

sacred tinsel
#

if you're the only one reading it, it probably doesn't matter

raven ridge
#

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.

magic python
#

@sacred yew doesn't matter imo - there's an error and a message about it, so equally clear

copper nacelle
#

My understanding is that assert is for developer / logic errors, to be detected for "fail fast".

magic python
#

@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

raven ridge
#

@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

magic python
#

good point re the catching of them @raven ridge

mint forge
#

imo just use custom exception ¯_(ツ)_/¯

magic python
#

@mint forge it's more code for the same thing tho

mint forge
#

wdym?

magic python
#

exactly what i said

mint forge
#

how is it more code?

#

it's like 2 lines

magic python
#

it's double, yes, 2 lines instead of 1

raven ridge
#

You can write it on one line, if that matters to you.

peak spoke
#

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

magic python
#

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

sacred tinsel
#

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

copper nacelle
#

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

sacred tinsel
#

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

magic python
#

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

sacred tinsel
#

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"

magic python
#

it's just a "please tell me if this is wrong"

yeah

prisma cypress
#

Hey guys, odd question. Is there any reason why a module can't see a function?

undone hare
prisma cypress
#

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.

sacred yew
#

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?

magic python
#

@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

sacred yew
#

true

#

i agree with using base exceptions mostly unless they don't work for the usecsae

magic python
#

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

prisma cypress
#

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.

narrow pasture
grave jolt
#

@narrow pasture in CPython, integers from -5 to 256 are cached, so all 256s are the same object

spice pecan
#

In a regular python file, literals would also be cached

grave jolt
#

yeah

#

it's just an optimization -- you shouldn't rely on it

narrow pasture
#

what happens with 257?

spice pecan
#

A new integer object is created

narrow pasture
#

oh so its checking if object c is not object d?

grave jolt
#

yes

spice pecan
#

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

narrow pasture
#

wdym by cached integers btw?

spice pecan
#

-5 through 256, as fix error mentioned above

unkempt rock
#

The internation of strings also varies based on the implementation of python

narrow pasture
#

hm ok got it

raven ridge
#

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.

soft bone
#

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?

flat gazelle
#

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)

raven ridge
#

@soft bone your package needs a py.typed file in it - does it have one?

soft bone
#

@soft bone your package needs a py.typed file in it - does it have one?
@raven ridge Does it have to be named so?

raven ridge
#

yes - it's an empty file that tells mypy that the package has type hints.

soft bone
#

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.

raven ridge
#

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.

soft bone
#

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.
@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.
flat gazelle
#

I mean, you could try except that keyerror and raise a valueerror instead @raven ridge

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 a py.typed file, and tools that look in packages for type hints should only do it if the package contains a py.typed file. Either you're not packaging the .pyi files, or you are and they're being ignored because you haven't packaged the flag file that says they should be read.

soft bone
#

@soft bone right. Because you're not packaging them properly, because you don't have a py.typed file, and tools that look in packages for type hints should only do it if the package contains a py.typed file. Either you're not packaging the .pyi files, 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?

raven ridge
#

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'],
    },
soft bone
#

Thank's, i will try it out!

raven ridge
#

also - wait, does this mean that you have only a module, not a package?

soft bone
#

i want to install it by python setup.py install later so it will be a package.

raven ridge
#

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

soft bone
#

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__.py because the entire module is written in C, i just need setup.py.

proper remnant
#

can anyone help?

soft bone
#

@proper remnant indentation

#

also useless parens

raven ridge
#

@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.

proper remnant
#

o

raven ridge
#

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.

soft bone
#

Well, that package exists in PyPI as well if it matters.

raven ridge
#

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.

soft bone
#

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?

raven ridge
#

the only __init__.py I see there is in the tests

soft bone
#

the only __init__.py I see there is in the tests
@raven ridge right, because i don't need another one that package works fine.

raven ridge
#

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)

magic python
#

@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).

raven ridge
#

@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?

gloomy rain
#

What is the downside of adding custom exceptions supposed to be?

raven ridge
#

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)

desert peak
feral cedar
scarlet cave
#

okay

grave jolt
#

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?)

raven ridge
#

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.

desert peak
#

@grave jolt since they're always attached to a namespace (self), I think it's fine.

grave jolt
#

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

desert peak
#

anyone know a good way to run an async fn in a ctor?

raven ridge
#

I googled that last week and stackoverflow said "don't".

desert peak
#

I need to evaluate the coroutine results

grave jolt
#

like, if a Student has a class, no need to dance around that with klass or class_

raven ridge
#

restructure the code so the async stuff is done elsewhere.

grave jolt
#

you can make a lazy async method, for example

desert peak
#

well, the async stuff is part of the class

#

it's a thin wrapper around aiohttp.ClientSession

raven ridge
#

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

grave jolt
#

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()
peak spoke
#

Don't create unexpected interfaces, you can make an alternate method to construct the object or schedule it to be ran inside of it

grave jolt
#

or make a free-standing coroutine function, maybe?

#

but it depends, I guess

desert peak
#

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

raven ridge
#
class Connection:
    def __init__(self, sock):
        self._socket = sock

    @classmethod
    async def create(cls):
        return cls(await make_socket_somehow())
desert peak
#

so you're suggesting a factory instead of a ctor

raven ridge
#

yep. free function or classmethod, but yeah.

desert peak
#

I wonder if __new__ can be async

#

hm

grave jolt
#

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

flat gazelle
#

I guess you could also have a metaclass for async init.

grave jolt
#

or not unfortunately...

#

You could also make Connection awaitable, but that's kind of weird?..

desert peak
#

well here's what I have so far:

raven ridge
#

unfortunately, there are no private ctors in Python
@grave jolt psh, just use inspect to check who called you and raise if it wasn't your factory! /s

grave jolt
#
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

flat gazelle
#

Also, doesn't the thing you are wrapping use __aenter__ to do its async stuff rather than the constructor

peak spoke
#

you can make it use an async init with a metaclass as lakmatiol mentioned, but that's just confusing

desert peak
#
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

raven ridge
#

@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.

desert peak
#

creation of the object also happens in a sync-ctx before running the framework, however

raven ridge
#

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.

grave jolt
#

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__)?

desert peak
#

so leave the session uninitialized until first-use essentially?

#

or rather, without auth initialized

#

that is doable

rustic bone
#

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)

unkempt rock
unkempt rock
#

how od you guys feel about zip being okay with iterables of different lengths?

late widget
#

What's the issue with it?

unkempt rock
#

it doesnt seem consistent

#

normally you get an error for sequences of varying lengths

late widget
#

It's just consuming two iterators until one of them yields no more items

unkempt rock
#

yeah.

late widget
#

There's nothing wrong with that?

#

Its behaviour is well defined

unkempt rock
#

yeah but the behaviour itself isn't consistent

#

think about something like unpacking

#

!e

a, b = [1, 2,3]
fallen slateBOT
#

You are not allowed to use that command here. Please use the #bot-commands channel instead.

unkempt rock
#

You get a value error

late widget
#

Because that's not the same

unkempt rock
#

name any other example of python being okay with sequences of varying lengths

late widget
#

Why does that matter though? Unpacking and zipping are different operations

unkempt rock
#

theyre pretty much polar opposites

late widget
#

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)]
unkempt rock
#

so having consistency in how they deal with varying lengths makes sense

late widget
#

Why though? Then you've removed a huge portion of zips usage

flat gazelle
#

not everything zip works on has a length

late widget
#

^Also a very good point

unkempt rock
#

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

late widget
#

Again you're trying to draw a parallel between two different operations which just isn't really helpful

unkempt rock
#

but what im saying is that python is inconsistent here

late widget
#

Also @flat gazelle's point of they don't need a length

unkempt rock
#

okay? just check if one exhausts before the other

flat gazelle
#

you can't do that

unkempt rock
#

im not saying it has to have a dunder len

late widget
#

But you can't do that

#

Generators can't be re-run

unkempt rock
#

how can you not?

flat gazelle
#

the only way to check if there are more items is to try to get the next one

late widget
#

Unless you have a copy of the original before consuming its elements

unkempt rock
#

the only way to check if there are more items is to try to get the next one
@flat gazelle exactly.

flat gazelle
#

and if you do that, you now wasted an element of the iterator

unkempt rock
#

if you see that one generator raised an error but another didnt

#

then you should raise a ValueError

late widget
#
>>> 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)]
[]
unkempt rock
#

!pep 618 throwing this out here

fallen slateBOT
#
**PEP 618 - Add Optional Length-Checking To zip**
Status

Final

Python-Version

3.10

Created

01-May-2020

Type

Standards Track

flat gazelle
#

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]
unkempt rock
#

going to read that, brb

#

thats a great feature

#

although, its still optional

#

still seems slightly inconsistent but 🤷‍♂️

peak spoke
#

How would you handle infinite iterables if it weren't optional?

visual shadow
#

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

unkempt rock
#

im not saying i havent made use of zip like that, i have quite a lot of times. it just seems inconsitent.

flat gazelle
#

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
sacred haven
#

Anyone familiar with Celery workers?

gleaming rover
#

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 🤷‍♂️

unkempt rock
#

yo i have a problem with my python

#

this is the error code

fresh cargo
#

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."

brave badger
#

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

fathom cobalt
#
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?

mint forge
fathom cobalt
#

oh ok

#

sorry

gleaming rover
#

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

unkempt rock
#

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)] ?

dawn patio
unkempt rock
#

Thanks, @dawn patio. Having a read.

mint forge
#

if u mess with builtins.pyi will it affect how your code will run?

unkempt rock
#

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))).

peak spoke
#

pyi files are type stubs and aren't executed by anything when you run python normally on the py file

mint forge
#

ohh, i thought if i changed something there then it would change the entire python complier lol

clear anvil
#

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.

gleaming rover
#

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

tame pollen
#

thaank ya

unkempt rock
#

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.

dawn patio
brave badger
#

Due to how Python code is executed, yes, at that point (setting class-level attributes and methods), the class itself isn't defined yet

unkempt rock
#

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.

signal tide
#

put it outside the class?

unkempt rock
#

What would you suggest? Defining a global (!!) object named "origin" that holds a Point instance?

signal tide
#

if you're init'ing the origin within the class, it'll recursively call it

unkempt rock
brave badger
#

!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)
fallen slateBOT
#

@brave badger :white_check_mark: Your eval job has completed with return code 0.

0 0
signal tide
#

what's cls?

brave badger
#

The first argument for classmethods, similar as to how self is for regular instance methods

signal tide
#

also sticking self.point = (x,y) in there would probably be beneficial

#

ah

unkempt rock
#

That's pretty interesting @brave badger. I would be returning a new instance of Point though, for each call to origin, right?

brave badger
#

Yes, but you could implement caching/singletons in a fairly trivial manner

sacred tinsel
#

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>
unkempt rock
#

I will look into that. Thanks @brave badger.

sacred tinsel
#

but I'd just leave it in module namespace probably

unkempt rock
#

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)
dawn patio
unkempt rock
#

It's using a type annotation.

#

Optional. Has no influence on run time execution.

deft pagoda
#
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):
...
unkempt rock
#

The type annotation will instruct the IDE, linter, etc. that origin should store a "Point".

dawn patio
#

oh, got it, thanks

unkempt rock
#

Thanks, @deft pagoda. You will agree that's a lot of syntax for a very simple idea! I will look into meta-classes.

sacred tinsel
#

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

deft pagoda
#

there's other, arguably nicer, ways to cache

sacred tinsel
#

I'm not sure how type checkers would deal with it

deft pagoda
#

like with a decorator, for instance

unkempt rock
#

(I love this channel, lots of feedback and insightful comments. Thanks, folks.)

deft pagoda
#
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

sacred tinsel
#

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>
deft pagoda
#

that works

sacred tinsel
#

wait why didnt that error for me

#

it should be a string hasattr(cls, "_origin") right

deft pagoda
#

i think your decorators are backwards

sacred tinsel
#

ah I'm looking at the func objects

#

wait, is it even possible to have a classmethod property

deft pagoda
#

that's a 3.9 thing

fathom dirge
#

hi guyz

#

i'm new here

signal tide
#

actually speaking of classes but not really, how do you docstring dataclasses?

brave badger
#

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

signal tide
#

see I tried that but the args are undefined

#

idk if that's just pycharm but I can't get a preview

brave badger
signal tide
#

ah for sure

wide shuttle
#

!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)
fallen slateBOT
#

@wide shuttle :white_check_mark: Your eval job has completed with return code 0.

001 | Point(x=0, y=0)
002 | True
wide shuttle
#

The origin is cached at the type level by the way, the metaclass _origin is just a convenient default value

sacred tinsel
#

nice yeah that makes sense

grave jolt
#

(and we'll hope that noone mutates Point.origin lemon_scared )

wide shuttle
#

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

grave jolt
#
o1 = Point.origin
o1.x = 2945204059
#

maybe make it a dataclass(frozen=True)?

wide shuttle
#

right, that's true

grave jolt
#

I think it makes sense to make points immutable

wide shuttle
#

Do points ever mutate?

#

Yeah

grave jolt
#

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
wide shuttle
#

I don't know! Let's try.

fallen slateBOT
#

@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
grave jolt
#

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!!!"
fallen slateBOT
#

@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'
grave jolt
#

yep

deft pagoda
#

!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))
fallen slateBOT
#

@deft pagoda :white_check_mark: Your eval job has completed with return code 0.

Point(x=0, y=0)
tacit hawk
#

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.

languid dagger
#

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

grave jolt
#

because some classes can contain themselves recursively, like Cons(1, Cons(2, Cons(3, Cons.Nil)))

languid dagger
#

I like that a bit more than doing 0, 0 in the call args

tacit hawk
#

Add data files to MANIFEST.in and set include_package_data=True in setup()

grave jolt
# languid dagger I like that a bit more than doing `0, 0` in the call args

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))

radiant scroll
#

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
undone hare
#

Because the logical and operator will operate on boolean values and won’t use any dunder

radiant scroll
#

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

undone hare
#

I understand, you should check out the channel topic then

#

This channel is for discussions, but not for helping

radiant scroll
#

But I'm not really asking for help, I'm just curious as to why it was implemented this way

tacit hawk
#

I thought help channels were meant for questions that requires long answers

radiant scroll
#

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

unkempt rock
undone hare
undone hare
unkempt rock
#

Optimization?

undone hare
#

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')```
unkempt rock
#

I thought the point of and was to work for any value and return the last truthy value

fallen slateBOT
#

@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
unkempt rock
#

or the first falsy value

undone hare
#

(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')```
fallen slateBOT
#

@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
undone hare
#

Do you see how this is way more optimised than if you had to load True and False onto the stack?

radiant scroll
#

hmm, I see, I suppose that makes sense

delicate sorrel
#

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

fresh cargo
undone hare
#

Let's see

#

!e

import dis

dis.dis('b if a else a')```
fallen slateBOT
#

@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
undone hare
#

Yup, that's less optimized, you load a twice here

sacred yew
#

@radiant scroll & and and are 2 different things

#

& is bitwise

#

and is logical

raw jetty
#

Pretty advance stuff right there

signal tide
#

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?

grave jolt
#

@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):
    ...
signal tide
#

ah ok ya I was hoping that wasn't the case

#

I think I'm just going to add a case

grave jolt
#

why not make it the second variant?

signal tide
#

like if x is None and...

#

uh I can't really spilt it up

grave jolt
#

Can you show your function?

signal tide
#

I could but it would overcomplicate it a bit

grave jolt
#

I'll try to figure it out

signal tide
#

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

grave jolt
#

I think this is better suited to a help channel

#

claim and ping me

radiant fulcrum
#

those inline else blocks though

signal tide
#

I had to reformat it or the bot would've picked up on it

tulip hazel
signal tide
#

does overloading not have a 3.9 implementation?

boreal umbra
signal tide
#

ya, the decorator is there but I can't use before/after

#

pip'ing it gets the 3.8 vers

boreal umbra
signal tide
#

I have no clue

boreal umbra
#

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.

signal tide
#

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

boreal umbra
signal tide
#

that's what I had give or take..

boreal umbra
#

Sounds fine to me

signal tide
#

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

boreal umbra
#

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.

signal tide
#

also rip my frequency graph

raven ridge
#

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

brave badger
#

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

raven ridge
#

I'm not too fond of mypy 😄

boreal umbra
raven ridge
swift imp
#

what dont you like

#

Or what do you find limiting?

raven ridge
#

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.

swift imp
raven ridge
#

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.

swift imp
#

maybe not to you LOL

raven ridge
#

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.

swift imp
#

oooh ok

#

ok

#

I think I see

#

Well I feel like you need a singleton pattern in this case

boreal umbra
#

@raven ridge what would you think of a "null argument" special value that serves no purpose but to be the default argument sentinel

raven ridge
#

how would it tie into the actual language, as opposed to typing?

swift imp
#

Like if you really want to check for the exact instance of _RAISE and not its type, why not make _RAISE a special singleton

raven ridge
#

the singleton pattern is a hack to get globals into pure OOP languages.

swift imp
#

Well what else r u supposed to do

raven ridge
#

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

swift imp
#

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

raven ridge
#

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

swift imp
#

So we've come full circle. Fair enough. Good Talk.

raven ridge
#

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

unkempt rock
#

randomheart = (random.randint(goodheart1,goodheart2,goodheart3,goodheart4,goodheart5,goodheart6))
how do you choose a random one from all of them?

mint forge
signal tide
#

tbh I might just split the method into separate ones for each arg

signal tide
grave jolt
#

@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

cloud crypt
#

mypy is not so smart and evil

raven ridge
#

I haven't tried pyright yet, though I do want to try

grave jolt
#

it even supports recursive type aliases lemon_exploding_head

cloud crypt
#

oh finally

#

lol

#

does it support code generation classes though hehe

grave jolt
#

that's... too much to ask, I guess 🙂

cloud crypt
#

do

#

do

#
level_type: LevelType = LevelType.DEFAULT``` and mypy be like _expected LevelType, got int_
grave jolt
#

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?

cloud crypt
#

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

grave jolt
#

well, it's totally reasonable that a typechecker is unable to introspect some of the magic stuff 🙂

#

dataclasses, namedtuples and enums are all hardcoded

cloud crypt
#

mmm awesome

tacit hawk
#

Do you all prefix "private" vars with underscore?

raven ridge
#

Yep

tacit hawk
#

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

undone flame
#

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.

grave jolt
#

an alternative would be to just pass an immutable object from the start 🙂

#

list -> tuple
set -> frozenset
dict -> immutables.Map

paper echo
#

@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

grave jolt
#

well, for example, Clojure runs on the JVM, which might explain it

peak spoke
#

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

crimson wedge
#

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?

grave jolt
#

Are you sure the OS will allow you to do that?

crimson wedge
#

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

swift imp
#

@paper echo you like attr over dataclasses?

spark magnet
#

@swift imp many people prefer attrs

swift imp
#

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

grave jolt
#

some people prefer pydantic.BaseModel, I suppose lemon_scared

spark magnet
#

@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.

swift imp
#

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?

raven ridge
#

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.

paper echo
#

@swift imp backward compat to 3.6 is somewhat nice, more functionality in general, slots=True and better performance

raven ridge
#

if you use sys.exit it will.

swift imp
#

Thanks

sonic citrus
#

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

mint forge
sonic citrus
#

Sure I posted there

junior wedge
#

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!

sacred yew
#

this is not a help channel

junior wedge
#

I know

#

I wanted opinions

sacred yew
#

yes

#

and this is the wrong channel

#

this is for meta discussion about python itself