#internals-and-peps

1 messages · Page 91 of 1

unkempt rock
#

!e

x = 0
y = 0
def f():
    x = 1
    y = 1
    class C:
        print(x, y)
fallen slateBOT
#

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

wide shuttle
#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1

    class C:
        nonlocal x
        print(x, y) # What does this print?
        x = 2

f()
fallen slateBOT
#

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

1 1
wide shuttle
stable grail
#

so why does it not care about y

unkempt rock
#

Right tnx

wide shuttle
#

It's the local assignment that changes the behavior

#

That in itself is not odd, for a function that triggers the UnboundLocalError

#

I'm just a bit surprised that it does something different for classes

stable grail
#

!e

def f():
    y = 1
    def g():
        print(y) # NO Error!
    g()
f()
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

1
undone hare
#

Yep, it is resolving it through the closure since you did not reassign y

wide shuttle
#

@stable grail Indeed, it's the local assignment that makes the difference

#

Both in the case of the function (error) or the class (suddenly a global lookup, bypassing the nonlocal scope/closure)

stable grail
#

but why would something on line number n+1 change the line n

#

thats what i find the most interesting

wide shuttle
#

The same as it does for functions: Python will recognise it as a name that's local to that scope

#
def f():
    y = 1
    def g():
        print(y)
        y = 2  # error because of a n+1 line
    g()
f()
stable grail
#

meaning it creates the scope first

undone hare
#

My best guess is that variables are resolved at compile time, that’s a pretty standard procedure

wide shuttle
#

What do you mean by that?

#

It will very much use the value that you determine at runtime

#

say that you do this:

def f():
    x = 1
    y = 1

    class C:
        print(x, y) # What does this print?
        x = 2



x = 10
f()
x = 12
f()
x = input("> ")
f()
#

it would do exactly as you expect

#

10, 12, whatever you input

undone hare
#

I think what is happening here is that at some point during the compilation procedure, the compiler will walk the whole tree and assign numerical value to each variable (the bytecode arguments). When doing this pass, if it sees an assignment, it will consider that variable as being global, and change the instruction used to look it up.

wide shuttle
#

Right, but why is it different for classes compared to functions?

#

What you're saying is basically just restating what happens, right?

undone hare
#

Yeah, that’ my guess of why this happening

#

Although I’m not sure why it is thowing an exception in one case

wide shuttle
#

Well, for functions, the behavior is apparently different than for classes

stable grail
#

allegedly different. im not so sure it is that different

wide shuttle
#

The difference is that a function throws an exception if you try this, while a class looks at the global scope for the value before it's assigned locally

stable grail
#

classes dont need nonlocal to keep track of the reference to a name.

#

it just picks one from the outermost scope

#

while a nested function cant

#

using nonlocal in a nested structure is kinda the solution to get a correct answer

wide shuttle
#

but, without the local assignment, the class does look at the enclosing scope

#

that's why y=1 for the class

stable grail
#

like, why would a class look in the enclosing scope?

undone hare
#

Something to note is that we assign a class attribute on the class, while we create a local with the function

wide shuttle
#

Not sure, but it does do that

#
x = 0
y = 0

def f():
    x = 1
    y = 1

    class C:
        print(x, y) # y=1 from the enclosing function scope, x=0 from the global scope
        x = 2

f()
undone hare
#

What instruction do they use for assigment?

stable grail
#

whats the qualname of C ?

#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1

    class C:
        print(x, y) # What does this print?
        x = 2
    print(C.__qualname__)
f()
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

001 | 0 1
002 | f.<locals>.C
undone hare
#

Make sense

#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1

    class C:
        print(x.__qualname__, y.__qualname__) # What does this print?
        x = 2
f()```
fallen slateBOT
#

@undone hare :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 11, in <module>
003 |   File "<string>", line 8, in f
004 |   File "<string>", line 9, in C
005 | AttributeError: 'int' object has no attribute '__qualname__'
undone hare
#

Hmm.. is there a way around that?

stable grail
#

so in python2 when unbound methods was a thing, this would not happen?

#

!pep 3155

fallen slateBOT
#
**PEP 3155 - Qualified name for classes and functions**
Status

Final

Python-Version

3.3

Created

2011-10-29

Type

Standards Track

wide shuttle
#

My guess is that the behavior is the same for Python 2

#

I think the special sauce here is that the generated bytecodes are different if the current block is a function

undone hare
#

The original post is in Py 2

wide shuttle
#

Probably to better support closures

undone hare
#

They use the print statement

stable grail
#

if you swap class an function around, having class as the first level, will it still be the same?

wide shuttle
#

You'd get an UnboundLocalError I assume

undone hare
#

It will be 0 0 since the second definition will create class attributes

wide shuttle
#

as then you're referencing a local name before the assignment in a function scope

undone hare
#

Or maybe just error out

stable grail
#

what if you create nested functions with name binding

wide shuttle
#

!e

x = 0
y = 0

class C:
    x = 1
    y = 1

    def f():
        print(x, y)
        x = 2
    
    f()
fallen slateBOT
#

@wide shuttle :x: Your eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "<string>", line 4, in <module>
003 |   File "<string>", line 12, in C
004 |   File "<string>", line 9, in f
005 | UnboundLocalError: local variable 'x' referenced before assignment
undone hare
#

Alright, so that’s pretty consistent

wide shuttle
#

I have a guess

#

If we remove the assignment, you should get the global scope

#

!e

x = 0
y = 0

class C:
    x = 1
    y = 1

    def f():
        print(x, y)  # 0 0 ?

    
    f()
fallen slateBOT
#

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

0 0
wide shuttle
#

right, makes sense

#

just like with other things that create a local scope within a class scope (e.g., the list comprehension above)

undone hare
#

With the class? Of course since you create class attributes

wide shuttle
#

that doesn't really matter, you can use the names

#

just not from within another local scope that you're creating

#

!e

x = 0
y = 0

class C:
    x = 1
    y = 1

    def f(x, y):
        print(x, y)  # 1 1

    
    f(x, y)
fallen slateBOT
#

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

1 1
stable grail
#

so when you add everything to a class

#

the "highest" scope it goes to is the <local> scope

#

so if we make something that has a very nested qualname

#

f.<local>.c.<local>.G

#

what local scope would it get the value from

#

im thinking that it gets it from the closest local scope

#

and the rest from the global

undone hare
#

Hmm that’s interesting

stable grail
#

you might not be able to create this though

#

my first attempt failed

#

can you only have one local scope?

wide shuttle
#

I don't think your logic is quite right

#

!e

x = 0
y = 0


def a():
    x = 1
    y = 1  # <- will happily use the second enclosing scope for y

    def b():
        x = 2

        class Foo:
            print(x, y)
            x = 3
        
    b()


a()
fallen slateBOT
#

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

0 1
wide shuttle
#

unless I misunderstood your argument

stable grail
#

!e

def f():
    def g():
        def h():
            pass
        return h
    return g

print(f().__qualname__)
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

f.<locals>.g
stable grail
#

im just wondering why h is left out

wide shuttle
#

you never called g

stable grail
#

!e

def f():
    def g():
        def h():
            pass
        return h
    print(g().__qualname__)
    return g

print(f().__qualname__)
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

001 | f.<locals>.g.<locals>.h
002 | f.<locals>.g
wide shuttle
#

You never called g in the first snippet

#

So, you never actually create h or return it from somewhere

stable grail
#

yeah, you where my rubber duck @wide shuttle 😄

wide shuttle
stable grail
#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1
    def g():
        x = 2
        y = 2
        class H():
            print(x, y)
            x = 3
    return g()

f()
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

0 2
stable grail
#

notice it only goes one local scope up

#

f.<locals>.g.<locals>.h

#

it picks the values from the first local scope

#

ist that a bit interesting as well @wide shuttle @undone hare ?

#

how does that even work?

#

is the local scope moved on top of a stack or?

#

since the values are not destroyed

#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1
    def g():
        x = 2
        y = 2
        class H():
            print(x, y)
            x = 3
    print(x, y)
    return g()

f()
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

001 | 1 1
002 | 0 2
wide shuttle
#

Those names will probably be turned into distinct numbered names

#

I think that's what happens for local names and closures

stable grail
#

and maybe thats what it does, just "pick the next local scope from the stack"

wide shuttle
#

And then the look-up order goes down the enclosing scopes again

stable grail
#

i dont know much about how the stack works under the hood though

wide shuttle
#

This is probably something that already happens in the compiler (to know which value to look up when)

stable grail
#

well, if it picks from the closest local scope, then if you nest classes inside classes, it should still pick from the closest local scope right?

#

nah.. im just thinking.. it should not, the class attribute will catch it

wide shuttle
#

this is where it gets interesting: I think this is when functions and classes start to divert in the OPCODES they produce

stable grail
#

but the most nested class should

#

!e

x = 0
y = 0

def f():
    x = 1
    y = 1
    class G:
        x = 2
        y = 2
        class H():
            print(x, y)
            x = 3
    return G

f()
fallen slateBOT
#

@stable grail :white_check_mark: Your eval job has completed with return code 0.

0 1
stable grail
#

yeah..

wide shuttle
#

Explains that the opcodes produced for functions are different

#

Scroll down to the last section before the conclusion

undone hare
#

I'll have to read that

stable grail
#

well.. ill add that to my reading list 😄

sonic idol
#

ModuleNotFoundError: No module named 'python_nbt'
what do LOL?

mint forge
mint forge
#

Nope doesn’t copy X from the global scope — you can verify this by adding a ‘print locals()’ after the existing print line, or by surrounding the ‘X = 2′ with an ‘if 0:’, and checking C.dict after the class is created.

As far as I can tell this isn’t a bug, since both CPython and PyPy produce this result, though I have no idea who would rely on this behavior.

Here’s the best reference that I could find:
http://www.gossamer-threads.com/lists/python/dev/254461

It’s an old thread from 2002 that seems to allude to this behavior being around for backwards compatibility. My reading is that at some point all lookups worked this way, ie this code would have printed “0 0″. Then at some point they added nested functions and changed the way that function scoping works, but didn’t apply the same change to class scoping.

The technical details are that there are a number of different opcodes that Python can use to look up names; in a function scope locals are looked up with LOAD_FAST, but in a classdef they are looked up with LOAD_NAME, which does not check any parent scopes and just skips to the global scope. Non-locals in classdefs are looked up with either LOAD_NAME or LOAD_DEREF, the latter of which will check enclosing scopes.

Not something you run into every day but something you have to get right as an implementor!

wide shuttle
#

Yeah, that's a comment to the blogpost Guido links

#

We were wondering why it worked that way, although the answer seems to be "this is just how it works" combined with "it works differently for functions" (probably to make closures powerful for functions)

tidal marten
#

Why is NoneType not declared in builtins?

#

!e

import builtins

print(type(None).__module__)
print(hasattr(builtins, 'NoneType'))
fallen slateBOT
#

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

tidal marten
#
001 | builtins
002 | False
peak spoke
#

Because there's almost no practical use for it, the type is not directly exposed anywhere in the stdlib afaik

mint forge
#

ye its not

undone hare
#

Is there even a way to get an handle to NoneType? Maybe type(None)

peak spoke
#

Yes, that's how most of the types from the types module are exposed

mint forge
#

But you don't have access to NoneType, so how would you compare it?

undone hare
#

Ah, it is in types

#

Can you subclass NoneType haha

native maple
#

github?

#

you looking at a module or just testing

peak spoke
#

No, NoneType is not in types, but most other things like FunctionType etc. are

#

Any it gets them just through type

def _f(): pass
FunctionType = type(_f)
undone hare
#

Fair

#

Now I want to find a way to subclass NoneType

#

I'm sure you can break half of the interpreter by passing a type like that around

tidal marten
#

NoneType not being in builtins is a bit inconsistent though

tidal marten
peak spoke
#

Why?

tidal marten
#

Because type(None).__module__ says it should be in builtins?

native flame
#
>>> class A(type(None)):
...     pass
...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: type 'NoneType' is not an acceptable base type

F

tidal marten
#

So basically it's just a hack, F

undone hare
#

There probably is a way tbh

#

If you use some ctypes magic to inject it in the MRO or something like that

tidal marten
#

NoneType can be a singleton as far as I know

undone hare
#

Yeah it is

tidal marten
#

But it is singleton in the sense that it has to use some magic so that the implementation is invisible

peak spoke
#

Looks like it'll be added back in to the types module in 3.10, along with EllipsisType and NotImplementedType

tidal marten
#

Someone should publish a null package on pip 😂
The slogan should be:

null is not None
peak spoke
tidal marten
#

Probably yeah

#
class Singleton(type):
    """
    This class is to be used as a metaclass.

        class SingletonObject(metaclass=Singleton):
            ...
    """
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instances[cls]


class NullType(metaclass=Singleton):
    def __repr__(self):
        return 'null'

    def __str__(self):
        return 'null'


null = NullType()
flat gazelle
#

doesn't work, since you can subclass NullType

tidal marten
#

It works fine though

>>> class MyNullType(NullType):
...     pass
... 
>>> MyNullType()
null
grave jolt
tidal marten
#

Well, when it's moved to types in 3.10, type(None).__module__ should print types

grave jolt
wide shuttle
#

Being able to determine the identity of an object sounds like a fundamental operation to me. I'd wager it's an important operation in Python's implementation as well.

#

For me, that makes it a strong candidate for being part of the builtins

thorny gyro
#
x, y = 0, 0
def foo():
    x, y = 1, 1
    class C:
        print(x, y) # 0, 1
        x = 2
foo()
#

Has this been discussed

mint forge
#

ye

grave jolt
wide shuttle
#

It's used within Python itself quite a few times, like equality checks for instances of user-defined classes

#

Obviously, you could say that such usage doesn't require it to be a builtin for users, but that makes it a fundamental operation to me

#

It's not some add-in provided by the standard library in addition to Python's core; it's a core feature

grave jolt
#

@wide shuttle But putting something in a different module is just a way of structuring things. Threading and multiprocessing are not "add-ins" either, nor is the dis module, or the traceback module, or the sys module.

#

Why is sys.getsizeof in sys, but id in the builtins?

wide shuttle
#

I don't really think they are the same

#

dis is an additional module for disassembly, traceback provides additional traceback-related features (but you'll find all the actual exceptions raised at run time in the builtins namespace).

#

but maybe that's all just categorization

pliant tusk
#

i would say theres an argument to be made for id to move into sys

wide shuttle
#

What would be your argument?

pliant tusk
#

id gets lowlevel information on an object, similar to sys.getrefcount and sys.getsizeof

limpid marten
#

I also think the name id being reserved is a bit sad.

grave jolt
#

moreover, id is implementation-dependent

pliant tusk
#

in that case youre issue is that the list your making is moved into the internal free lists array and reused

#

id is guaranteed to produce a unique id as long as its argument is a live object

peak spoke
#

I'm not really sure where they'd go but I'd rather see things like compile, exec memoryview etc. to be moved first; I use id regularly when debugging something so the same argument for it staying in buitlins could be made as for breakpoint

tidal marten
#

Maybe utils but that would mess with projects that use that name internally

true ridge
#

here it is

wide shuttle
#

Seems like a some mixed feelings, but quite a few people in favour of it in some form

#

Looks like it was initially put on the schedule for P3000 (courtesy of that first link you provided), but it was later removed from the changelist

#

I can't find much about that latter decision; I think it was a decision made by Guido at some point

grave jolt
#

here are all the stdlib modules that use id at least once:

_threading_local, asyncio.queues, asyncio.sslproto, asyncore, codecs, concurrent.futures, cProfile, ctypes, dataclasses, distutils, doctest, gzip, idlelib, importlib, inspect, lib2to3, multiprocessing, optparse, pickle, plistlib, pprint, pydoc_data, reprlib, tarfile, threading, tkinter, threading, unittest, weakref, xml, xmlrpc
peak spoke
#

there are also things like ord and chr I don't really see a need to be builtin (maybe in the string module) but they're used a lot in teaching

grave jolt
unkempt rock
#

hi is there any python package or module which gives information about the package present in the Pypi repository ?

#

using Pypi endpoints ?

peak spoke
#

Most of my uses of id would probably be one off scripts or the repl

unkempt rock
#

or it need to be created ?

unkempt rock
grave jolt
#

because of some allocation strategies, as chilaxan described below

peak spoke
#

It guarantees that every object will get an unique id at the time it's called, but as it loops the objects get dereferenced and can be reused

lone trench
desert peak
#

what is more "correct" when implementing protocols, typing or collections.abc?

#

@lone trench I think it's off-topic spam personally

lone trench
#

thanks

charred wagon
desert peak
#

can you expand on that thought @charred wagon ?

#

I'm just paging through mypy documentation and they use typing everywhere instead of collections

charred wagon
#

Maybe they haven't updated docs yet.

#

Python docs mark all the typing equivalents of collections.abc as deprecated

desert peak
#

oh, interesting

#

ah, not quite @charred wagon

#

You're thinking of the builtins

charred wagon
#

No, not just those.

#

Scroll down further to the abstracts

desert peak
#

It seems you should use abcs for the inheritance, but use typing for the params/returns

#

oh I see what you're talking about now

#

huh. I didn't know the abcs didn't support the generics syntax previously

radiant fulcrum
#

Wernt they also removing typing in future python versions?

charred wagon
#

I have not heard of that

desert peak
#

I don't think so. There are still valuable things in typing

#

you can't create "true" generics without typing

radiant fulcrum
#

Ah no they were removing the typing generics like List, Dict etc...

desert peak
#

that's going to be a hard habit to break (from typing import List, etc.)

radiant fulcrum
#

Yh

desert peak
#

especially since we don't even have access to 3.9 internally yet 😢

#

we just barely got 3.7 lmao

radiant fulcrum
#

Also waiting for the questions like why does list[foo] work but xyz not

grave jolt
#

or maybe people will just give up on it and just let third-party type checkers parse comments with type hints

desert peak
#

implementing strict static typing in Python 4 brainmon

grave jolt
#

Python 5 haskell

desert peak
#

Python 6 ⚙

raven ridge
radiant fulcrum
#

Alot of linters can parse doc string typings tbh

desert peak
#

type annotations came around because of the type hint comments of mypy

grave jolt
#

yeah, that makes sense

desert peak
#

it's a shame they took so long to come about. TypeScript exists because of jsdoc in a lot of ways

grave jolt
#

Speaking of type hints... it seems to me that different type checkers (mypy/pyright/pyre/...) are not really compatible with each other. When you try a different type checker or try your type checker on an existing project, you get lots of type errors

raven ridge
#

Yep.

grave jolt
#

...because each type checker interprets the PEPs with its own interpretation

#

and e.g. pyright has recursive type aliases, while mypy doesn't

desert peak
#

that hasn't been my experience and I flip between intellij/vscode pretty often (mypy v. pyre)

grave jolt
#

...and mypy treats Callables in class attributes weirdly

grave jolt
#

or are you using mypy on its own?

desert peak
#

It's my understanding it uses mypy under the covers. I use mypy in my CI as well

#

ah, pyright is the other thing I use, not pyre (via pylance)

#

the one thing I find unbearable about pycharm/intellij is its use of pep8 instead of letting me specify a linter

grave jolt
#

I recently tried pyre on my small project instead of pyright, and it gave me dozens of errors 👀

desert peak
#

yeah, never used pyre so can't speak to that

radiant fulcrum
#

Pycharm doesn't use mypy under the hood

#

Theres an optional extension for it

desert peak
#

👀

unkempt rock
#

unexpected behaviour with other librararies or just unexpected behaviour which wouldn't happen if you didn't use it

#

idk seemed hacky

grave jolt
#

You're not mutating the actual module object

desert peak
#

is top-level await allowed in py37? or do I have to use asyncio.gather or something?

#

I'm already using aiohttp; don't want to add another deps for one call

radiant fulcrum
#

Huh?

#

If you're gonna start an event loop and use it youlo need asyncio or trio to actually start and run the event loop

#

Only certain repls like ipython support awaiting dorectly in the repl

grave jolt
#

Yeah, top-level await doesn't make sense, because await isn't tied to a particular implementation of an event loop.

#

Yeah, top-level await doesn't make sense,
(apart from repls)

radiant fulcrum
#

Writing your own event loop verycool

#

@grave jolt plz

#

Sorry for the targetted ping but on mobile with dms off so modmail is 😩

grave jolt
#

!ban @unkempt rock spreading malware

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @mellow cedar permanently.

grave jolt
#

thanks

stable grail
#

is the link somewhere else?

grave jolt
#

no

stable grail
#

good

radiant fulcrum
#

Erm

grave jolt
stable grail
#

same

radiant fulcrum
#

Theres another dude...

stable grail
#

its the same thing as last time

grave jolt
#

ye, he posted to pygen as well

#

!ban @soft tundra malware

fallen slateBOT
#

:incoming_envelope: :ok_hand: applied ban to @soft tundra permanently.

desert peak
#

oof

#

so what's the way to accomplish top-level await, using asyncio.run?

radiant fulcrum
#

you can yeah

raven ridge
#

Conceptually, what await does is ask the currently running event loop to suspend the current coroutine and run the need runnable task. You can't do it at the top level because there's no event loop to yield to at the top level

#

asyncio.run() creates an asyncio event loop and runs the coroutine using it.

grave jolt
#

yep, and if you decide to use e.g. trio, you're in trouble

raven ridge
#

There are other types of event loops that you can create instead, but the asyncio one is the only one that ships with Python

radiant fulcrum
#

One thing i did learn with trio

desert peak
#

my use-case here is avoiding adding requests to my dependencies when I already have aiohttp

radiant fulcrum
#

is that its is depressingly slow compared to asyncio in terms of its socket handling

radiant fulcrum
#

or use urllib 😉

desert peak
#

well I need an async client since I make the requests in my web server request lifecycle

#

my whole architecture is built around being async since most of my app is interacting with DBs and other web services

radiant fulcrum
#

okay, but do you have like an explicit dep on aiohttp or can you use an alternate client 🤣

desert peak
#

aiohttp looked like it had better support than httpx

#

I had an explicit dep on aiohttp ^

#

not that I need it, but I did have a need for an async client

radiant fulcrum
#

Httpx Is fairly nice and a bit more sane than aiohttp

desert peak
#

HTTPX should currently be considered in beta.

#

that's what drove me away

radiant fulcrum
#

I mean sureee

raven ridge
#

Things tend to move straight from beta to abandoned, heh

radiant fulcrum
#

But its in quite a late beta now and mostly due to the http2 support

desert peak
#

"we should be 1.0 in late 2020" hasn't happened, so even more 👀

#

I work for a large financial institution, they balk at non-production-GA dependencies

raven ridge
#

For lots of projects, beta means "I'm still changing this", and the next stage after that is "whatever I give up it works"

radiant fulcrum
#

Tbh idk why im pushing httpx cuz not like i use it any more than aiohttp

desert peak
radiant fulcrum
#

ig the biggest pull for httpx is the http2 support

desert peak
#

what does Coroutine[T] signal to an API consumer, that T is the return type if you await?

#

since async signals the fn returns a Coroutine, right?

radiant fulcrum
#

Typically its Coroutine[Any, Any, T]

desert peak
#

:head spins:

radiant fulcrum
#

because it follows the generator type pattern

desert peak
#

you spoke past me with that one. mind expanding?

radiant fulcrum
#

Well coroutines are built off the idea of having a generator with yield that lets you suspend that function

#

the generator can yield a different type to what it returns

#

but it can also have foo.send(x) called on it to wake up where it yielded from and return the value from it yield

#

so you have a yield type, return type and send type i think

raven ridge
#

You may want to use Awaitable instead of Coroutine. Then it would just be Awaitable[T] to signal that calling await on it returns a T.

desert peak
#

wasn't aware that type existed, neat

#

the asyncio stdlib documentation really sucks

radiant fulcrum
#

honestly cuz the community that built it dont really have much of an idea either

#

Some of the confusion thats happened in the past in the community is notlikeduck

desert peak
#

"nodejs is great, let's copy it!" "wait, how do eventloop?"

radiant fulcrum
#

my biggest peeve is the streams api

desert peak
#

of all the async APIs I know, I like .NET's the most

#

the Task<T> is so easy to understand

raven ridge
#

asyncio has improved a lot... 3.7 was a massive leap forward over 3.6 in terms of providing higher level interfaces that people can actually understand.

#

Unfortunately, all the low level stuff is still there, and it's still possible to find the wrong stuff...

radiant fulcrum
#

Trio is the 'sane' version of asyncio

#

the only issue with trio is the speed

#

in the sense that it is really slow in the areas where async should excel

desert peak
#

like i/o resources?

radiant fulcrum
#

mhmm

#

like waiting for socket readiness etc...

#

instead of the callback approach which tbf is probably the best part of asyncio and actually really well implemented in terms of efficiency, they use a fixed awaitable that only awaits once then you have to await again

desert peak
#

I think my biggest disdain about python is its use of functions over interfaces

#

like len() map() etc

#

an __iter__ should be able to use a map postfix

radiant fulcrum
#

you mean the fact you have to call a function that just calls another function thinking_derp

desert peak
#

yeah

spice pecan
#

give pipe operator

desert peak
#

how would that even look

my_iterable
|> map fn

?

spice pecan
#

I guess we'd either need a way to pass multiple arguments or create partial (curried) functions

desert peak
#

I think C# & TS are working on that

#

last I saw

spice pecan
#

iterable |> functools.partial(map, int) is not really making it better, perhaps *(func, iterable) |> map?

desert peak
#

gross, no

#

less syntax, not more

spice pecan
#

Fair enough

grave jolt
#

But composing iterator functions is a pain, yeah

desert peak
#

I've been writing a lot of Rust over the past few months in my free time and coming back to Python gets worse each time 🤷

grave jolt
#
    foo
    .iter()
    .map(...)
    .filter(...)
    .flat_map(...)
    .to_list()

yeah^

desert peak
#

if __iter__ exists, you should be able to just call .list() imo

#

in addition to the other iterator methods

#

but that's probably a pretty big breaking change

grave jolt
#

The difference between Python and Rust is that Python doesn't have much static information at all, so all available methods need to be placed in the definition of a class.

#

I guess you could inherit from Iterable...

desert peak
#

oh I'm aware, it just makes me sad

#

so say I'm writing an async function, what's the most appropriate annotation for its return type?

#

Awaitable[T]? since that's the only intended use-case is to await on it?

#

I notice a lot of libs just ignore annotating async fns entirely

grave jolt
desert peak
#

hm, interesting

peak spoke
#

The coroutine function's return type should just be as normal

desert peak
#

gotcha

grave jolt
#

but yeah, Awaitable/Coroutine would just be redundant in async

#

Also @desert peak if you want an exercise, make two functions to transform between Iterator[Awaitable[T]] and AsyncIterator[T] 🙂

desert peak
#

nah, I've got work to get done 😄

grave jolt
#

Iterator[Awaitable[T]] -> AsyncIterator[T] is easy, the other way around -- not so much

desert peak
#

it's a shame yield from was removed from async fns

#

could've eased that implementation some

#

I'm not entirely sure on the reasoning

grave jolt
#

@desert peak Iterator[Generator[T, S, R]] <-> Generator[T, S, R] would look pretty much the same

desert peak
#

I think it'd be cool to see a Rust implementation of Python. I think it could benefit from its ease of development for new features

#

Though it'd be wildly unpopular with the existing developer base

astral gazelle
#

RustPython is a thing iirc

desert peak
#

pyo3, but it's not actually a Rust implementation of Python

#

it's for developing new extensions instead of C

radiant fulcrum
#

Rust Python is a thing indeed

#

We're also slowing making progress to adding some better support for async and await stuff in PyO3 although the system is a lil naive atm

#

Rust python may also become the first python interpreter built around the idea of what numba's JIT does with LLVM but with cranelift

desert peak
radiant fulcrum
desert peak
#

what's the benefit of the cranelift backend?

radiant fulcrum
#

Well CraneLift is a much faster compiler

#

Which will eventually become rust's debug compiler

#

But the general aim of RustPython's JIT is to allow the entire Python system to become JIT compiled making use of CraneLift's speed

desert peak
#

I think RPython would've been a catchier name akin to CPython

#

does that mean RustPython would ship with cranelift's compiler?

#

to accomplish the JIT?

radiant fulcrum
#

Well the Jit contains cranelift itself

#

Atm the standard none JIT system of RustPython is a little slower than CPython atm

#

but ig thats to be expected as its no where near as optimized as it could be

desert peak
#

no releases since Jun'20 makes the project look dead

radiant fulcrum
#

think 1.2 was the first semi stable release with out the std lib

desert peak
#

are y'all using CFFI for now?

#

or is std actually implemented?

radiant fulcrum
#

for which

#

rust python?

desert peak
#

yeah

radiant fulcrum
#

not really something you'd use for production rn, they're just slowly building the std lib up

#

So today for example introduced a bunch of unit tests for implementing the random lib

#

aim seems to mostly be implement unittest properly so they can start using Cpython's test suite

#

btw

desert peak
#

obvi (on non-prod rn)

radiant fulcrum
#

did you know its possible to override the coroutine wrapper?

desert peak
#

I haven't used any asyncio prior to adopting FastAPI at Q4 last year. Never really had a need

grave jolt
radiant fulcrum
#

ikr

desert peak
#

rip

radiant fulcrum
#

Oh i see now

desert peak
#

I imagine the hardest part is just getting the execution model and grammar correct, no?

radiant fulcrum
#

I partiality updated my branch due to conflicts blobpain

#

so im missing like

#

600 commits

#

time to delete and re-clone ig

true ridge
desert peak
#

if you guys had a coworker who makes the worst APIs you've ever seen and hasn't improved in two years, how would you even begin to handle that? Just ran into one of the dumbest issues I've seen this week where a required attribute goes uninitialized intentionally

#

which breaks downstream

true ridge
#

I've contributed very little in the past, though it is really hard to just keep hacking on it. not really relevant with the project but rather rust is a bit annoying in terms of compile speed

desert peak
radiant fulcrum
#

Rust's particular setup with LLVM seems to like high clock speed

#

My PC with 6 cores at 5ghz will beat my server running 16 Cores at 2ghzthinking_derp

desert peak
#

hm, rustc seems to use all my cores at full utilization just fine

radiant fulcrum
#

Alot of it is affected by the compiler config in the toml

#

hopefully alot of the issues with compile speed for debugging will be fixed with cranelift when it eventually becomes stable

desert peak
#

but won't that cause subtle differences between profiles?

#

if you use rustc backend for release and cranelift for dev?

radiant fulcrum
#

I mean yeah but you shouldnt be using debug to bench stuff anyway

#

debug mode can quite literally be between 10 - 100x slower than release mode

desert peak
#

I see

desert peak
#

@true ridge are you a maintainer for anything CPython or a contributor alone?

true ridge
#

I ~maintain the AST interface. We dont really have a maintainership / subsystem concept, but rather (not official) zones (codeowners)

desert peak
#

is there any excitement for Rust among CPython devs?

true ridge
#

AFAIK there are some people who are really interested in Rust, and pyoxidizer

#

I also want to start writing it, but like as I said, it really annoyed me with high compile times. If it will be improved in the future, I don't see a reason to not to write rust

desert peak
#

I think that's one of their big goals with ed'21 is a better const story which should help compile times

#

the improvements of Rust since 1.0 have reminded me a lot of C# improvements in the same timespan now with Nadella at the head. It's like we entered this super developer-focused timeline after the stagnation of the 2000s

#

I suppose Python also fits in that boat with py27 finally gone and people actually moving their packages forward

radiant fulcrum
#

i agree for the most part

#

do feel like python's async system is sorta stagnating though

swift imp
#

Python needs serious development on speed

#

Like js is just as dynamic and is fast

radiant fulcrum
#

Well JS is a JIT compiled lang and also has alot of semantics that allow it to not have the same sort of hurdles as python does

#

equally everyone who's really maintaining python is doing as a volunteer and unless someone feels motivated enough to try improve the performance it wont get much better

#

I personally wouldn't want to try optimized Python's C code base notlikeduck

limpid marten
#

JS is jitted? By what?

radiant fulcrum
#

Wdym by what

#

its entire implementation is built around a JIT compiler and a async runtime

limpid marten
#

I didn't know V8 JITed.

radiant fulcrum
#

IIRC i believe all runtimes for JS are built off a JIT

#

JS as a language is alot younger than Python as well as it's runtimes so it was able to learn alot from python's mistakes

desert peak
#

not really

#

~'96 or so?

#

when was py20?

radiant fulcrum
#

95 was the original version

desert peak
#

JS did see new life with nodejs and Google investment with V8

radiant fulcrum
#

But bearing in mind JS went though the massive re-design and re-implementations that lead to V8, libuv etc....

#

what was it called again bow

#

ES6?

desert peak
#

?

radiant fulcrum
#

the JS language spec thats used now

desert peak
#

it's always been ES

#

that happened in the mid 00s

limpid marten
#

I really have a hard time believe JS beats Python benchmarks.

radiant fulcrum
#

You should believe it

desert peak
#

it's public info... it beats it handily

radiant fulcrum
#

JS is wayyyy faster runtime wise

#

Async by default + incredibly fast development in it's libs

limpid marten
#

I wonder how it compares when you use something like numba.

radiant fulcrum
#

wont change much if at all

limpid marten
#

Clearing a JITed language has it's advantage.

radiant fulcrum
#

well yeah

#

Sadly Python's asyncio basically kill's PyPy's advantage

#

If you ever wonder why Japronto is so much faster than any of the others

#

Its just because Japronto pipelines

#

all the others just queue

desert peak
#

?

radiant fulcrum
#

?

desert peak
#

I don't understand what pipelining means I guess

radiant fulcrum
#

Before Http2

#

Pipelining was the concurrent way of sending requests

desert peak
#

oh gotcha

radiant fulcrum
#

So the client sends many requests before getting the first response back

desert peak
#

duplexing

#

is what you're referring to

radiant fulcrum
#

the only issue was that servers never really behaved properly, along with DNS issues etc... and HTTP/2 came around

#

so basically all of those tech empower benchmarks are pretty much entirely un-realistic as your clients will never really send pipe lined requests

desert peak
#

too bad http/2 support still suffers

radiant fulcrum
#

disabled is all modern browsers

desert peak
#

it's coming around - very slowly

radiant fulcrum
#

Hyper.rs Is likely the fastest framework made in the real world

desert peak
#

speed rarely matters for most projects, however

radiant fulcrum
#

Yeah

#

Which is why Hyper is incredibly powerful

desert peak
#

people doing pre-optimizations picking the wrong tool for their job

#

I personally like Rocket from an ergonomics perspective

radiant fulcrum
#

because it has a complete HTTP spec coverage as well as a the work stealing tokio runtime

desert peak
#

I want to make the case for Rust at work, but I think my scaffolding cli will have to do for now 😅

radiant fulcrum
#

I preach the work stealing runtime for everything where its good for it lol

#

Websocket gateways are just

#

I want to implement Http2 for my rust server but yikes the amount of info on it is not nice to try make

desert peak
#

no, not at all

#

the spec is very complicated

#

and featureful

radiant fulcrum
#

Basically HTTP/1 pipe lining but sane

#

My aims atm are:

  • Finalizing HTTP/1 ASGI stuff
  • Writing the WS protocl
  • Adding HTTP/2
#

fun times

desert peak
#

I wish there was a rich-like cli lib for Rust or tqdm

#

Python has so many nice libraries

radiant fulcrum
#

Clap is pretty good

#

Also some amazing cli basic gui systems for rust

desert peak
#

I'm looking at clap v. structopt rn

#

they look like they implement the same API so I'm unsure which to use

#

but clap has major versions?

radiant fulcrum
#

Claps always done me good

desert peak
#

Oh I see now

#

structopt is derivative of clap

swift imp
#

because classes use the module level scope for some reason

#

not the local scope

#

its weird

solemn hedge
#

but why does y = 1?

spiral willow
solemn hedge
#

Yeah I tried that too

solemn hedge
#

I think I kind of get it. Any changes or reassignments to certain module level variables will make them be module level regardless (as long as inside the class)to the position of the change or reassignment?

brave badger
#

!e Interestingly enough

x = 0
y = 0
def f():
    x = 1
    y = 1
    class g:
        print(x, y)
        x = 2
print(f.__code__.co_varnames)
fallen slateBOT
#

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

('x', 'g')
spiral willow
#

I guess, it was itneresting to look at, however, if this is actual problem, it sounds like software design issue

swift imp
solemn hedge
amber nexus
#

The X is the confusing part

#

y makes perfect sense

native flame
#

I mean I can understand what's happening but I've no idea why it's designed that way

unkempt rock
#
x = 0
y = 0
def f():
    x = 1
    y = 1
    class g:
        nonlocal x
        print(x, y)
        x = 2
f()
#

1 1

raven ridge
#

https://docs.python.org/3/reference/executionmodel.html#binding-of-names

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

https://docs.python.org/3/reference/executionmodel.html#resolution-of-names

Class definition blocks and arguments to exec() and eval() are special in the context of name resolution. A class definition is an executable statement that may use and define names. These references follow the normal rules for name resolution with an exception that unbound local variables are looked up in the global namespace.

#

So - the assignment to x inside the class g makes x a local variable for that block. When the x is resolved at the time of the print, the local x variable is unbound, so resolution falls back to the global x variable, which is 0.

Meanwhile, the y variable isn't bound inside the class g block, so it isn't a local variable, and so it follows normal resolution rules:

When a name is used in a code block, it is resolved using the nearest enclosing scope.
And that finds the nonlocal y that's set to 1 in the scope of the enclosing function.

tidal marten
#

So in a sense, you cannot have anonymous classes?

raven ridge
#

the first argument to the type constructor is a name, so no - every class has a name.

#

Though, weirdly, it's allowed to be an empty string.

#

!e ```py
C = type("", (), {})
print(C())
print("Name:", C.name)

fallen slateBOT
#

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

001 | <__main__. object at 0x7f569692dfd0>
002 | Name: 
red solar
#

Can u print dir(C()) too?

raven ridge
#

!e ```py
C = type("", (), {})
print(vars(C))
print(vars(C()))

fallen slateBOT
#

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

001 | {'__module__': '__main__', '__dict__': <attribute '__dict__' of '' objects>, '__weakref__': <attribute '__weakref__' of '' objects>, '__doc__': None}
002 | {}
raven ridge
#

vars is probably more interesting than dir.

red solar
#

Lol just {}

#

Thnx 🙂

#

(Was in bed and curious, I have nothing to add)

tidal marten
#

I mean, anonymous in the sense that returning a function is creating anonymous function

sacred yew
#

yeah that works

tidal marten
#
def myfunc():
    def _anonymousish():
        pass
    return _anonymousish
sacred yew
#

changing anonish to a class should work the same way

tidal marten
#

But the scoping is messed up

#

As of now anyway

#

I actually like Ruby's closure thingy. I don't think you can do something similar with lambda?

raven ridge
gleaming rover
#

that would be lambda

#

and the analogue (kinda) would be creating a class with type

gleaming rover
raven ridge
#

It's as close as you can get, at least.

#

heh, you can also do:

#

!e ```py
def foo():
return type("<lambda>", (), {})
print(foo())
print(foo()())

fallen slateBOT
#

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

001 | <class '__main__.<lambda>'>
002 | <__main__.<lambda> object at 0x7f107c8cbfa0>
tidal marten
#

I thought class declaration uses the module scope instead of function scope?

#

Or is it just a bug in the current version?

raven ridge
#

no, that's not what's happening. Read the docs paragraphs I pasted again.

#

What you're seeing there is a quirk of class bodies, as opposed to def bodies - when something would result in an UnboundLocalError if it were done in a def body, doing the same thing in a class body results in a lookup against the module globals instead.

tidal marten
#

Oh, okay. That's actually reasonable.

raven ridge
#

but given that the same thing would be an error if you did it in a def, it doesn't have anything to do with whether it can be used for closures.

#

I'm betting the reason for that quirk is to allow you to do things like:

SOME_CONSTANT = 42
class C:
    SOME_CONSTANT = SOME_CONSTANT
#

that is, it gives an easy way to re-expose module globals as class attributes.

tidal marten
#

I can't do something like this tho...

def a():
    x = 10
    class A:
        x = x
    return A
print(a().x)
#

Oh wait, using other names for the class variable (i.e. not x) works fine

mint forge
#

you need to do a()().x

raven ridge
#

no, you don't - it's a class variable.

raven ridge
fallen slateBOT
#

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

10
tidal marten
#

I'm thinking about those Java callbacks with anonymous classes

raven ridge
#

those are usually written as lambdas instead, in modern Java

tidal marten
#

Yeah

raven ridge
#

they were only ever classes because Java didn't used to have any way to pass a function around, only a class instance.

#

(That's the case for a lot of design patterns - many of them are just workarounds for limitations in the Java language)

#

Singleton is the classic example - it's a way to create a global variable in a language that doesn't allow global variables.

tidal marten
#

Yeah

#

Now that I think of it, this is pretty useless lol

def a(x):
    class A:
        def __init__(self, y):
            self._y = y
        def get_value(self):
            return x + self._y
    return A
print(a(10)(11).get_value())
#

Maybe useful for programmatic class declaration, code generation?

raven ridge
#

🤷 functions that create classes aren't necessarily useless.

#

Yeah, that's probably the best use case for it.

#

or possibly class decorators.

tidal marten
#

Yeah

finite sparrow
#

Singleton is the classic example - it's a way to create a global variable in a language that doesn't allow global variables.
Singleton is usefull if you're writing a library and want to prevent the user from making duplicate instances of a class, if there can only ever be a single instance of it but it has to be user made

flat gazelle
#

but how often does such a class exist?

finite sparrow
#

or to work around circular imports since you can import the class instead of the instance

#

i mean i've had the need like, 2 times in a few years

#

its definitely not common but saying there is literally no need since we have globals is just wrong

flat gazelle
#

I feel like most of these cases could be replaced by a module or something like SimpleNamespace

finite sparrow
#

you cant instantiate a module with say, a API token.

#

and im not sure how SimpleNamespace would help that either (tho i have to admit this is first ive heard of it)

flat gazelle
#

I guess if you need global state which needs outside data which it cannot load itself (for example the data needs to loaded late in the loading) and it needs more complex logic rather than just being a mapping of attributes to values then there is value in making a singleton. So ye, IG there is merit to the pattern.

finite sparrow
#

now, i will admit that i did implement and publish a library for multitons without knowing any use case lmao

twilit zealot
#

Hey
Sorry for disturbing
Python 3.9.1 is not working properly

unkempt rock
twilit zealot
#

I wound many Bugs and its Totally hard to use it
The python is not working in the terminal
the command python in terminal is not working

#

I want to switch on 3.8
But show any one
Please help me

boreal umbra
raven ridge
#

That is, the singleton pattern refers to a particular way of creating and guaranteeing that only one instance of a class will ever exist, designed around the limitations of a language without global variables

boreal umbra
raven ridge
#

Depends what you mean by "singleton class". Are there times when it makes sense to make a class where only one instance should ever exist? Sure. Are there times when I would use the singleton pattern to accomplish that? No.

boreal umbra
raven ridge
#

That's not the singleton pattern, either. The singleton pattern has a private constructor and a public getInstance method

#

Though I wouldn't do either of those 🙂

boreal umbra
raven ridge
#

I've occasionally used the monostate pattern, though. I like it better than singleton: rather than restricting that only one instance can be created, it allows any number to be created, but all of the class's state is stored in class variables rather than instance variables, and so an update made through one instance is visible through all the others.

raven ridge
#

I can't remember a particular case, but you could imagine using it for logging, for instance. As it works today there logging.getLogger(name="") which looks up an existing logger with that name, and creates one of it hasn't already been created. Instead, it could create a brand new LoggerImpl object (a monostate that the user has configured), and each time it wants to log something it could pass the name along to instance methods of the LoggerImpl, which handle it according to the configured class state. Or something.

#

Caches are another good example. You could imagine an HttpCache that would use the monostate pattern to encapsulate responses cached by request as class variables, and anyone who wanted to see if something has already been cached would construct a new HttpCache and call lookup(url) on it, and - since it shares state with every other HttpCache that has been created, that'll work

finite sparrow
raven ridge
finite sparrow
raven ridge
#

Well, 🤷‍♂️ - what do you think the word "pattern" means in "singleton pattern"?

#

I think it refers to an approach that can be taken to create objects that are singletons.

#

And I would argue that other approaches to creating singleton objects are not the singleton pattern.

finite sparrow
#

okay so, wikipedia agrees with me. every otger resource I've ever seen about singletons agrees with me. if you want to follow your own definition by all means go ahead but that will make communication vastly more difficult

raven ridge
#

Is a module level _STATE = {} in Python a singleton object? Is it an example of the singleton pattern?

finite sparrow
#

is it a class? no. looks like a dict to me which is a instance of the dict class.

#

and has no way to ensure onoy one instance exists

#

hence: no singleton

raven ridge
#

Well, if your definition is that there's a guarantee that only one instance ever exists, then it's not possible to create a singleton in Python.

finite sparrow
#

its not about a absolute guarantee, you can always monkey patch your way around, but about normal usage, like instantiating a class with a constructor, returning the same instance

#

if you want to look at dictionaries specifically i would argue they are more like multitons, since the same arguements return the same instance

raven ridge
#

How about ```py
class MyState():
pass
MY_STATE = MyState()
del MyState

#

Is that a singleton object? Is that the singleton pattern?

finite sparrow
#

the fuck

#

!e ```py
class MyState():
pass
MY_STATE = MyState()
del MyState
print(id(MY_STATE), id(type(MY_STATE)()))

fallen slateBOT
#

@finite sparrow :white_check_mark: Your eval job has completed with return code 0.

140708913422288 140708913422240
finite sparrow
#

doesn't look like a singleton to me

#

hiding the constructor is not something i would consider a singleton, though that's more arguable then whether a singleton has to be specifically the Java implementation

raven ridge
#

You've moved the goalposts, I'd say. A minute ago you said it's about "normal usage", and then you took an object, called type() on it, and called the resulting class - that's not normal usage for an object.

finite sparrow
#

hmm, again as i said that's something I'm not so sure on, even though i think type() is normal enough ymmv

raven ridge
#

calling type to check the type of something is pretty normal, but calling the resulting type isn't common.

finite sparrow
#

fair enough, in that case yes you could say that's a singleton, though when doing it like this there truly is no advantage

raven ridge
#

And the WIkipedia implementation of a Python singleton is py class Singleton: __instance = None def __new__(cls, *args): if cls.__instance is None: cls.__instance = object.__new__(cls, *args) return cls.__instance But you can get another instance of that class as easily as doing: ```py
new_inst = object.new(Singleton)

#

that's not any trickier than calling type(), I'd say.

finite sparrow
#

all the advantages i can think of rely on the fact the instantiation can be done elsewhere

finite sparrow
#

the Wikipedia implementation is one that i would consider since it allows for instantiation elsewhere

raven ridge
#

well, so does this: ```py
_MY_THING = None
def get_my_thing():
global _MY_THING
if _MY_THING is None:
_MY_THING = _create_my_thing()
return _MY_THING

finite sparrow
#

at that point were talking about the usefulness off specific implementations which depend on the specific requirements

raven ridge
#

I don't think we are, still - because I don't agree that that's an implementation of "the singleton pattern"

#

though it is a way to create a variable that is intended to only ever be created once during the program's execution.

finite sparrow
#

and as i said, every resource i found disagrees with you, this is becoming pointless.

raven ridge
#

the singleton pattern, as described by GoF, is summarized on that Wikipedia page:

The singleton design pattern describes how to solve such problems:

Hide the constructor of the class.
Define a public static operation (getInstance()) that returns the sole instance of the class.

The key idea in this pattern is to make the class itself responsible for controlling its instantiation (that it is instantiated only once).
The hidden constructor (declared private) ensures that the class can never be instantiated from outside the class.
The public static operation can be accessed easily by using the class name and operation name (Singleton.getInstance()).

#

If you're arguing that "the singleton pattern" is broader than what the GoF called "the singleton pattern", then fine. But what you're describing is not what the people who coined the term were describing.

#

if other resources have made up their own, different pattern, and then said "and this is also the singleton pattern" - well, there's nothing I can do about that, but now there's two patterns instead of one and the same name is being used for both.

grave jolt
#

If only one instance should be possible, why not implement it as a module? Unless you're doing some importlib hackery, there's only ever one instance of a module.

#

the "constructor" can also automatically disappear

raven ridge
#

FWIW that doesn't take importlib hackery, it's enough to do:

import foo as lib1
import sys
del sys.modules['foo']
import foo as lib2
grave jolt
#

ah, well, yes

raven ridge
#

it's so easy to do that sometimes people do it accidentally. import foo after running python foo.py...

#

alright - considering our disagreement over what does and doesn't constitute "the singleton pattern", I'll amend my thoughts above: since in Python it's impossible to create a class that can only be instantiated once, you may as well just use module-scoped variables, possibly lazily initialized.

#

we can disagree about whether it's a limitation of Java that necessitates the singleton pattern or a limitation of Python that makes it unenforceable, but regardless of which of those two it is, there's not much point in using it in Python.

spark magnet
#

i'm kinda glad i missed the singleton debate 🙂

grave jolt
raven ridge
#

why not both?

grave jolt
#

not sure what you mean in either case

raven ridge
#

python is both compiled and interpreted - and, referencing the "why not both" meme 🙂

feral cedar
#

usually whenever it comes up someone ends up going "well aaaaaactualyyyyyyy"

raven ridge
#

It's the quickest way to end the pointless discussion, heh

tidal marten
#

Compiled? You mean compiled to bytecode?

raven ridge
#

Yes. CPython compiles Python code to CPython bytecode, which it then interprets.

tidal marten
#

Is there a way to delete an object but not destroy the variable?

#

Like

a = SomeObject()

...

if some statement or otherwise:
    del a

...

if a is None:
    print('No value')
paper hatch
#

does a = None work? Also this sounds like something for a help channel

tidal marten
#

I just wonder if Python has similar mechanism to like C++

brave badger
#

The object would be GC'd if the refcount drops to zero

#

Python's names are different to that of C++'s in the sense that there's no "uninitialized" state to them

#

Names in Python reference some object in memory, whether it'd be an arbitrary object or None

tidal marten
#

So the most efficient way to delete objects are like this?

value = receive_some_object_from_function()
value = None  # garbage collected
#

I assume setting to _ won't actually delete the object

raven ridge
#

del value or value = None will both drop the reference to the object that was held in value, and that may make the object eligible for garbage collection if there are no other reachable references to it.

brave badger
raven ridge
#

With del value the variable no longer exists, and you'll get a NameError if you reference it.

#

With value = None it still exists, and holds a reference to the None object.

tidal marten
#

Hmm, okay

raven ridge
#

value = 42 would work just as well to drop the reference to whatever object you're done with, and replace it with a new reference to an int object with the value 42.

kindred forge
#

can someone tell what is the difference between pythonfire and argparse ?

#

are they both same or they have different use cases?

barren aurora
#
>>> type.__class__
<class 'type'>``` hmm, how does this even work?
#

and that could go forever like, type.__class__.__class__....

undone hare
#

type is defined in C, so I guess it actually is an instance of itself

brave badger
#

I believe it's because of the fact that primitive (meta)classes themselves aren't actually Python classes, but are implemented in such a manner that they're indistinguishable from normal Python classes when used in Python code.

#

If it quacks like a duck, it's probably a duck[, even if it's not]

undone hare
#

You can see that it is implemented in C due to the operator overloading signature

#

!d type

fallen slateBOT
#
class type(object)``````py
class type(name, bases, dict)```
With one argument, return the type of an *object*. The return value is a type object and generally the same object as returned by [`object.__class__`](stdtypes.html#instance.__class__ "instance.__class__").

The [`isinstance()`](#isinstance "isinstance") built-in function is recommended for testing the type of an object, because it takes subclasses into account.... [read more](https://docs.python.org/3/library/functions.html#type)
barren aurora
#

oh

undone hare
#

I wonder if operator overloading will ever be a thing in Python

#

I really hope so

tidal marten
#

Would there be a way to actually make everything consistently act as objects, even with primitives?

flat gazelle
#

everything does act like objects

tidal marten
#

Hmm, yeah... 🤔

barren aurora
undone hare
#

I don't think this is a thing yet

barren aurora
#

oof

#

though it would be good to have it

tidal marten
#

Isn't there an overloading decorator?

#

I forgot where it is, maybe in typing

flat gazelle
#

how would you imagine that working? type hints aren't really consistent enough to make this possible

barren aurora
#

wait a second

#

there is an __add__ method

undone hare
#

Eeehh.. First level typehints could work

tidal marten
#

Someone paste the docs for typing.overload here

mint forge
#

!d typing.overload

fallen slateBOT
#
@typing.overload```
The `@overload` decorator allows describing functions and methods that support multiple different combinations of argument types. A series of `@overload`-decorated definitions must be followed by exactly one non-`@overload`-decorated definition (for the same function/method). The `@overload`-decorated definitions are for the benefit of the type checker only, since they will be overwritten by the non-`@overload`-decorated definition, while the latter is used at runtime but should be ignored by a type checker. At runtime, calling a `@overload`-decorated function directly will raise [`NotImplementedError`](exceptions.html#NotImplementedError "NotImplementedError"). An example of overload that gives a more precise type than can be expressed using a union or a type variable:... [read more](https://docs.python.org/3/library/typing.html#typing.overload)
undone hare
#

That's a misleading tutorial

flat gazelle
#

then you need ambiguous call errors and other such silliness

barren aurora
flat gazelle
#

that is not quite right

tidal marten
#

Maybe Python is biting more than it can chew with overloading

flat gazelle
#

but it is close enough for most things

tidal marten
#

Imagine Python 4.0 coming in with a strict mode that enforce typing lol

brave badger
#

!pep 638

fallen slateBOT
#
**PEP 638 - Syntactic Macros**
Status

Draft

Created

24-Sep-2020

Type

Standards Track

brave badger
#

This could work?

flat gazelle
#

we are slowly getting closer and closer to raku

modern night
#

using metaclasses, you can overload bound methods within class bodies but it doesn't work with dunder mathods from my experimenting (and linters really don't like you doing it)

#

I made this, but as you can imageing, the implementation of the metaclass is very hacky (and idk if the logic beind the overload is consistent with other languages, just how i thought to implement it)```py
class TypeOverloaded(metaclass=TypeOverload):

var = "some var"

def foo(self, x: int, y):
    print("foo (int, Any)")

def foo(self, x, y: str):
    print("foo (Any, str)")

def foo(self, x: int, y: str):
    print("foo (int, str)")

cls = TypeOverloaded()
cls.foo("abc", "def")
cls.foo(1, 1)
cls.foo(2, "abc")
print(cls.var)

foo (Any, str)
foo (int, Any)
foo (int, str)
some var```

brave badger
#

Interesting

desert peak
#

anyone know if any editors support generation of protocols via type annotations yet?

#

like if I had class T(Iterable[str], MutableMapping[str, str]):, to see __iter__, __getitem__ and __setitem__ implementations with correction annotations?

radiant fulcrum
#

at that point i think its getting past the point in sane typing

desert peak
#

why do you think so? that's a normal case in other languages

radiant fulcrum
#

Yeah for static languages sure, but atleast imo, python's dynamic typing generally makes it just a lil, unatural

desert peak
#

if I implement an interface for a type in other languages, the editor handles all the boilerplate work of generating their methods for me

radiant fulcrum
#

but again im not someone who massively strict types in python

desert peak
#

protocols are strict

#

I do because maintaining products matters to me 🤷

radiant fulcrum
#

I type what i need to enough for it to be easy to understand not enough to enforce constraints

#

i find having a mess of typings everywhere is arguably harder to maintain but 🤷‍♂️

desert peak
#

until you run into a logic bug because you didn't annotate that static analysis could have found 🤷

#

I heavily use the pydantic package these days

#

Python, while fast to develop in, was not my choice of language but it beat being forced to use Java

unkempt rock
#

were can we learn python?

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

unkempt rock
#

Do you consider that object-oriented programming (OOP) facilitates the resolution of a problem or
need, identifying the actors that participate with their respective actions?

unkempt rock
#

:c

#

Could you replay?

desert peak
unkempt rock
#

About the OOP method

#

Do you know what it is?

feral cedar
#

that sounds like a test question

unkempt rock
#

._.

#

Help me

#

Okey...

#

Do you think that the OOP method facilitates the resolution of a problem or
need?

desert peak
radiant fulcrum
#

that is defo a test question

unkempt rock
#

It isn't, it's just a class question

radiant fulcrum
#

I doubt that

#

no one casually words things about OOP like in anything other than test questions

#

well class question sure

feral cedar
#

^

desert peak
#

in general people don't talk about OOP like that except in academics

unkempt rock
#

???

radiant fulcrum
#

but still a school work question

desert peak
#

!rule 5

fallen slateBOT
#

5. Do not provide or request help on projects that may break laws, breach terms of services, be considered malicious or inappropriate. Do not help with ongoing exams. Do not provide or request solutions for graded assignments, although general guidance is okay.

unkempt rock
#

Wtf???'

#

It is not a test

#

Is a class question

radiant fulcrum
#

Time for you todo some bop bop research on your own™️

desert peak
#

regardless, this is not the channel for that discussion

unkempt rock
#

But I don't know what to answer, because I never understood this method.

radiant fulcrum
undone hare
swift imp
#

Give me coalesce operators and eff'ing builtin multiple dispatch. I feel like if type annotations got fully fleshed out to consider everything then multiple dispatch would be an ez extension.

desert peak
#

"syntax purity" or some other nonsense

desert peak
#

wow, 2015 proposal. someone was a forward thinker

radiant fulcrum
#

would be nice to have tbh

desert peak
#

the python purist types say "just try it and use try/except everywhere"

#

!e

a = 'str'
try:
  v = a.b
except (AttributeError, NameError):
  v = 'default'
fallen slateBOT
#

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

desert peak
#

I wish more of the grammar was an expression vs. statement

grave jolt
#

like do notation, but in Python

#

I think I can find it somewhere

desert peak
#

you lost me at "contraption"

desert peak
#

that's hideous and does not communicate what null syntax does

grave jolt
#

yeah, that's pretty esoteric

#

it's basically copied from functional languages (haskell/scala/f#) where you can do this

readFromConfig :: Config -> Maybe (Int, Int, Int)
readFromConfig config = do
    foo <- lookup "foo" config
    bar <- lookup "bar" config
    baz <- lookup "baz" config
    return (foo, bar, baz)

and it is translated to a callback chain

readFromConfig :: Config -> Maybe (Int, Int, Int)
readFromConfig config =
    lookup "foo" config >>= (\foo ->
        lookup "bar" config >>= (\bar ->
            lookup "baz" config >>= (\baz ->
                Just (foo, bar, baz)
                )))
spice pecan
#

Speaking of esoteric, here's another blast from the past:

#
class CustomOperator:
    def __init__(self, func):
        self.func = func
        self.lhs = ()
    def __gt__(self, other):
        if self.lhs:
            lhs, rhs = *self.lhs, other
            self.lhs = ()
            return self.func(lhs, rhs)
        self.lhs = other,
        return True  # Must be truthy to eval both parts of chained comp
    def __call__(self, lhs, rhs):
        return self.func(lhs, rhs)

nullnt = CustomOperator(lambda x, y: x if x is not None else y)

print(None <nullnt> [])
print(0 <nullnt> 'hello')```
grave jolt
#

hehe

desert peak
#

my brain D:

spice pecan
#

Yeah, I've seen that one

#

Fascinating tbh

desert peak
#

has anyone done monads in Python that look nice yet?

spice pecan
#

I think there was a package that did the same thing as this CustomOperator, except... not poorly

grave jolt
desert peak
#

one thing I regularly miss from Rust are Option<T> and Result<T, E>

#

python doesn't do postfix, does it?

grave jolt
#

wdym?

#

ah

#

no

desert peak
#

there aren't any postfix operators

#

just prefix

grave jolt
#

yeah, just prefix

#

and infix

#

Although you could consider a method call a postfix operator.

#

foo.bar() instead of the prefix bar(foo)

desert peak
#

I found out that Generic[T] syntax is generally supported in Python. I wonder how I could use that to implement Option/Result types that are ergonomic

spice pecan
#

I guess subscripting is also postfix-ish?

grave jolt
#

yeah

#

and calling -- if you consider calling as an operation on a function, not on its arguments

desert peak
#

I wonder if I could make a generic constructor... if T[R]() would be valid syntax

flat gazelle
#

that is valid syntax

desert peak
#

then I wonder how I would access the R from the constructor

spice pecan
#

You'd return an object that somehow binds R

desert peak
#

borderline esoteric for python lol

grave jolt
#

You can surely access some dunder, I don't remember which one

#

you'll have to scavenge in the REPL

#

But, of course, you'll have to write it out explicitly

#

if you want this kind of type stuff, Python is probably not the place to go

flat gazelle
#

!e

class A:
    def __class_getitem__(self, item):
        class AInst(A):
            generic = item
        return AInst
    def __init__(self):
        print(self.generic)
A[int]()
fallen slateBOT
#

@flat gazelle :white_check_mark: Your eval job has completed with return code 0.

<class 'int'>
grave jolt
#

you can do it with Generic as well

#

somehow

desert peak
#

nice, so I can create a generic and then assign the discriminator somewhere

swift imp
#

What the heck is __class_getitem___, is that purely for typing

zenith topaz
#

In general you'd code it in a way where your statictype checkers will infer the type

flat gazelle
#

it's a new 3.9 feature which allows dict[str, int] as a type hint

swift imp
#

Oh man, what if I have a custom meta where I implemented __getitem__?

#

Bc I do have a class registry that does that

spice pecan
#

I thought __class_getitem__ came before 3.9, it's just that built-ins didn't have it until that point

grave jolt
#

I made the unfortunate mistake of trying to cram advanced type stuff into Python way too many times. So the real advice is to maybe find something simpler.

flat gazelle
grave jolt
grave jolt
#

no

#

just in general

desert peak
spice pecan
grave jolt
desert peak
#

but it is valuable to the library makers that make content for most Python users

#

like the macros proposal

swift imp
#

what happens if I have a custom meta with __getitem__ and then on my classes have __class_getitem__?

zenith topaz
#

Calling the class with a type just doesn't seem all that helpfull when generics already work plenty fine when infered.

desert peak
#

how would you find the inferred type of a generic for your class?

#

Say, if I had a tuple type

grave jolt
desert peak
grave jolt
#

...although there are libs like numpy that would benefit from features like type-level integers

swift imp
#

GvR was at the last pandas developer meeting specifically talking about type hints

desert peak
#

"oops, that number is too big for c_int_u32! teehee!"

swift imp
#

Dude I wish they implemented some sort of generics for array shapes

swift imp
#

Guido Von Rossum

desert peak
#

ah

#

wasn't aware BDFL had multiple acronyms

swift imp
#

pandas is absorbing the type sheds that microsoft has in some repo

zenith topaz
#

He's not going by BDFL anymore.

#

He stepped down.

desert peak
#

isn't typeshed a mypy thing?

#

sure, but he's still widely respected across the ecosystem

swift imp
desert peak
#

ah, never heard of that before

grave jolt
swift imp
#
function out = myFunction(A, B, C)   
    arguments
        A (1,1) string 
        B (1,:) double
        C (2,2) cell
    end

    % Function code
    ...
end
#

So A should be a scalar, B some row vector, and C and 2x2 matrix

desert peak
#

1-indexed lang
🤮

swift imp
#

typical, completely miss the point because of your own vitriol

desert peak
#

I'm not missing the point, I'm just making a joke. I don't have an investment in this particular conversation

flat gazelle
#

I mean, there is no problem if want to implement that on your own. The issue is more that it is less flexible than if - raise, and quite a few functions on arrays have quite complex preconditions

swift imp
#

I think it would be an amazing addition to numerical related libraries. Very often people could write functions expecting data to be in a certain shape and stuff will go very wrong if its not oriented in that but still run completely, error free.

desert peak
#

Rust is going through a similar problem with generics and array types atm

#

more specifically, const generics

flat gazelle
#

you need dependent typing for the kind of safety you would want, which is really complex and not ready for general use.

desert peak
#

from the discussions I've seen about that, it is a difficult problem

swift imp
#

How did matlab do it so easily for their objects?

flat gazelle
#

they only provide very basic checks

swift imp
#

I guess thats a dumb question because theres a lot of stuff in python that doesnt exist in matlab but at least from numpy's perspective

flat gazelle
#

like most functions don't need a 3x3 matrix, they need a square matrix

#

a square matrix is still possible, but not everything is

#

I don't think this is useful enough to provide sugar for in the general case

#

and well, you could make a decorator that parses these preconditions from a docstring if you really wanted it

desert peak
#

so off-topic from the whole generic arrays convo

#

can anyone explain why python sees an empty dict as falsey?

swift imp
#

bc the length of the keys is 0

desert peak
#

is it because it's a collection type?

flat gazelle
#

it has a len of 0

#

things that have a len of 0 are falsey

desert peak
#

so if I implement Sized for my T and it returns 0, python would see my T as falsey as well?

swift imp
#

if __bool__ isn't implemented then the output of __len__ is used. Any nonzero integer is True and 0 is False if neither __bool__ nor __len__ are implemented then the result is automatically True.

desert peak
#

thanks for explaining that. I knew what types return false, but wasn't sure on why

swift imp
#

that's like the 4th time i've explained it and have I have the definition of __bool__ almost seared into my brain now lol

desert peak
#

since JS is a different beast

#

and I work in a few languages that all seem to have different semantics

flat gazelle
#

it creates an issue in etree, where every node is a collection of its children and it's len is the amount of children, but also .find returns None of no element is found. So you need to explicitely ask

#

its quite the annoying trap

desert peak
#

glad I haven't needed XML recently

grave jolt
#

I'd say interpreting values as booleans is a bad idea anyway

desert peak
#

sometimes you just want easy conditions

grave jolt
#

idk why, but if not list: just... doesn't work for me (compared to if list == []:)

flat gazelle
#

in how many cases is it even correct to use interpreting as booleans

swift imp
#

But then people have to wrap len to check if iterables are zero length

swift imp
zenith topaz
#

Which is quite weird to anyone not used to python.

swift imp
#

I suppose

#

Now that im used to it, I like it but it did take me a while to get used to it.

grave jolt
#

I don't like the implicitness of if not list:, and it can also hide bugs (e.g. if list is 0, None or something else)

zenith topaz
#

static checkers would detect that

swift imp
#

a lot of us hate typing though

#

I tried to use it but it quickly becomes too verbose

#

but here I am asking for array size type hints >.<

desert peak
# grave jolt `.is_empty()`

get out of here with that logic. if I had the option, I'd subclass all the collections to implement sane methods on them 😦

#

everything being a function drives me loony

#

I especially feel it in filter, len and map

grave jolt
desert peak
grave jolt
desert peak
#

I haven't heard "lenses" as a term before

desert peak
#

I have never seen that before

#

what is first?

grave jolt
#

first is a lens -- it's an object that describes how to get or set the first element of a tuple

desert peak
#

tuple being immutable, that means a new type would be returned, no?

grave jolt
#

so (first * first).setter("b")(x) is like x[0][0] = "b", but for immutable data

desert peak
#

new "object" that is

grave jolt
#

Yes. It's like a getter&setter, but "setting" means creating a new value

#

and you can compose them with *

#

The exact principles aren't important here,

#

the main point is that you can't give first or second any coherent type annotation besides Any or Lens[Any, Any, Any, Any].

#

no proxies or metaclasses involved

desert peak
#

why not Lens[int, ...]?

#

like tuple does

grave jolt