#internals-and-peps

1 messages · Page 89 of 1

grave jolt
#

those two must be the same, because a "coroutine function" is just a function that returns a coroutine.

glad shoal
#

In my specific use case it would simply make the API easier to use. def parse() and async def parse() both parse objects, but async def parse() can also parse coroutines.

#

It's not a problem that I'm depedent on and need to fix, but it was one of those things that I came across and got addicted to the problem

grave jolt
#

Well, it just doesn't work with Python semantics, in the same way that you can't create a decorator that works differently on an instance method and on a freestanding function; or on a normal function and a generator function

glad shoal
#

That's my assumption of it as well. You can bootleg a solution, but nothing viable from my research.

grave jolt
#

The main reason it's not possible is that x = func() on an async function is a totally reasonable thing to do. For example, in create_task(func()).

raven ridge
#

I'd say it's more like how you can't make a function that decides whether to return an int or a string depending on whether its caller wants an int or a string. It's both not possible in the data model, and not a sensible thing to do.

raven ridge
#

for taking different argument types, sure. Not for returning different types.

glad shoal
grave jolt
#

I have seen that (return type dispatch) actually used in some graphics library in Rust, I think piston

grave jolt
glad shoal
#

But even then, inspect is not a module I take any pleasure in working with knowing it's not scalable

grave jolt
#

yep

raven ridge
# glad shoal I agree it's not a sensible/logical thing to do, but confused on why it would no...
def foo():
    if caller_wants_int():
        return int(some_var)
    return str(some_var)

def caller1():
    return foo() + 3

def caller2():
    return foo() + "bar"

def caller3():
    return foo() + foo()

Alright, let's imagine that you can figure out that caller1 wants an int, and return an int to it, and you can figure out that caller2 wants a str and return a str to it - by parsing the bytecode of your calling frame and seeing how the result is used, or whatever. What would you do for caller3?

grave jolt
#

like

def g(x: int):
    ...

def h(x: str):
    ...

g(f())
h(f())
glad shoal
# raven ridge ```py def foo(): if caller_wants_int(): return int(some_var) ret...

My assumption was that you simply pass a flag to foo() dictating the return type beforehand. My hope was that await was similar to passing such flag, but the more I've researched, the more I've come to the realization it's not possible. The problem irks me for this reason, and while I don't research it, it would be lovely to find that it's actually possible

#

In other words, my hope was that await func() would set a flag on the call to func() that can be accessed on runtime

grave jolt
#

It's not just await. There are legitimate reasons to call a coroutine function to get a coroutine.
Like I said,

task = create_task(async_function())
deft pagoda
#

i'm only half paying attention, but curio has a decorator that allows a function to be called as a coroutine or a normal function

#

if that's what you're after

glad shoal
deft pagoda
#

beazley is like the simpsons in that he probably has code for it already, whatever it is

glad shoal
#

Let me read through this source code. I have a solution, but it uses inspect.

glad shoal
#

Thank you for the share. Let me check it out

grave jolt
#

well, this uses inspect, of course

#

also

# curio/meta.py
#     ___
#     \./      DANGER:  This module implements some experimental
#  .--.O.--.            metaprogramming techniques involving async/await.
#   \/   \/             If you use it, you might die. No seriously.
#
deft pagoda
#

it uses inspect to make sure signatures match

glad shoal
deft pagoda
#
if inspect.signature(syncfunc) != inspect.signature(asyncfunc):
            raise TypeError(f'{syncfunc.__name__} and async {asyncfunc.__name__} have different signatures')
deft pagoda
#

i mean, that's a reasonable use case for inspect

glad shoal
#

Indeed it is. Another sad day

grave jolt
grave jolt
glad shoal
#

Thank you for the share @deft pagoda

grave jolt
#

but still, it's a hack that is only guaranteed to work in CPython, and it's a very unexpected API tbh

raven ridge
#

it's not even "guaranteed" to work in CPython; it depends on implementation details

feral cedar
#

why are comments borderline invisible on mobile. I thought it was just a blank box

glad shoal
#

Haven't heard of this library, but something that might come handy in the future. Was planning on using asyncio.stream and asyncio.protocol for some networking purposes. Will be staring this to look into it further when I get the time.

deft pagoda
#

i don't think the api is unexpected -- it's pretty well documented

grave jolt
#

It's unexpected as in: what else behaves like that?

raven ridge
#

I think it's quite unexpected to have a function change its behavior based on the context that it was called from, full stop

glad shoal
deft pagoda
#

i thought there was a function being released in a new version of python that detects context without the frame hack

glad shoal
grave jolt
#

Well, that's possible in some statically typed languages when it's unambiguous

glad shoal
#

An interesting thought. It would allow some interesting use cases.

deft pagoda
#

i can make the above snippet work

#

in a class definition at least

grave jolt
#

e.g. in Haskell there's a read function, which is like input, but it automatically converts the string to the given type (i.e. it's like the inverse or repr in Python)

glad shoal
raven ridge
grave jolt
#

That's undefined, I suppose. Just like x = func()

glad shoal
deft pagoda
#

unspecified

glad shoal
#

Undefined would be a good route, or function defaults to certain output.

raven ridge
#

yeah, I think all of that is terrible. 😄

glad shoal
#
def func() -> Default[int], Union[int, str]

(non working, ofc, but you guys get the point, hopefully)

deft pagoda
#

i think that's the best part

grave jolt
glad shoal
grave jolt
glad shoal
#

A different set of paradigm to work with, but an interesting one nonetheless.

grave jolt
#

There are also very fun functions returning an arbitrary type, like error :: String -> a, but Python uses NoReturn for that

glad shoal
#

I'm afraid I've never looked into Haskell (despite folks saying it's a good language to learn for it's weirdness), so I can't comment on the photo, or the examples

#

Perhaps, however, (despite having no knowledge or ever having used it), MyPy might be able to fill this void.

#

Is it MyPy? I believe I might be thinking of something else.

#

My apologies if not.

deft pagoda
#

!e

PROP = object()

class ContextMatters(type):
        def __new__(meta, name, bases, methods):
            ann = methods["__annotations__"]
            for attr, val in methods.items():
                if val is PROP:
                    methods[attr] = ann[attr]()
            return super().__new__(meta, name, bases, methods)

class Test(metaclass=ContextMatters):
    x: str = PROP
    y: int = PROP

print(Test().x, Test().y)
fallen slateBOT
#

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

 0
deft pagoda
#

i guess printing an empty string isn't fun

glad shoal
#

Another random thought, and another library I've not exhausted in my own use cases to know it enough. Can you modify runtime executions via the ast module?

deft pagoda
#

maybe in combination with, like, ctypes? i'm guessing though

#

can compile some ast into byte code and replace something in memory

glad shoal
#
def func():
    return hello

This builds on compile time. Can, then, one modify the runtime context of func() to give meaning to hello?

#

and therefore be able to create weird non-Python contexts?

deft pagoda
#

i mean, once again, it's sort of a trivial thing to do in a class body

glad shoal
#

I would assume on file as well, with such example, via globals. But say the following:

def func():
  return (15)2

Where (15)2 is equivalent to 15*2.

#

A random fleeting thought I've had in the past when minimally working with AST.

deft pagoda
#

!e

from itertools import count

class IncrDict(dict):
    def __init__(self):
        self.counter = count()

    def __missing__(self, key):
        if key.startswith('__'):
            raise KeyError(key)

        self[key] = next(self.counter)
        return self[key]

class EnumMetaclass(type):
    def __prepare__(*args, **kwargs):
        return IncrDict()

class Enum(metaclass=EnumMetaclass):
    ...

class Fruit(Enum):
    APPLE
    BANANA
    KIWI

print(Fruit.APPLE, Fruit.BANANA, Fruit.KIWI)
fallen slateBOT
#

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

0 1 2
glad shoal
#

You know your metaclasses my friend. Hats off to you

#

Hell, you know your Python.

deft pagoda
#

i'd like python a lot less if it didn't have all this weird magic in it

glad shoal
#

My love affair only started a few months ago when I began diving deeper into its core

#

I understand your sentiment

#

Nowhere near as proficient

#

But, regardless of your knowledge, the real question still is: can you solve a Leetcode problem in 30 minutes with 3 interviewers talking to you at the same time?

deft pagoda
#

definite maybe

glad shoal
#

It's a joke

#

But for sure

raven ridge
fallen slateBOT
#

@raven ridge :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 2
002 |     (15)2
003 |         ^
004 | SyntaxError: invalid syntax
raven ridge
#

I mean, you could certainly build your own parser that could make that work, but you can't use Python's, because it can only parse stuff that's valid Python code

mint forge
#

this is so cool

livid geyser
#

I once used that with some esoteric hackery to almost completely break my shell (it still works, just requires some esoteric hackery)

#

I forgot what exactly I did but I can probably find it

mint forge
#

the thing with what i was doing is that [] still works

livid geyser
#
import sys
sys.meta_path.clear()
sys.modules.clear()
#

@mint forge

#

So not quite that but the same effect

#

Every time you run a valid python statement it tells you that it's lost the builtins module

mint forge
#

lol

livid geyser
#

I don't think that actually clears sys.modules though

#

Oh wait it does but it breaks at that point

mint forge
#

very cool

livid geyser
#

Anyway yeah the shell is basically unusable except that running print() still works

#

I suppose if I combine this with del builtins.xxx that could totally destroy it

mint forge
#

do it

livid geyser
#
import builtins
_del = delattr
for i in dir(builtins):
    _del(builtins,i)

del _del
import sys
sys.meta_path.clear()
sys.modules.clear()
#

Oh bugger I delete delattr lol

mint forge
#

ye lol

#

i got the same thing

#

hahah, but cool nonetheless

livid geyser
#

Oops I just killed my shell because I forgot I already killed python

#

oh crap I broke xonsh

mint forge
#

lol i can't quit cause it's deleted

livid geyser
#

Ctrl-D?

mint forge
#

i closed the cmd

livid geyser
#

Oh that's windows

#

Ctrl-Z

undone hare
#

Haha

livid geyser
#

Really? What version?

undone hare
#

Can’t exit

mint forge
#

3.8.5

livid geyser
#

It 'works' in py380

undone hare
#

Trapped for eternity

livid geyser
#

Weird

#

Wait not my py38 is 385

#

The heck

#

Oh wait I deleted __import__ too so the sys hack doesn't work lol

#

This esoteric code is becoming esoteric

mint forge
#

yep but it is cool ngl

livid geyser
#
import builtins
_del = delattr
_imp = __import__
for i in dir(builtins):
    _del(builtins,i)

del _del
sys = _imp('sys')
sys.meta_path.clear()
sys.modules.clear()
del _imp
del sys

should work

#

I think deleting globals breaks everything

mint forge
#

in ipython it just exists out

livid geyser
#

LOL probably because I literally broke 99% of the repl

#

ImportError: __import__ not found

#

🤔

mint forge
#

that still gives me module not found

livid geyser
#

CPython?

mint forge
livid geyser
#

Because you wrote it wrong lol

#

It's dir(builtins)

mint forge
#

ah ok

livid geyser
#

You should be able to just paste my message

#

Note that for some reason it doesn't think _imp is defined - I think it's because I'm deleting globals

mint forge
livid geyser
#

Yup

mint forge
#

very cool

#

deleting builtins is fun

#

haha

livid geyser
#

You should be able to del _imp and del sys now to completely destroy any chance of doing anything in that shell

mint forge
#

it's already deleted

livid geyser
#

If anyone finds a way out of this I'll be very surprised

#

There's no way of giving any output

mint forge
#

oh wiat it is

#

right

#

amazing

livid geyser
#

I've deleted both open and print, as well as __import__

pliant tusk
#

It is possible to recover from that

livid geyser
#

There should literally be no way out that isn't more esoteric than the way we got here

mint forge
pliant tusk
#

You can traverse the subclasses of object to get an importer that works

livid geyser
#
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'object' is not defined
mint forge
#

haha

livid geyser
#
... 
>>> Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: __build_class__ not found
pliant tusk
#

().__class__.__base__

mint forge
#

lost builtins module

livid geyser
#

Works if you assign it to a

#

The lost builtins module just means you can't repl-print

mint forge
#

right, so how to go about recovering after doing that

livid geyser
#

I think I broke the autocomplete lol

pliant tusk
#

@livid geyser you can do dir = lambda o:o.__dir__()

livid geyser
#

There's no way to print it though

#

I just opened another shell lol

pliant tusk
#

or you can do type = ().__class__.__class__ then dir = lambda o:type(o).__dir__(o)

#

once we get back open we can print

mint forge
#

break python then rebuild it, wow

clear kindle
#

My bad, sorry

livid geyser
# pliant tusk once we get back `open` we can print

I don't see any of ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__'] helping us here

#

This really is an esoteric escape lol isn't it

pliant tusk
#

yes

livid geyser
mint forge
#

take me with you

pliant tusk
#

you need to think creatively to recover a shell from this point

paper echo
#

has there been a PEP to deprecate string literal concatenation, like "a" "b" --> "ab"

#

or a mailing list thread at least

astral gazelle
#

Why would they?

peak spoke
#

Mostly a useful thing from my experience

astral gazelle
#

Same, with multiline strings

undone hare
#

Also, this would break way too much code

paper echo
#

in my experience it's just a source of bugs

#

i don't know any cases where i would write "a" "b" or ```python
"a"
"b"

and where i couldn't just write `"a" + "b"` or ```python
"a" +
"b"

instead

#

i know a lot of code uses it

#

but that doesnt mean its a good feature

#

it makes sense in C where the whole idea of concatenating strings isnt easy due to memory allocation

undone hare
#

The first one will error out in most cases though

astral gazelle
#

I've been using it with \ tbh

"a" \
"b"

Isnt this proper usage?

#

Or is it /, can never remember

peak spoke
#

It's \, but you should mostly use the implicit line continuation in parentheses instead of that

paper echo
#

yeah you would need line continuation outside of parentheses

#

this is used often in Scikit-learn source for example when formatting error messages

#
    raise FooError("This is the error message "
                   "that is shown to the user.")
#
    raise FooError("This is the error message " +
                   "that is shown to the user.")

but really would this be so bad?

peak spoke
#

I find the concat a big ugly, while it can be confusing at times when you forget it, the benefit of being able to split strings where you want to fit into your col limit is much better imo

paper echo
#

meanwhile if you meant to write

    raise FooError("This is the first arg",
                   "and the second arg")

but accidentally deleted the , you get weird output and maybe not an error

astral gazelle
#

It looks terrible

#

Half of the appeal of python is well, its appealing

paper echo
#

the trailing + is that bad?

astral gazelle
#

IMO yes, comma looks better

unkempt rock
#

comma looks better? They do different things

#

The comma is separating the two strings into two arguments

astral gazelle
#

To be printed tho, no?

#

FooError(*args)

#

Thats what i was thinking anyway

#

Idk why my mind immediately went to print

sacred yew
#

they do different things

#
In [32]: raise IndexError("a","b")
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-32-0ede76577b9c> in <module>
----> 1 raise IndexError("a","b")

IndexError: ('a', 'b')

In [33]: raise IndexError("ab")
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-33-03f3d98fed63> in <module>
----> 1 raise IndexError("ab")

IndexError: ab
unkempt rock
#

Ah, print

astral gazelle
#

Hmm okay, nevermind, i misread that, dunno why i thought of print tbh

#

But still if they did the same thing comma looks better lmao

paper echo
#

yeah that's not the point im making

#

the point is that concatenation of string literals doesn't really benefit anyone and creates a new category of bugs that sometimes can be hard to identify

undone hare
#

Being able to split a string on many lines without operators is very useful though

paper echo
#

i guess, i just dont see the ability to omit + as something particularly important

vagrant spire
sacred yew
vagrant spire
sacred yew
#

thats not what happens when you run the code

#

thats linter warnings telling you your code style isn't the best

#

are you using tabs?

vagrant spire
#

no

feral cedar
#

are you just pressing space 3 times

vagrant spire
#

so what I should to do now

sacred yew
#

how are you indenting the code

#

tab key?

feral cedar
#

is that pycharm?

vagrant spire
#

yes its pycharm

feral cedar
#

then reindent file with spaces, i think

vagrant spire
feral cedar
#

also, this isn't on topic for this channel

#

but, there should be a button to fix your indenting somewhere

vernal narwhal
raven ridge
#

AFAIU the advantage of implicit string concatenation is that it's done at compile time, not runtime. Explicit concatenation with + would need to be done at runtime, and cost some performance.

peak spoke
#

as long as it's not very long, the concat will also be done at compile time

#
In [2]: dis.dis("'string' + 'anotherstring'")
  1           0 LOAD_CONST               0 ('stringanotherstring')
              2 RETURN_VALUE
raven ridge
#

Mm, fair enough. How long is "very long"?

#

People usually don't do this until they're over a line length limit, so 60 characters or so for the first string literal

paper echo
#

that is a good point

peak spoke
desert peak
#

not what this channel is for

swift imp
#

I want to dynamically define a class with a custom meta, how do I do that?

#

Like you can do type('Name', (object,),{}) but if I want to have a specific metaclass how do I do that?

#

Also if i wanted to pass the kwargs to __init_subclass__?

modern night
#

if you want to dynamically choose a metaclass i think you need to replace type with the metaclass of choice, i'm not sure about the __init_subclass__ part though

swift imp
#

Apparently it's types.new_class

modern night
#

thats probably the intended way but looks like my suggestion may also work ```py
class Meta(type):
def new(mcs, name, bases, cls_dict: dict):
dict_ = dict(zip(cls_dict.values(), count()))
return type.new(mcs, name, bases, dict_)

x = Meta("MyClass", (), {1: "foo", 2: "bar", 3: "baz"})

x.foo
0
x.bar
1```

deft sky
#

How do you guys define complicated app structure which has its own data to be represented into the interface?
Do you guys hold single data as an object in the program or something then representing it into the UI?
I'm just asking opinion, to see if there's useful explanation or designing methods i can get.

undone hare
unkempt rock
#

would a snake game work on discord using reactions for controls?

feral cedar
#

probably would be too slow to play

#

rate limits and lag

unkempt rock
#

yeah i thought so

covert cape
#

i'd seen someone do it in the discord.py server though

#

and yes, the lag was definitely there

#

didn't turn out as bad as i'd have though (off-topic for here i realize)

swift imp
#

Is it true you still need to inherit from object to utilize __slots__?

#

I can't find anything about it under the data model but a rather well voted SO says it has to

spice pecan
#

I don't think you can not inherit from object in Py3

swift imp
#

Oh, I suppose that makes more sense

spice pecan
#

If no parents are specified, object is implicitly filled in

swift imp
#

But if I am inheriting from a class with a custom meta?

spice pecan
#

object would still be there in the inheritance hierarchy

swift imp
#

I guess that parent inherits from object?

#

Ok

swift imp
#

About to start slotting all my classes bc why not if I dont need dynamic attributes?

raven ridge
#

Because it's premature optimization, and will surprise users of your classes

swift imp
#

Yeah I decided not to

#

In my current project I decided to limit to cases where the property I have on the class access some class attribute, which I think is appropriate

#

Which was 2 classes

mellow gale
#

what is regex used for in python, i know you can find patterns of text like a phone number like 000-000-0000 but anything else?

limpid marten
#

Pattern matching text is very useful.

frigid trout
#

For example how @fallen slate's eval command sees a code block

boreal umbra
frigid trout
#

Yeah I was saying that @fallen slate uses regex to find the code block if there is any, I wasn't asking how python eval command works.

night wolf
#

not sure if this is the correct place for this but can someone explain this behavior:

#

!e

foo = 'outer'
class Test:
    foo = 'inner'
    bar = foo.upper()
    baz = [foo.upper() for _ in range(2)]

print(Test.bar)
print(Test.baz)
fallen slateBOT
#

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

night wolf
#

well it prints

001 | INNER
002 | ['OUTER', 'OUTER']
swift imp
#

I have no idea why the list comp uses the scope outside the class

gleaming rover
#

hm

#

that is weird

deep bramble
#

that's very odd

gleaming rover
#

the inner scope isn't even visible to the comprehension...?

#

!e

class Test:
    foo = 'inner'
    baz = [foo.upper() for _ in range(2)]

print(Test.baz)
fallen slateBOT
#

@gleaming rover :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 1, in <module>
003 |   File "<string>", line 3, in Test
004 |   File "<string>", line 3, in <listcomp>
005 | NameError: name 'foo' is not defined
night wolf
#

whattt

deep bramble
#

ok that's a lot weirder that I thought

night wolf
gleaming rover
#

oh, hm

#

I see

flat gazelle
#

Listcomps are implemented partially atop functions, and just like methods don't see class scope, neither do they. It is somewhat unexpected though

grave jolt
#

yeah

#

!e

import dis

def f():
    return [x*x for x in y]

dis.dis(f)
#
  4           0 LOAD_CONST               1 (<code object <listcomp> at 0x7f3cfedd27c0, file "<string>", line 4>)
              2 LOAD_CONST               2 ('f.<locals>.<listcomp>')
              4 MAKE_FUNCTION            0
              6 LOAD_GLOBAL              0 (y)
              8 GET_ITER
             10 CALL_FUNCTION            1
             12 RETURN_VALUE

Disassembly of <code object <listcomp> at 0x7f3cfedd27c0, file "<string>", line 4>:
  4           0 BUILD_LIST               0
              2 LOAD_FAST                0 (.0)
        >>    4 FOR_ITER                12 (to 18)
              6 STORE_FAST               1 (x)
              8 LOAD_FAST                1 (x)
             10 LOAD_FAST                1 (x)
             12 BINARY_MULTIPLY
             14 LIST_APPEND              2
             16 JUMP_ABSOLUTE            4
        >>   18 RETURN_VALUE
#

It's sort of like

def f():
    def _listcomp(.0):
        rv = []
        for x in .0:
            rv.append(x * x)
        return rv
    return _listcomp(y)
ivory gorge
#

Hi everyone

#

I am trying to put together a simple app together as a project that I have to deliver as I am studying.
#my knowledge with python is very little still. I am having issues with an error related to json when I try to test it using postman

#

If I share with you guys my issues would anyone please give me some help ?

mint forge
desert whale
#

What is the reason for the lines in the disassembly of that code above is only made from even numbers/factors of 2?

grave jolt
desert whale
#

Oh okay

grave jolt
#

so that's the relative address of each instruction

desert whale
#

👍 thanks for clearing that up

glad shoal
#

Anyone here got tips for creating an extension system for existing projects?

Looking for something that specifically allows me to extend a singledispatch classmethod function. In other words:

Project:

class Foo:
  @singledispatchmethod
  @classmethod
  def bar(cls, msg: str):
    print("str", msg)

Plugin:

pip install plugin

Plugin.py:

def bar(cls, msg: int):
  print("int", msg)

Foo.bar.register(bar)

Does not need to use singledispatch, but the idea is to use create a secondary function with a different type, registered by this plugin via pip install. The idea of loading the plugin via Project is trivial, but registering the function is my issue.

spice pecan
#

There's singledispatchmethod which ignores the first argument IIRC

#

I'd assume it would work for classmethod as well

glad shoal
#

Yes, so sorry, meant to write singledispatchmethod.

swift imp
#

Anyone have a book recommendation on useful patterns written in python

regal oxide
#

quite quite

earnest juniper
#

hi i have a hard time knowing when to use method and when to use functions

#

is there a rule of thumb of when to use which?

deep bramble
#

method is asociated with an object (class)

#

method is a function, it just belongs to and object

#

the only real difference that with method, the object will be passed to it as an argument

#

(that's the self)

earnest juniper
#

hm ok for instance if a have multiple objects(class) with different int(values), and i want the program to return the highest value. And with that I use a for loop, do i use the for loop within method or function?

deep bramble
#

if a function only takes those ints as parameters, it's just a function, it's only a method if you were to actually extend the int class itself and use it there

#

i.e.:
This would be a method (in this case a static one, because we aren't taking self) ```py
class extended_int(int):
@staticmethod
def max_from_sequence(*ints):
...

This would just be a fuction```py
def max_number(*ints):
  ...
#

it's not a mistake if you called method a function, because it is a function, but you can't call any function a method, only those that belong to certain objects

earnest juniper
#

ok thx!

undone hare
#

The rule of thumb is that everything is a function, and function bound to a class are methods

wide shuttle
#

That's almost right

#

When you create a function inside of a class definition, you will "just" create a regular function, because that's what the statement does, but because you're doing that in the definition of a class, you assign a class attribute to the function instead of a regular name.

#

When you then access that function as an attribute on an instance, you'll get a bound method, as functions are descriptors

#

They have a __get__ method and that takes care of binding the instance to the function to create that "bound method"

#

!e

class MyClass:
    def my_function(self):
        print("hello!")

print("Regular function object:", MyClass.my_function)

my_instance = MyClass()
print("Accessing the attribute through an instance gets you a bound method:", my_instance.my_function)
fallen slateBOT
#

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

001 | Regular function object: <function MyClass.my_function at 0x7f840e9c6940>
002 | Accessing the attribute through an instance gets you a bound method: <bound method MyClass.my_function of <__main__.MyClass object at 0x7f840e9d3f10>>
tacit hawk
#

is isinstance(instance, Type) equivalent to Type in type(instance).mro()?

lofty rover
#

I'm running across the following issues: some clients want to run a python script with syncs local changes in an excel sheet with an API. The client is non-technical, so they dont really understand a CLI. I'm thinking about creating either a scheduled task using win 10 scheduler (and letting the IT guy set it up) which runs the python script every X hours, or creating an exectutable python file which will be idiot proof. Curious to hear opinions about one or the other, or another possibility.

#

Is using something like pyinstaller even best practice?

spice pecan
grave jolt
#

yeah

#

for example, you can have isinstance(x, T) for types from collections.abc, even though they have no direct instances

#

!e

from collections.abc import Sequence

print(isinstance([1, 2, 3], Sequence))
fallen slateBOT
#

@grave jolt :white_check_mark: Your eval job has completed with return code 0.

True
magic python
#

how does one find out what was used in order for something to be done? for example, with a string comp such as s = '', if s ... then s will be False because it's empty, but I don't understand what was used for this to be done. Looking at dir(s) isn't clear either, I expected somethign along the lines of __bool__ in there, but didn't see it

#

i tried dis.dis(s == True), but this throws TypeError: don't know how to disassemble bool objects, so I'm not sure how to find out what it is which enables s = '' to be evaluated as false

visual shadow
#

the key is to recognize that if is the statement doing the actual invocation/work, and so s may not necessarily expose the mechanism itself

magic python
#

oh, anything with __len__ will eval to False if len ==0 🤔

visual shadow
#

so you need to dig/find out from the angle of what if is doing instead.

#

Exactly

magic python
#

it's not clear how i'd find out what the if is doing under the hood, dis is (presumably) not the right approach

#

or is it just something that you know / search for in a doc / or don't know

visual shadow
#

not always. statements are usually the annoying ones. this is where googlefu helps a lot

#

Once you know where to look, then you can begin.

magic python
#

yeah i was coming up short there 😦

unkempt rock
#

Hi I just joined this server, do you guys have any suggestions of which programming app I should use?

#

I have recently started learning Javascript

magic python
#

@unkempt rock read the topic

unkempt rock
#

I did

magic python
#

you're in the wrong channel then aren't you

unkempt rock
#

sorry

visual shadow
#

for example, in checks for membership, but you may not necessarily see which mechanism it defaults to by just inspecting the objects themselves. Although it can help at times, since python is pretty good with names for its dunders

swift imp
magic python
#

Maybe it's just a case of reading the docs 😅

swift imp
#

Yeah lol

#

You could look at the object dict and see if both bool and Len are implemented

clear jacinth
#

Hi there. Thinking about * usage in function parameters. I noticed that devs use it to enforce argument names. I cannot find official feature discussion. And wondering if this is the right usage for it, since it does not look like a Pythonic way of doing stuff. To me it looks like a hack

def foobar(foo, * bar):
   print(foo, bar)

foobar('foo_var', bar='bar_var')
unkempt rock
#

!pep 3102

fallen slateBOT
#
**PEP 3102 - Keyword-Only Arguments**
Status

Final

Python-Version

3.0

Created

22-Apr-2006

Type

Standards Track

peak spoke
#

Any reason you think it looks like a hack?

clear jacinth
#

thanks @unkempt rock !
@peak spoke It's an implicit way of restricting user from passing keyword arguments into the function without providing names for them

peak spoke
#

How is it implicit? You have to use the specific syntax and will get a clear error if you try to use the function's interface improperly. Being able to specify kwarg only args (and positional only) is important to keep the code readable from the caller's side, and it must have the split if you use varargs

clear jacinth
#

Isn't keeping the code readable not the responsibility of the caller's side?

visual shadow
#

let's address the two separate questions separately. First, it's explicit. Implicit would mean there's no clear indication and/or the default approach without extra syntax would behave this way. But we know that the default behaviour allows both keyword and positional args

#

Second, keeping code readable is definitely the responsibility of everyone who writes code, both callers and the library makers.

peak spoke
#

Keeping their code readable is their responsibility, and having to specify it with a name is much clearer than just passing in True for example. It also helps keep the API stable between versions as moving around positionals changes behaviour but kwargs don't care about that

visual shadow
#

It's the same reason why python has some really idiomatic syntax. If the language makers decided that the responsibility was solely on the code writers, it wouldnt be necessary to incorporate some of the very things that make python great now.

#

So, enabling good code is a noble pursuit, and people who create code for the sake of consumption should keep it in mind

#

I think boolean flags are a great example for this specific feature. if i have a param that takes 3 boolean flag with some default values, it will be very confusing and potentially error-prone trying to rely on just positional args for them

#

keyword args are also great for when the API is still under flux, and more params may be introduced down the line

#

Forcing args to be keyword only allows the API makers to have the freedom to add args in an order that perhaps looks logical or makes sense

#

without breaking the existing code bases

clear jacinth
#

thank you for sharing your knowledge @visual shadow @peak spoke . I understand it now

visual shadow
#

anytime!

chilly thistle
stiff portal
#

anyone know if you can access **kwargs without looping trough them, like kwargs.key?

boreal umbra
#

!e

def thingy(**mabob):
    print(mabob)

thingy(a=1, b=2, c=3)
fallen slateBOT
#

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

{'a': 1, 'b': 2, 'c': 3}
boreal umbra
#

calling it kwargs is just a convention; the ** operator is what imbues it with these magical properties.

boreal umbra
stiff portal
#

Nah, i reached my intended result for now

quick glade
#

Damnit variables, why can't you just magically scope yourselves

#

I have no clue why n_op is becoming a global variable here, even without my n_op = "booyah" it's a global. 😓

brave badger
#

@quick glade for doesn't have scope in Python

#

It's more convention and good practice to not refer to whatever variables were created within them

#

Another thing, lambdas and functions are late-binding; when you build one that contains a reference to some closure variable, it won't actually store the "current value" of said thing, just the name of what it should refer to

quick glade
#

Yeah I know about the for scope, that's why my booya worked.
My issue was that the lambda would always take the last value of what n_op was in the loop.

#

I assumed lambda worked like inner functions (for decoarators) in the way it treat variables from outside itself

brave badger
#

You could use a function factory for that fwiw

quick glade
quick glade
brave badger
#

Something like this enforces _ to be bound to whatever that was passed

def eager_bind(n_op):
    def _(self, other):
        return N(self, other, n_op)
    return _
quick glade
#

Oh ok that makes alot of sense

chrome solar
#

Hi I was wondering how I could compile python for my os?

#

Like compile to a bin that my cpp kernel could use

raven ridge
#

what do you mean by "cpp kernel"?

chrome solar
#

i mean my oses kernel is written in cpp

#

But how could I compile python myself

sacred yew
#

uhhh

#

arent all mainstream kernels written in C?

chrome solar
raven ridge
#

all the major ones, AFAIK.

sacred yew
#

linux is

#

windows is

#

osx is

#

what else

raven ridge
#

In any event http://nuitka.net/ is the closest thing to what you're asking for that I can think of.

sacred yew
#

pyinstaller?

raven ridge
#

well, depends what you mean by "compile" and "bin"

sacred yew
#

im assuming bin == executable

raven ridge
#

nuitka produces native self-contained executables, PyInstaller doesn't - but PyInstaller is also a useful direction to check into.

chrome solar
sacred yew
#

"This article is a bit out of date, poll User:Sortie or check his patch to Python 3.4."

#

and thats for cross compiling python

raven ridge
#

oh, wait - you're trying to compile the interpreter, not a Python script?

sacred yew
#

arent there build instructions on the github

#

since these are really outdated

chrome solar
#

wish osdev had documentaion like this, we got literately 100 pages of real documentation and the rest is a 2700 page manual written in asm lmao

raven ridge
sacred yew
#

do you even need to cross compile though

#

aren't you trying to run on your own computer

raven ridge
#

depends on what the computer is - if it's running a handmade OS it may not have had a compiler ported to it yet, or it may be running on hardware slow enough that compile times are unreasonable

#

but yeah, if autotools and make and gcc are working on it, then just build as normal instead of cross compiling.

sharp vine
#

is anyone here familar with Binary search trees/AVL trees?

sacred yew
undone hare
#

Please keep rickrolls and similar in off-topic, this channel is strictly for Python related talks

grave jolt
#

!e

print(1 + not 0)
fallen slateBOT
#

@grave jolt :x: Your eval job has completed with return code 1.

001 |   File "<string>", line 1
002 |     print(1 + not 0)
003 |               ^
004 | SyntaxError: invalid syntax
grave jolt
#

Why is this invalid syntax?

wide shuttle
#

I think it's because + has a higher binding precedence than not

#

So, 1 + (not 0) would work

#

You can experiment with it by turning it around and observing the result of not 1 + 0 vs (not 1) + 0

#

Both will work, but you'll get a different answer

undone hare
#

Let's check the grammar

#

Yeah, not_test is above arithm_exp

#

And a construct can only be made of constructs below it

grave jolt
#

!e

def f():
    print(x + - y)
    print(x + ~ y)
fallen slateBOT
#

@grave jolt :warning: Your eval job has completed with return code 0.

[No output]
wide shuttle
#

@grave jolt That's not equivalent, those unary versions have a higher binding precedence than the binary + while not has a lower binding precedence than +

grave jolt
#

Why should precedence matter when deciding whether something is valid syntax?

wide shuttle
#

So, x + - y will be equivalent to x + (-y)

#

Because it's now tried as (1 + not) 2

#

as far as I understand it

sinful crystal
#

!e

    print(x + - y)
    print(x + ~ y)```
fallen slateBOT
#

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

grave jolt
#

!e

print(2**~5)
fallen slateBOT
#

@grave jolt :white_check_mark: Your eval job has completed with return code 0.

0.015625
wide shuttle
#

Hmm, right

#

That's because of this footnote:

#

The power operator ** binds less tightly than an arithmetic or bitwise unary operator on its right, that is, 2**-1 is 0.

#

I think @true ridge may know the proper answer here. I'm just guessing it.

undone hare
grave jolt
#

doesn't python 3.10 use a new parser?

undone hare
#

I don’t think the syntax have been updated so deeply yet

true ridge
true ridge
true ridge
#

In case of anyone interested more deeply, I suggest checking out the precedence handling code at ast.unparse. It used to parenthesize every expression, but now it calculates and tries to actually imitate a reverse effect of what the parser does in terms of precedence (also for **, see the right/left associativity stuff): https://github.com/python/cpython/blob/3bd6035b6baf1a7d51b7cc2c6bb2c81886236b67/Lib/ast.py#L1360-L1375

undone hare
#

Interesting, thanks for the correction!

undone hare
#

Hello @unkempt rock, this isn't the right channel to share your blog posts, please use #python-discussion for that

unkempt rock
#

oh

#

okay thanks

#

my bad

undone hare
#

All good :+1:

swift plinth
#

from collections import defaultdict
while True:
#Let the game start
game = input('Do you want to play the game? Say Yes/No')

if game.lower() == 'no':
break
elif game.lower() == 'yes':
# a dictionary to store the data
store = defaultdict(list)
love = list(map(str,input('What do you love ?').split()))

store['love'].extend(love)

good = list(map(str,input('What are you good at ?').split()))

store['good'].extend(good)

world = list(map(str,input('What the world needs ?').split()))

store['world'].extend(world)

money = list(map(str,input('What you can be paid for ?').split()))

store['money'].extend(money)

now after storing the data in the dictionary we will compute the values for the given variable i.e. vocation,world etc.

#intersection of world and money for vocation

for ch in store['world']:
if ch in store['money']:
store['vocation'].append(ch)

#intersection of money and good for profession

for ch in store['good']:
if ch in store['money']:
store['profession'].append(ch)

#intersection of good and love for passion
for ch in store['good']:
if ch in store['love']:
store['passion'].append(ch)

#intersection of love and world
for ch in store['world']:
if ch in store['love']:
store['misson'].append(ch)

for ch in store['good']:
if ch in store['love'] and ch in store['world'] and ch in store['money']:
store['lkigai'].append(ch)

for a,b in store.items():
print(a,b)

#

the ** break** is out of loop

#

line 7

#

idk why or how

grave jolt
swift plinth
swift plinth
grave jolt
unkempt rock
undone hare
#

All good

unkempt rock
#

:)

unkempt rock
#

hllo

#

can anyone help me?

#

i want to ask a question

unkempt rock
#

Hey

stray hollow
#

Hello. This is not a help channel. This channel is for discussion about the language itself. If you want help, please look at #❓|how-to-get-help

magic hollow
#

been trying to get into python an advice for getting started?

minor oriole
#

!resources

fallen slateBOT
#
Resources

The Resources page on our website contains a list of hand-selected learning resources that we regularly recommend to both beginners and experts.

minor oriole
#

@magic hollow take a look here

magic hollow
#

thanks!

minor oriole
#

np

austere gate
#

Question about Spark...

I have the impression that spark is widely use and it’s fast

Today I took the spark course, and learn it’s build on RDD blocks, where RDD is much slower than data frame

————————————
Then it come across my mind... is spark really helps us to process the data faster?

Yes, the data separate into partitions, and able to cache them definitely helps the speed.

However, with so many modules optimize dataframe, is spark really needed?

Please help me understand it 🙂

gleaming rover
#

@austere gate this is a channel for discussion of the Python language. you can try #data-science-and-ml.

austere gate
#

Got it. Sorry that I don’t know where to put up this question 🙈

deep bramble
#

you must be doing something special in your class

#

I think without overriding __eq__, it will only return true if it's the same instance

#

there are several things which could be happening here, for example, your Player class might be inheriting from something which does have __eq__, or the class itself might be a singleton (I doubt this, but it would be a case in which this would happen)

#

it doesn't

#

__str__ doesn't affect equality checks in any way

deft pagoda
#

tuples are equal if their elements are equal

#

so yes

#

(this includes NamedTuple)

elder lodge
#

if i have a mypackage/lists.py and i want to import from a package called lists how do i do that?

when i do from lists.services import ListService pycharm complains

fallen slateBOT
#

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

quasi isle
#

hi 👍

boreal umbra
#

@unkempt rock This channel is strictly for discussion.

wise ibex
#

yo guys i just upgraded from python 3.7 to 3.8.2 but when i type python --version it still show 3.7

teal cedar
#

is it illegal to ask for help with YAML in this server

deep bramble
#

it's not illegal, but you might not get an answer, this is certainly not the channel for it though, this is for discussions about python itself

teal cedar
#

thanks

south canopy
warm trout
wise ibex
#

chill guys i figured it

radiant scroll
#

Is there a way to apply @staticmethod decorator to every method in my class?

flat gazelle
#

@radiant scroll there indeed is, but I would suggest making a module instead.

radiant scroll
#

The thing is that this is already in it's own module, but that module contains 3 classes like these and I'm not sure how I feel about splitting this into another 3 files

flat gazelle
#

I would lean more towards 3 files than 3 namespace classes. Since you can for example do a from import from a module

grave jolt
#

Or you can use SimpleNamespace

#

but that's a bit unexpected and obscure

flat gazelle
#

that doesn't work nicely with functions

grave jolt
#

you mean, editor support?

#

yeah

radiant scroll
#

I was hoping there was some class decorator that could automatically turn the methods into static ones

#

perhaps metaclass, but that seems like too much

flat gazelle
#

you can easily make one, but consider how confusing it would be for users

#

and your editor

#

which cannot tell that such a decorator exists

grave jolt
#

If you're using mypy, you could probably make some sort of custom plugin, but that seems like overengineering

radiant scroll
#

so I should split it into 3 modules, even if they'll only contain about 3-5 functions each?

flat gazelle
#

yes

#

or consider whether you actually can't just have all the 15 functions in a single module without a separate namespace

radiant scroll
#

they should be separated, but I suppose I can turn them into modules then, I wanted to use classes because it felt cleaner for the file structure, but if it brings so many problems with it, I suppose modules will be better

flat gazelle
#
def methods_static_by_default(cls):
    for a, v in vars(cls).items():
        if not a.startswith('__') and callable(v):
            setattr(cls, a, staticmethod(v))
    return cls
``` should probably work as the decorator, though I didn't test it extensively. But yeah, modules are just much nicer for namespaces, since imports are designed to work with them.
grave jolt
#

Or you can just not mark the functions as static methods

#

!e

class Foo:
    def __init__(self):
        raise NotImplementedError

    def bar(x, y):
        return x + y

print(Foo.bar(3, 7))
#

if you really want to use classes

fallen slateBOT
#

@grave jolt :white_check_mark: Your eval job has completed with return code 0.

10
grave jolt
#

but it's unexpected as well

radiant scroll
#

that would probably cause even more issues with the editor, yeah, I 'll just use modules

grave jolt
#

You could just put a # type: ignore or # noqa next to these methods

#

but yes, just use modules

gusty lichen
#

I was wondering if there is some sort of protection for pypi.
If not, a malicous user could create a script that commits dozens of useless packages and pollute the namespace or not?

charred wagon
#

There isn't. In fact, it has been an issue in the past, especially with people claiming package names that are common misspellings.

#

But if reported, they do get taken down.

crystal pebble
#

Sorry, quick question. This was in somebody's __setitem__: return self.value := self.value[:key] + value + self.value[key+1:]
Would this create an entirely new object every time it's run, or would an existing object just be updated?

gusty lichen
charred wagon
#

For a package index of its size, it is not feasible for any sort of manual review of all submissions and all subsequent updates. Static analysis is not always reliable either. Ultimately, its the users' responsibility to make sure what they are downloading is safe.

#

Even if it were to be restricted to "trusted" submitters, that doesn't absolve the user of their responsibility.

gusty lichen
#

sure, like always. static analysis is a cat and mice game between malicious programmers and the ones fighting them

#

not very knowledgable in linux, but apt package list works similar to pypi right?

charred wagon
#

I believe they're restricted to certain users e.g. the maintainers of the linux distro

#

There are usually companion package lists that are more public e.g. AUR

grave jolt
#

I found a weird usage of assigning a lambda to a variable: when you want to specify that a function satisfies a specific protocol or type alias:

Easing = Callable[[float], float]
back_and_forth: Easing = lambda t: 1 - 2 * abs(0.5 - t)


class Trajectory(Protocol):
    """
    A trajectory is a way of interpolating between two points
    """
    def __call__(
        self,
        x1: float, y1: float,
        x2: float, y2: float,
        t: float
    ) -> tuple[float, float]:
        ...
        

linear_trajectory: Trajectory = \
    lambda x1, y1, x2, y2, t: (
        x1 * (1 - t) + x2 * t,
        y1 * (1 - t) + y2 * t,
    )

is this too cursed?

#

AFAIK there isn't really a way to express it differently. Or is there?

flat gazelle
#
back_and_forth: Easing
def back_and_forth(t):
    return 1 - 2 * abs(0.5 - t)
#

or does the type checker not like that

grave jolt
#

nah, "Declaration "back_and_forth" is obscured by a declaration of the same name"

flat gazelle
#

what I assume does work is

def __fun(t: float) -> float:
   return ...
 back_and_forth: Easing = __fun
``` but that isn't all that great
grave jolt
#

but it's kind of strange as well

#

one benefit of using lambdas with Pyright is that the types of arguments are inferred bidirectionally

#

(i.e. here t is inferred to be float because of Easing)

#

sometimes it feels like gradual typing is just like another language nailed on top of Python 🤔

#

and it's like a wild animal

#

rest of Python: more or less uniform tools, one way to do stuff, very little undefined behaviour (in non-cursed code)

typing: multiple competing and incompatible tools; no standard way to extend or provide custom rules for stuff like dataclasses or attrs or
SQLAlchemy; as a result, many valid programs are not passing the typechecker

swift imp
#

How do I add an instance variable a slotted class? This is essentially a monkey patch. Is there really no way around this?

flat gazelle
#

@swift imp you could create a descriptor that stores the attribute in some external place

#

since __slots__ doesn't stop class variables from appearing, nor does it stop the descriptor protocol

swift imp
#

Like

instance_refs = {}
class Descriptor:
   def __get__(self, instance, attr):
       return instance_refs[instance]
   def __set__(self, instance, value):
       instance_refs[instance] = val
spice pecan
#

Pretty much, though it would make sense to store a dict on the descriptor instance instead of making it global

swift imp
#

True

flat gazelle
#

another note, I would suggest making id(instance) the key instead of just the instance itself so that it works on instances with different hashing algos/which are unshable

swift imp
#

True

#

Ok

#

Know what kills me, I'm trying to use weakref and the objects I'm storing cannot have weakrefs created

#

Probably bc theyre slotted?

#

Fuck it

peak spoke
#

Can always add weakref to slots

swift imp
#

At that point I might as well just subclass and replace it in the module no?

#

Unless it becomes an issue I'll just forget about the weakrefs for now

#

Adding to slots after the class is defined doesn't do anything. That was my first attempt

hasty lily
#

can anyone help me diagnose why this isn't working the way I expect it to?

#

I'm trying to cross reference data in a pickle from an hour ago and only print new listings but for some reason I'm getting dupes every time I run my scan.

sacred yew
boreal umbra
limpid marten
#

What do you mean?

brave badger
#

!shhh

fallen slateBOT
#

✅ silenced current channel for 6 minute(s).

brave badger
#

Again.

#

!warn 791101296576823367 I'm not sure if you're making it deliberate, but please refrain from continuous off-topic discussion in a channel after you've been told by staff to move to another one.

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied warning to @unkempt rock.

brave badger
#

!unsilence

fallen slateBOT
#

✅ unsilenced current channel.

fallen slateBOT
boreal river
#

Good morning sun_with_face ll Good evening
Can I use Google maps API to get directions to a certain location...? If yes, mind giving some insights..?

cloud crypt
sacred yew
#

why is StopIteration an Exception subclass when GeneratorExit is only a BaseException subclass?

#

they both aren't technically "errors", so is it just legacy reasons?

ocean bobcat
#

what are popular ORMs people like working with?

#

sql academy?

limpid marten
charred wagon
#

Because PEP 342 was created before PEP 352 (the one that introduced BaseException).

#

Incidentally, both PEPs were implemented in the same Python version, 2.5

grave jolt
#

Is there some macro language or code generator for declarations like this?

    @overload
    def join(self) -> Pi[tuple[()]]: ...
    @overload
    def join(self, a: Pi[A]) -> Pi[tuple[A]]: ...
    @overload
    def join(self, a: Pi[A], b: Pi[B]) -> Pi[tuple[A, B]]: ...
    @overload
    def join(self, a: Pi[A], b: Pi[B], c: Pi[C]) -> Pi[tuple[A, B, C]]: ...
    @overload
    def join(self, a: Pi[A], b: Pi[B], c: Pi[C], d: Pi[D]) -> Pi[tuple[A, B, C, D]]: ...
    @overload
    def join(self, a: Pi[A], b: Pi[B], c: Pi[C], d: Pi[D], e: Pi[E]) -> Pi[tuple[A, B, C, D, E]]: ...
    @overload
    def join(self, *pis: Pi[A]) -> Pi[tuple[A, ...]]: ...

I'd like to write something like

    def join(self, *!X) -> Pi[!tuple[X]]: # A B C D E
        ...

and have it generate all that boilerplate

undone hare
#

You could preprocess the code and then exec it, or use a custom #coding thingy

grave jolt
undone hare
#

Right, right

#

Couldn’t you use generics for that?

grave jolt
#

no, Python's generics aren't powerful enough for this sort of thing

#

e.g. you can't define a function that takes any number of arguments and returns a tuple of them, like f(4, 2, "foo") -> tuple[int, int, str]. You have to write these overloads.

undone hare
#

Hmm.. I guess you could write a script to generate those

gleaming rover
#

I see that kinda thing in a certain JS library

#

but, to answer your question...no, sorry.

grave jolt
gleaming rover
grave jolt
#

it looks a little bit terse, but it's possible

gleaming rover
#

K extends keyof T always makes me a bit weak at the knees

#

😂 feels so good

#

but

#

the thing is

#

you can't use the ..., right

#

that was what I was thinking of

grave jolt
#

@gleaming rover In TS, ...args are hinted as an array, unlike in Python. Which generally is a bit counterintuitive, but here it makes a certain thing possible

#

if it wasn't like that, I could've used an array

gleaming rover
#

oh, right

#

that's true

#

forgot about that

grave jolt
gleaming rover
#

is that what it's called

grave jolt
#

it's a "projection"

#

like, a function from a record or tuple to a single element

#

doesn't make much formal sense here, just for the sake of using greek letters

#

Dependent typing is when a type depends on a value, if I understand it correctly.

gleaming rover
#

it is

#

which was what I associated pi with

#

so I was a bit confused

barren fiber
#

Hi here. I have a website that runs with a python backend. It does some compute heavy stuff (numpy, tensorflow, etc.). It is currently packaged as docker images
I would like to package it as an electron app. Do you think such python application can be correctly packaged as windows executable ?

swift imp
#

That makes me wish there was a type annotation to indicate value bounds, or sizes but I guess that isn't a type though

undone hare
#

I think there’s something like that, they use something similar to typehint the mode argument of open

barren fiber
#

@swift imp pydantic models can do this

#
class Pie(BaseModel):
    flavor: Literal['apple', 'pumpkin']


Pie(flavor='apple')
Pie(flavor='pumpkin')
swift imp
#

Yeah but you can't say like an integer between 1 and 50 right?

#

Or an array of length 10 in dimension 1

#

They added a whole operator for matrix multiplication but won't supply stuff like Matlab argument blocks where you can specified shape type and value range

barren fiber
#
 bigger_int: int = Field(gt=10, lt=50)
 a_list: List[str] = Field(max_items=10)
swift imp
#

Just seems inconsistant

#

That looks interesting, I've never heard of pydantic

winter geyser
#

So if 2 vegans get in a fight is it really called beef?

astral gazelle
#

Not the channel for this my guy, try off topic

swift imp
#

Has anyone read anything new on the steering councils decision of patmat?

unkempt rock
#

if python is built on c how do lists work

#

like, in c all memory is defined when you malloc() them. you cant just append to an array like you can in python

#

unless append() is tied to realloc()

#

that would be very inefficient tho

#

since realloc() copies the array each time

#

does it??? noooooo

swift imp
#

Lists arnt contiguous memory at the c level

quaint osprey
#

yo

swift imp
#

More akin to a bunch of pointers iirc

spice pecan
#

Instead of extending the underlying array by exactly 1 item, it effectively uses a multiplier

#

I don't remember the actual value, but you can imagine that it, for example, doubles the underlying array once it reaches full capacity, and then just remember the actual capacity vs the amount of occupied slots

grave jolt
#

But Python only has "reference semantics", not "value semantics", so it can only store pointers

grave jolt
#

lists are overallocated to prevent that

pliant tusk
#

list_length is the count of items in the ptr array that are actually in the list, ptr_arr_size is the size of the allocated ptr_arr

raven ridge
# unkempt rock that would be very inefficient tho

The list contains a contiguous dynamic array of pointers to Python objects. It does realloc as the list grows, but the trick it plays is that each time it grows, it grows by a multiple of the current size. That means that as the list gets larger reallocations become more expensive (because they need to copy more stuff) but rarer (because the amount of new items needed to trigger each subsequent reallocation is larger than the last). This leads to what is called "amortized constant time" appends

#

Which means that, even though some appends will be slower than other appends, when considered on average across many append operations the amount of time each one takes on average does not vary according to the size of the list

olive harbor
#

Good afternoon everyone I am new to the discord, but I am trying to make a batch file with a python script using Selenium to do web scraping. From what I have researched I can just create a notepad file that has the python.exe in quotations and the .py script in quotations and save it as a .bat file. When I do this the file saves correctly, but never opens the web driver firefox.exe I believe it is because it cannot find the firefox.exe when running the batch file. If anyone has any tips or another way to create a .bat please let me know or I can add you to a current discord call I am on so you could perhaps direct me to doing the correct thing. I am rather new to python so any helps is appreciated.

boreal umbra
trail ridge
#

we have to be able to access it soo its valid

thorny gyro
#
>>> t = (1, 2)
>>> a, b = t
>>> a
1
>>> b
2
>>> a, b, c = t, 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: not enough values to unpack (expected 3, got 2)
``` why is this not possible
ionic cypress
#

use *

flat gazelle
#

because t, 3 is ((1, 2), 3). You can unpack it like (a, b), c

ionic cypress
#

a,b,c = (*t,3)

flat gazelle
#

to construct (1, 2, 3), you would need ^

#

a, b, c = *t, 3 the parens are not needed though

ionic cypress
#

ooo

thorny gyro
#

I see

#

ty

unkempt rock
#

Hi

boreal umbra
# unkempt rock Hi

Hello, this channel is for discussing Python at a high level. What within that topic did you want to talk about?

turbid fox
#

Could Python or robloxpy be used to execute scripts into roblox games?

tardy junco
#

No. RobloxPy is just doing usual stuff you can normally do in roblox

charred wagon
#

Does Python have an optimisation for concatenating a string to an empty string?

#

In my brief testing, it seems to return the same string instance when this is done

#

is this behaviour that I can rely upon?

#

!e ```py
s = '\n'
s2 = '' + s
print(s2 is s)

fallen slateBOT
#

@charred wagon :white_check_mark: Your eval job has completed with return code 0.

True
peak spoke
charred wagon
#

Thanks

spark magnet
#

@charred wagon how would you take advantage of relying on that?

charred wagon
#

Was looking at a loop which used x += y and sometimes needed to reset x to an empty string.

#

Not really taking advantage of it I suppose

#

I was wondering if it would do a wasteful copy of the y string to create a new object in that case

#

For all I know, even if it did copy, conditionally assigning instead of concatenating may be slower still 🤷‍♂️

spark magnet
#

i think you are safe, and you are right that extra work in python will be worse

peak trout
#

damn that's cool

visual shadow
#

If you need to construct a string part by part, you could use a list to hold all the pieces and use a join at the end.

radiant scroll
visual shadow
#

Strings being stored as arrays has no bearing on the "work" that goes into a concat. If you notice, even in the realm of C arrays have fixed length, and when you try to combine two fixed length arrays that are maxed out, you must get a new memory allocated to hold the combined array. However, purely speaking from the realm of python, strings are explicitly defined as immutable

#

So the idea of "extending" a string inplace wouldn't even apply

sharp plover
#

I'm not sure how it's implemented in practice, but if they use a dynamic array, this is O(1) per character appended when amortised.

#

Try timing the following two code snippets:

#
old = 'a' * 10**6
new = ''
for c in old:
    new += c
#
old = 'a' * 10**6
new = ''
ref = new
for c in old:
    new += c
    ref = new
visual shadow
#

Is this an implementation detail or can this behaviour be relied upon?

#

Also, i must say it's very interesting, i never knew we had this

sharp plover
#

Erm, I don't know to be honest. I'd have to check whether other interpreters have this optimisation.

cold forum
#

Does mypy TypeVar allow having a generic with an upper bound, that includes the bound type itself, so that assigning instances of the base (bound) class is allowed?
I've been looking for half an hour without finding anything.

grave jolt
cold forum
#

Not quite, I have this class:

CT = TypeVar('CT', bound=DeviceConfig)

class Device(ABC, Generic[CT]):
    def _get_config_class() -> Type[CT]:
        return DeviceConfig

But I get Incompatible return value type because DeviceConfig is not included in CT (only subtypes are allowed)

spice pecan
#

CPython checks the refcount and modifies in-place if there's only one actual reference

flat gazelle
#

@cold forum pretty sure the reason for that is that the type variable of the generic class get's filled at the call site, so if you had Device[SubclassOfDeviceConfig] that implementation would be incorrect.

cold forum
flat gazelle
#

I am pretty sure the type checker is not powerful enough to do this.

grave jolt
#

nah, you can't do that

cold forum
#

Weird, I don't understand why there's no option to allow TypeVar(..., bound=basetype) to take basetype as well

grave jolt
#

wait

flat gazelle
#

a type variable doesn't mean any type fulfilling the bound, a type variable means a single specific type that the user chooses

#

and the user may not choose DeviceConfig.

grave jolt
#

yeah

cold forum
#

Yes, but the bound= as far as I understand means the chosen variable has to be a subtype of the bound

grave jolt
flat gazelle
#

bound does include the bound itself

#

Device[DeviceConfig] is fine

cold forum
#

Mmmhh... so that method in the base class, returning DeviceConfig, can't exist because subclasses might want some other CT type

grave jolt
#

Yes.

#

You can just make the return type annotation to be Type[DeviceConfig]

#

What do you want to do, in general?

cold forum
#

So I was using generics on the base Device class to conceptually link them together basically, for better type checking

grave jolt
#

The problem with your definition of Device is that if you have a Device[CT], its config has to be a subtype CT, not just of DeviceConfig

#

Just like if you have a Dict[K, V], its keys method must return a keys view of K, not a keys view of Hashable.

cold forum
#

Yeah, actually the whole class definition looks something like this:

CT = TypeVar('CT', bound=DeviceConfig)
LT = TypeVar('LT', bound=DeviceLog)

class Device(ABC, Generic[CT, LT]):
    ...

But while DeviceLog is an ABC, so it never gets directly assigned, DeviceConfig isn't. Maybe I should make DeviceConfig ABC too, and have something like class DefaultDeviceConfig(DeviceConfig), and have return that in the base factory method instead?

cinder ferry
#

So i'm working on a small script that takes input. And I'm using regex to verify that the input matches a pattern. Now i want it to match the pattern T.X.Y, with T being EITHER b, c or r and the X and Y being any lenght integers (both positive and negative). I got my regex to ALMOST work, except now the T doesn't just accept b, c or r, but also br, which should be invalid. The regex is as follows.
re.search(r"[bcr]\.-*\d+\.-*\d+", uinput). uinput is the input() from the user

#

as a few examples, the input b.1.500 is valid and is accepted. r.-300.20 is valid and accepted. d.20.-3 is invalid and rejected, but cr.50.-30 is invalid but accepted

#

anyone knows how to make a character from a class in regex match just ONCE?

#

feel free to @ me when you know

lapis hound
#

@cinder ferry you need to anchor your regexp, because anything before will also match

#

re.search(r"^[bcr]\.-*\d+\.-*\d+$", uinput)

lapis hound
#

also, you probably want -? and not -* because --- will match and you probably don't want that.

cinder ferry
#

i just want the - 0 or 1 time to indicate a negative integer @lapis hound

lapis hound
#

right.

#

that's why you should use ? and not * because * will match 0 or more, which could be >1.

#

re.search(r"^[bcr]\.-?\d+\.-?\d+$", uinput)

#

? matches 0 or 1 time only

cinder ferry
#

and ? was 0 or 1?

#

right thanks

#

yeah i'm still quite new to regex so this is a learning expedition for me

#

right so the ^and $ are so it doesn't match anything before and after

#

the ? to do {0,1}

#

but do you know a way to match if a single letter is either b, c or r?

#

i assumed it was possible with classes, but maybe not. @lapis hound

lapis hound
#

[bcr] will

#

you'll see that after adding ^ at the start of the regexp, it'll no longer match cr.50.-30

cinder ferry
#

ah so it was matching the c in bc, and then the b was because it would match anything before too?

lapis hound
#

the reason cr was matching before is because everything before r.50.-30 would match

cinder ferry
#

right that makes sense

lapis hound
#

you could test it with uinput = 'this will r.50.-30 match your regexp' if you use the regexp without ^ and $

cinder ferry
#

right

lapis hound
#
>>> uinput = 'this will r.50.-30 match your regexp'
>>> re.search(r"[bcr]\.-?\d+\.-?\d+", uinput)
<re.Match object; span=(10, 18), match='r.50.-30'>
cinder ferry
#

that makes complete sense

#

i updated it now

lapis hound
#

you may want to input().strip().lower() to get rid of any stray whitespace

#

if you're handling user input

#

also, not sure if input() removes the trailing carriage return (the \n)

cinder ferry
#

i don't think it does

lapis hound
#

looks like it does.

cinder ferry
#

but my regex seems to work now and reject any suffix characters

lapis hound
#
>>> test = input()
testing
>>> test
'testing'
#

it doesn't include the carriage return at the end of the string

cinder ferry
#

oh wait i read your statement wrong

#

i thought it said something along the lines of it keeps the trailing \n

lapis hound
#

compared to, say, sys.stdin.readline() which does include the newline.

#
>>> import sys; test = sys.stdin.readline()
testing
>>> test
'testing\n'
cinder ferry
#

i guess now i can take a look if i can make the program repeat, i guess just a simple while True and a continue statement so it restarts

#

well thanks @lapis hound for the help. Your suggestions definitely make sense

lapis hound
#

Good luck with the rest of your project.

cinder ferry
#

thanks

#

it's just a small script i wanted to write after someone gave me the idea yesterday lol

barren fiber
#

each time I read regexes, I die a little inside

swift imp
#

Why regexes are awesome

#

Regexes are so awesome they're used extensively in DNA sequencing

trail ridge
#

we should debug the rpt nodule so we can access the database

barren fiber
#

Regexes are cool

#

but i usually can them 'write only programming'

boreal umbra
cinder ferry
# barren fiber each time I read regexes, I die a little inside

if i give you just

(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])

your probably won't understand a single thing

#

if i give you this to say this is the finite diagram of this regex you might understand it slightly better

barren fiber
#

the issue is usually with editing regexes

cinder ferry
#

if i say that's currently the official regex for recognizing email adresses you might understand it even more

barren fiber
#

It's often easier to start from scratch 😛

#

The diagram is really cool

cinder ferry
#

i've updated my regex to now be the following (^[bcr][.,\s]-?\d+[.,\s]-?\d+$)|(^b[.,\s]-?\d+[.,\s]-?\d+[.,\s]-?\d+$)

#

and this is pretty much my first regex i ever wrote, and it's actually easy really

#

yes i know i can make the regex smaller

#

let me do that rn

charred wagon
barren fiber
#

How hard is it to package a python app with deps such as numpy and tensorflow, as a windows executable ?

elder lodge
#

quick question about Django models. you can do Users.objects.filter(...) or Users.objects.all() i know objects is a django Manager but in terms of just python mechanics itself. in this context, Users is not instantiated. what is objects because it can't be an instance variable. but it's usable as if Users is instantiated.

elder lodge
deep bramble
#

If you just want to know how to do something like this, it can be a class variable, i.e.: ```py
class Foo:
a = 5

Foo.a # --> 5

But Django is fairly complex, and it's handled these models are handled with metaclasses which are basically constructors of classes themselves. All you basically need to know is that these `objects` attribute was assign to the class itself with some metaclass, and the `objects` type itself can really be anything, it can be an instance of some other django class, or a fucntion, etc.
charred wagon
#

Aren't they just classmethods?

#

Or class attributes, sorry

elder lodge
#

ok i suspected they were metaclasses

#

that's what i wanted to understand. thank you

radiant scroll
#

Would this be a good way of making hashable lists, or are there some issues that could arise from this?
I also wonder if python doesn't already have something like this somewhere in stdlib, so I could abstract this logic away

class hashable_list(list):
  instances = dict()
  
  def __new__(cls, *args, **kwargs):
    new_instance = super().__new__(cls, *args, **kwargs):
    hash_value = hash(new_instance)
    cls.instances.setdefault(hash_value, new_instance)
    return cls.instances[hash_value]

  def __hash__(self):
    total_hash = 0
    for element in self:
      total_hash += hash(element)
    return total_hash
#

I'm specifically interested in the possible issues from __hash__, I do realise that I'm returning the same, mutable instances, so if this list is created and adjusted, it would adjust all of the other lists, that is intended behavior

charred wagon
#

Summing hashes isn't good because 1. it disregards the order of items in the list 2. there are multiple ways to get the same sum, so you'll get hash collisions

radiant scroll
#

yeah, I thought that might be an issue, but what would be the preferred way to do it then?

charred wagon
#

I don't know, sorry.

grave jolt
#

But yes, you're going to get into trouble with this if you're mutating a list.

radiant scroll
#

how does tuple implement it's __hash__?

amber nexus
#

I was just wondering why something like

a = 0
def function():
    a = a + 4

Doesn't work, since for example having a + 4 in the function would work.
Why is it only when you use a = a that it searches for a in the local scope rather than getting the value defined in the scope outside of the function.

charred wagon
#

My guess is that this is just a way to have consistent behaviour

#

It forces you to be more explicit about your intent

amber nexus
#

Yeah that sounds reasonable

unkempt rock
#

Its better than JS, you can unintentionally affect global variables if you forget to define variables with var in your function

raven ridge
#

it's defined to be that way:

If a name is bound in a block, it is a local variable of that block, unless declared as nonlocal or global. If a name is bound at the module level, it is a global variable.

#

and as for why it's defined to be that way - that's the only way for there to be local variables at all.

#
def foo():
    x = 1
    return x

If this rule didn't exist, would it be possible for this to assign to a global variable instead of a local?

charred wagon
#

I think you misunderstand the question

amber nexus
#

Yeah slightly, although I did just have a thought

charred wagon
#

The example given could have used a from the global scope and then create a locally scoped variable

#

What i was trying to say with my answer is that those kind of semantics would be inconsistent and confusing

amber nexus
#

Is this behaviour beneficial fallout of the way variables are created. Like for example a = a + 4, does it initialise the local a before attempting to assign to it a + 4, leading to it looking for the local variable a rather than getting the one defined in the global scope

raven ridge
#

local variables are determined at parse time, not when the function is run.

amber nexus
#

ah ok

raven ridge
#

the existence of an assignment to a particular variable name, and the absence of a global or nonlocal for it, makes it a local variable - at the point when the function is parsed, and the bytecode for it is created (because the bytecode is different depending on whether it's looking up a local variable or a non-local or global variable)

#

you're right that it could make a reference to a local variable before it has been assigned look it up in an enclosing scope, I suppose

#

but doing that would actually be kinda tough.

#

quite tough, really. py x = 5 def foo(): if random.random() < 0.5: x = 10 print(x) If you wanted this to print 5 or 10 with a 50/50 chance, it would need to generate different bytecode for the x access in the print(x) line depending on whether or not the if block was entered, because accessing a local variable uses different bytecode than accessing a global variable.

amber nexus
#

ah yeah that would be tricky

raven ridge
#

the other thing I guess it could do is initialize local variables with a reference to a global variable of the same name, but that would make calling functions much slower - it would imply a global lookup for every local variable every time the function is called.

#

I suppose it wouldn't be entirely unreasonable for LOAD_FAST to fall back to LOAD_GLOBAL instead of raising an UnboundLocalError?

grave jolt
#

hmm

#

well, if you have

def f():
    x += 2
    x = 1

couldn't it just raise a compile time error?

undone hare
#

It is way more complicated because of the mutable nature of Python

#

For example if you add an exec("x" + "= 0") at the top

grave jolt
#

sure

#

But, for example, Python can issue syntax warnings in some cases:

#

!e

def f():
    [{}]()
fallen slateBOT
#

@grave jolt :white_check_mark: Your eval job has completed with return code 0.

<string>:2: SyntaxWarning: 'list' object is not callable; perhaps you missed a comma?
grave jolt
#

maybe it could do the same for this:

def f():
    x += 2
    x = 1
undone hare
#

While variables can be "tampered"

#

You need to account for scoping, control flow, and stuff

grave jolt
#

In simple cases it can issue warnings, like here.

#

Where you probably just forgot a global a

undone hare
#

That's a whole layer of analysis while this warning is probably just detecting a pattern in the AST

grave jolt
#

@undone hare ...in the same way that Python doesn't do full type checking and inference, but it can spot trivial stuff like ()().

#

which is likely a typo

undone hare
#

Well, this doesn't need any advanced analysis, by just looking at the ast you know that it will result in an error

raven ridge
grave jolt
#

hm, yeah, that's a bit more complex

#

however, static analysis tools (even flake8 and such) can point out when I do a mistake like that, so that's probably not very hard

raven ridge
#

A static analyzer can take much more time to do that sort of checking than the interpreter itself can afford to do. Slowing down all compiling in order to introduce a relatively expensive check for a relatively rare mistake is a hard sell.

fast rose
#

If I'm making a class to represent a webhook and I wanted to make all of the webhook keys class variables but all of the webhook keys are in camelCase, would you convert them to snake_case to stick with Python conventions or keep them camelCase to make it easier when working with the documentation that sent the webhook?

undone hare
fast rose
#

It's coming from a json object webhook from another server.

undone hare
#

Hmm

#

I'd make the internal attributes snake_case

#

Well, the Python representation snake_case

fast rose
#

I can keep their convention so their extensive documentation is consistent

undone hare
#

I have a very deep aversion for camelCase

fast rose
#

Great, already made the function to convert the dict keys to snake

honest narwhal
#

Is there a way to convert all the attributes of function.__code__ into an actual function object?

#

I see all these things like co_cnlocals, co_code, co_stacksize, etc..

#

And I think that it's possible for me to do something like

#
function = create_function(all of the __code__ attributes)``` and it'll create a fully working function
charred wagon
honest narwhal
charred wagon
#

new_function = FunctionType(code=other_function.__code__, globals={})

honest narwhal
#

What about co_code

true ridge
honest narwhal
#

that looks interesting

charred wagon
#

Well you need the entire code object

#

You can make one yourself using the compile() built-in

true ridge
honest narwhal
#

Okay your example made a function using __code__, but is there a way to make a function by putting the attributes of __code__ in there?

#

not __code__ itself

true ridge
honest narwhal
#

Depends what it does

charred wagon
#

Yeah with CodeType(code args...) I guess

true ridge
#

!d types.CodeType.replace

fallen slateBOT
#
replace(**kwargs)```
Return a copy of the code object with new values for the specified fields.

New in version 3.8.
charred wagon
#

I don't see that point in that if you already have the code object

true ridge
#

it basically does the CodeType(co_attr=old_code.co_attr, co_attr2=old_code.co_attr2, ...) job

unkempt rock
#

someone send me a free code?

#

is to learn the structure

deep bramble
#

there are plenty of open sourced repositories on github or other platforms like that, but this isn't the correct channel to ask in, this channel is focused on questions about python implementation itself, and questions regarding that

brave badger
#

@summer hedge this

summer hedge
#

thanks. Moved it there

ionic sage
#

hi

unkempt rock
#

How do I state the argument name for a multi-arg created with an asterisk when calling the function with the multi-args?
Example:

def func(*args):
	print(args)
func(args=82, 27, 7.23, 'ha2£')
grave jolt
#

Why do you want to do that?

halcyon trail
#

Random question

#

Why does the AssertionError exception inherit from Exception?

#

Given the whole mentality of the purpose of assertions, what they are used for, it seems like AssertionError should be outside that hierarchy, the same way that say KeyboardInterrupt is

#

assertion failures indicate that a precondition was not met, and basically that the program itself is invalid, so it shouldn't be ok normally to just try to "handle" the error

charred wagon
#

You may find insights into that by digging through mailing lists surrounding PEP 348 and 352, but based on the PEP contents it doesn't seem this was ever even considered.

gleaming rover
#

e.g. division has a precondition that the divisor must be nonzero, but you get a ValueError that you can handle

unkempt rock
#

i only agree because the language is so dynamic in nature

gleaming rover
#

IMO assert is just shorthand for "raise a special kind of exception if this condition is not true"

unkempt rock
#

it lets you pass arguments without spending a bunch of runtime checking their properties extensively

gleaming rover
#

conceptually kind of similar to asserts in other languages

#

but not as extreme

unkempt rock
#

if this was say C/C++ and i tried to divide by 0, i would 100% except some assertion before that to crash the program - it's a programming error, using an api out of contract

#

i've written an incorrect program

#

just with python, imo the term "incorrect program" is slightly looser

#

so catching assertions is more ok

unkempt rock
gleaming rover
#

would it always be a programming error?

#

okay so the case I'm thinking of is

#

say you pull data from some outside data source and you get only the records that fulfil some criteria, and you want to compute summary statistics, which involve division and would be meaningless if there were no matches

unkempt rock
#

and an exception is more meaningful?

raven ridge
#

Division by zero is defined behavior on IEEE 754 floats.

unkempt rock
#

hmm you're right :/ ok i stand by what i said tho, and just feel my example was a little off

gleaming rover
#

but what I meant to highlight was that it's not necessarily bad code?

unkempt rock
#

do it in python; you say that no matches is meaningless, but i assume an exception would also have no matches?

#

which is what you get if u divide something by 0 (unless your thing automatically translates it to a NaN or something)

gleaming rover
raven ridge
#

Assertions in Python just aren't very useful. Just don't use them. 🤷

unkempt rock
#

lol

#

ah, that's nice of numpy

raven ridge
#

assert is a sanity check that can be turned off at runtime. Using it in production code for anything other than an a nicer error message for something you would handle either way is wrong.

#

For unit test suites, clearly they're pointless if someone turns off assertions, so they're the exception to the rule.

#

Unless you're in control of how the program that uses assert is started, you can't know what assert will do, so it's safest to not use it.

unkempt rock
#

why is it safest not to use it? it's a choice between a programming error (being propagated) and an exception

sacred yew
#

make it actual error handling that throws a real exception

visual shadow
#

Asserts can be turned off

raven ridge
#

You should raise an exception directly.

charred wagon
#

Cause you cannot rely on the assertion being enabled

unkempt rock
#

ah ok i see wym

#

didn't actually know they could be turned off, that's neat