How do I call a class function inside the class definition?
Asked Answered
C

3

1
class MetaData():

    maxSize = 2**10

    # class definition code
    if not os.path.exists('sample.data'):
        SSD  = open('sample.data', 'wb+')
        data = {
            0: [],
            1: {'.': None,}
        }
        data[1]['~'] = data[1]

        MetaData.save()  # i want to call the save function here


    # class function
    @classmethod
    def save(cls):

        cls.SSD.seek(0)
        cls.SSD.write(b' ' * cls.maxSize)
        cls.SSD.seek(0)
        cls.SSD.write(pickle.dumps(cls.data))

I want to use the save() function inside the class block. I've tried MetaDate.save() and simply save() both of which throw errors

Is there any way to achieve this?

Edit

Yes, maxSize is a class var and yes i can access it using cls.maxSize.

Chimb answered 9/1, 2021 at 17:16 Comment(4)
Also, SSD isn't a member, so cls.SSD won't work.Fetlock
It also isn't a class function, its an instance function where the commonly referred to parameter of self has been renamedCornfield
In order to make a function a class function, you should add the decorator @classmethod, but still your code won't workAurify
Unless you actually need a class for some reason, you probably want something closer to just thisFetlock
S
0

Your question is very similar to one I asked once — Calling class staticmethod within the class body? — which is interesting because it means you could make it a static method instead and call it like this:

import os
import pickle


class MetaData:
    maxSize = 2**10

    @staticmethod
    def save():
        SSD.seek(0)
        SSD.write(b' ' * cls.maxSize)
        SSD.seek(0)
        SSD.write(pickle.dumps(cls.data))

    # class definition code
    if not os.path.exists('sample.data'):
        SSD  = open('sample.data', 'wb+')
        data = {
            0: [],
            1: {'.': None,}
        }
        data[1]['~'] = data[1]

        save.__func__()  # Call the save function
Sera answered 9/1, 2021 at 18:42 Comment(0)
S
0

Here's another answer.

You can use a metaclass to workaround to the limitation that you can't reference the class in the class body (since the class doesn't exist yet). You can create the class in the metaclass __new__() method and then modify it — in this case by calling a classmethod defined in it. Here's what I mean:

import os
import pickle


class MetaMetaData(type):
    def __new__(meta, classname, bases, classdict):

        cls = type.__new__(meta, classname, bases, classdict)

        if not os.path.exists('sample.data'):
            cls.SSD = open('sample.data', 'wb+')

            cls.data = data = {
                0: [],
                1: {'.': None,}
            }
            data[1]['~'] = data[1]

            cls.save()

        return cls


class MetaData(metaclass=MetaMetaData):
    maxSize = 2**10

    @classmethod
    def save(cls):
        cls.SSD.seek(0)
        cls.SSD.write(b' ' * cls.maxSize)
        cls.SSD.seek(0)
        cls.SSD.write(pickle.dumps(cls.data))

    # class definition code
    ...


if __name__ == '__main__':
    print(MetaData.data)

Output produced from running it for the first time (i.e. when there was no preexisting sample.data file):

{0: [], 1: {'.': None, '~': {...}}}

Note that the SSD class attribute is an open file — which is very strange, but that's what your code would do too, if it were runnable.

Sera answered 11/1, 2021 at 0:32 Comment(0)
O
-1

At the point when you call save, the class is not yet defined. One way to get around this is to use inheritance and define save in the base-class:

class B:
    @classmethod
    def save(cls):
        print("Saving")

class A(B):
    B.save()

Then of course, variables in the head of A are not known in B.save and have to be given as arguments to save.

Well, or like this:

class B:
    SSD = None

    @classmethod
    def save(cls):
        print(f"Saving {cls.SSD}")

class A(B):
    B.SSD = 3.14

    B.save()
Ornamental answered 9/1, 2021 at 17:43 Comment(2)
Why do you need a separate class for this? Just put B.save() after the class definition, done.Masefield
true, @deceze, Thinking about it, I would normally avoid any code (other than simple assignments of static variables) in the class header, then put all that logic e.g. into a class method, and as you say, call it afterwards to complete the initialisation. ... or overthink the design and avoid too much of this static stuff alltogether.Ornamental

© 2022 - 2024 — McMap. All rights reserved.