#๐ code review, class dunders
90 messages ยท Page 1 of 1 (latest)
@hexed hemlock
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.
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
I didn't understand what it does from the description
for example, u could use __class_instancecheck__
and it'd go to the metaclass' __instancecheck__
ok so __class_<anydunder>__
but that's not what __class_getitem__ does
__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
ok so I investigated, and seems it's the other way around. type.__getitem__ calls self.__class_getitem__
even __class_new__
?
no it's not
!e
class Meta(type):
def __getitem__(self, *_):
raise TypeError
class MyClass(metaclass=Meta):
def __class_getitem__(cls, *_):
print("no it doesn't")
MyClass[1]
:x: Your 3.14 eval job has completed with return code 1.
001 | Traceback (most recent call last):
002 | File [35m"/home/main.py"[0m, line [35m9[0m, in [35m<module>[0m
003 | [31mMyClass[0m[1;31m[1][0m
004 | [31m~~~~~~~[0m[1;31m^^^[0m
005 | File [35m"/home/main.py"[0m, line [35m3[0m, in [35m__getitem__[0m
006 | raise TypeError
007 | [1;35mTypeError[0m
class_getitem calls the metaclass' getitem
thats what i said
not the other way around
it doesn't
as I just showed in the eval
class type:
def __getitem__(self, value):
try:
return self.__class_getitem__(value)
except AttributeError:
... # default impl
perhaps its if the metaclass has getitem use it instead
otherwise look for class_getitem
the metaclass getitem has no default implementation
type has no getitem
its just the way it does its lookups
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
!e
class MyClass:
def __class_getitem__(cls):
print("what")
# notice we instantiate the class here
MyClass().__class_getitem__()
:white_check_mark: Your 3.14 eval job has completed with return code 0.
what
what u mean
ok so does type.__getattribute__ do something with it then?
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?
you're right
!e
class MyClass:
def __class_getitem__(cls):
print(cls)
print(MyClass.__dict__)
: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}
yea
but it might be that type is making it a classmethod
it matters if you are trying to change it
huh, apparently __new__ becomes a staticmethod, not a classmethod
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
it should be as i did it in here^
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
its static bebcause u need to do cls.__new__(cls)
to be honest, new could also be a class method
maybe yes maybe not, not sure
int.__new__(bool)?
ok
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.