#๐Ÿ”’ code review, class dunders

90 messages ยท Page 1 of 1 (latest)

hexed hemlock
#

this is using the idea of __class_getitem__, but for it to work with all dunders
the idea i've come up with is a decorator, i think that it could be neat to try making it work as a metaclass, though i'm not sure it's possible.

wooden krakenBOT
#

@hexed hemlock

Python help channel opened

Remember to:

  • Ask your Python question, not if you can ask or if there's an expert who can help.
  • Show a code sample as text (rather than a screenshot) and the error message, if you've got one.
  • Explain what you expect to happen and what actually happens.

:warning: Do not pip install anything that isn't related to your question, especially if asked to over DMs.

hexed hemlock
#
def class_dunders(cls: type) -> type:
    function_result: type

    curr_cls = cls
    curr_cls_name = curr_cls.__name__
    curr_cls_bases = curr_cls.__bases__
    curr_cls_dict = dict(curr_cls.__dict__)

    new_mcs_dict = {}
    new_mcs_dict_items_amount = 0

    for curr_cls_attr_name, curr_cls_attr_value in curr_cls_dict.items():
        if (
            curr_cls_attr_name.startswith("__class_")
            and curr_cls_attr_name.endswith("__")
            and curr_cls_attr_name != "__class_getitem__"  # a special case, in order to avoid changing the original behavior
            and isinstance(curr_cls_attr_value, classmethod)
        ):
            new_mcs_attr_name = '_' + curr_cls_attr_name[7:]
            new_mcs_attr_value = curr_cls_attr_value.__func__

            new_mcs_dict[new_mcs_attr_name] = new_mcs_attr_value
            new_mcs_dict_items_amount += 1

    if new_mcs_dict_items_amount > 0:
        curr_mcs = type(curr_cls)

        # creating a new class object (using the type metaclass object), that is a metaclass object
        # , which inherits the current metaclass object and adds functionality to it

        new_mcs_name = "class_dunders" + '_' + curr_cls_name
        new_mcs_bases = (curr_mcs,)

        new_mcs = type(new_mcs_name, new_mcs_bases, new_mcs_dict)

        # setting the current metaclass object as the new metaclass object

        curr_mcs = new_mcs

        # creating a new class object (using the current metaclass object)

        new_cls_name = curr_cls_name
        new_cls_bases = curr_cls_bases
        new_cls_dict = curr_cls_dict

        new_cls = curr_mcs(new_cls_name, new_cls_bases, new_cls_dict)

        # setting the current class object as the new class object

        curr_cls = new_cls

    # setting the result as the current class object

    function_result = curr_cls

    return function_result
#

@safe cosmos

safe cosmos
#

I didn't understand what it does from the description

hexed hemlock
#

and it'd go to the metaclass' __instancecheck__

safe cosmos
#

ok so __class_<anydunder>__

safe cosmos
hexed hemlock
#

__class_getitem__ goes to the metaclass' __getitem__

#
@class_dunders
class a:
    @classmethod
    def __class_instancecheck__(cls, instance: Any) -> bool:
        return True
    
print(isinstance(5, a))
#

u could basically create all the metaclass' dunders from inside the class

safe cosmos
hexed hemlock
#

even __class_new__

safe cosmos
#

!e

class Meta(type):
    def __getitem__(self, *_):
        raise TypeError
    
class MyClass(metaclass=Meta):
    def __class_getitem__(cls, *_):
        print("no it doesn't")
        
MyClass[1]
wooden krakenBOT
# safe cosmos !e ```py class Meta(type): def __getitem__(self, *_): raise TypeErro...

:x: Your 3.14 eval job has completed with return code 1.

001 | Traceback (most recent call last):
002 |   File "/home/main.py", line 9, in <module>
003 |     MyClass[1]
004 |     ~~~~~~~^^^
005 |   File "/home/main.py", line 3, in __getitem__
006 |     raise TypeError
007 | TypeError
hexed hemlock
#

thats what i said

#

not the other way around

safe cosmos
#

as I just showed in the eval

hexed hemlock
#

oh i see

#

well yea

#

what u say is true

#

but not very much changing the picture

safe cosmos
#
class type:
    def __getitem__(self, value):
        try:
            return self.__class_getitem__(value)
        except AttributeError:
            ... # default impl
hexed hemlock
#

perhaps its if the metaclass has getitem use it instead

#

otherwise look for class_getitem

hexed hemlock
#

type has no getitem

#

its just the way it does its lookups

safe cosmos
#

hrm

#

ok I see

hexed hemlock
#

u can read the code i wrote though

#

the way i did it is making those names in the dict of the metaclass, and attaching them to the methods of the class itself

#

sort of like __getitem__ = cls.__class_getitem__

#

and then creating the metaclass, and with it creating the class

safe cosmos
#

!e

class MyClass:
    def __class_getitem__(cls):
        print("what")

# notice we instantiate the class here
MyClass().__class_getitem__()
wooden krakenBOT
hexed hemlock
#

what u mean

safe cosmos
#

nvm

#

I should've did print(cls)

#

it prints the class, not the instance

hexed hemlock
#

yea

#

its because its a class method

safe cosmos
#

ok so does type.__getattribute__ do something with it then?

hexed hemlock
#

but its a special case when @classmethod isn't needed

#

no its just a class method

#

not sure?

#

u mean maybe u can change the metaclass' getattribute?

safe cosmos
#

you're right

#

!e

class MyClass:
    def __class_getitem__(cls):
        print(cls)

print(MyClass.__dict__)
wooden krakenBOT
# safe cosmos !e ```py class MyClass: def __class_getitem__(cls): print(cls) prin...

:white_check_mark: Your 3.14 eval job has completed with return code 0.

{'__module__': '__main__', '__firstlineno__': 1, '__class_getitem__': <classmethod(<function MyClass.__class_getitem__ at 0x7ff227be2f00>)>, '__static_attributes__': (), '__dict__': <attribute '__dict__' of 'MyClass' objects>, '__weakref__': <attribute '__weakref__' of 'MyClass' objects>, '__doc__': None}
hexed hemlock
#

yea

safe cosmos
#

but it might be that type is making it a classmethod

hexed hemlock
#

no its just python syntax

#

making it a special case

#

in my opinion

safe cosmos
#

it's not an opinion thing tho

#

there is a correct answer

hexed hemlock
#

well u could check for it, but it doesn't matter

#

its a special case

safe cosmos
#

it matters if you are trying to change it

hexed hemlock
#

made by python

#

u can't change it for other methods

safe cosmos
#

huh, apparently __new__ becomes a staticmethod, not a classmethod

hexed hemlock
#

maybe u could

#

not sure

#

u could wrap the method inside the metaclass' new

#

but i dont want to do that

#

because typecheckers also regard __class_getitem__ as a special case

#

well i guess u can though

#

its just a stupid design decision

#

made by python

#

i dont want to do it like that

hexed hemlock
#

to wrap it explicitly in @classmethod

#

seeing cls as an argument without @classmethod is pretty stupid

#

its also true for __new__, that it needs to be with @staticmethod

hexed hemlock
#

to be honest, new could also be a class method

#

maybe yes maybe not, not sure

#

int.__new__(bool)?

safe cosmos
#

aight I'm done for now

#

too eepy

hexed hemlock
#

ok

wooden krakenBOT
#
Python help channel closed for inactivity

This help channel has been closed. Feel free to create a new post in #1035199133436354600. To maximize your chances of getting a response, check out this guide on asking good questions.