【问题标题】:How do I call a class function inside the class definition?如何在类定义中调用类函数?
【发布时间】:2021-04-15 03:07:25
【问题描述】:
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))

我想在类块中使用save() 函数。我试过MetaDate.save() 和简单的save() 两者都抛出错误

有什么办法可以做到吗?

编辑

是的,maxSize 是一个类 var,是的,我可以使用 cls.maxSize 访问它。

【问题讨论】:

  • 另外,SSD 不是会员,所以cls.SSD 不起作用。
  • 它也不是类函数,它是一个实例函数,其中self的常用参数被重命名了
  • 为了使函数成为类函数,你应该添加装饰器@classmethod,但你的代码仍然无法工作
  • 除非您出于某种原因确实需要一个类,否则您可能想要更接近 this

标签: python class oop class-method class-members


【解决方案1】:

您的问题与我曾经问过的问题非常相似 — Calling class staticmethod within the class body? — 这很有趣,因为这意味着您可以将其改为静态方法并像这样调用它:

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

【讨论】:

    【解决方案2】:

    这是另一个答案。

    您可以使用元类来解决您无法在类主体中引用该类的限制(因为该类尚不存在)。您可以在元类__new__() 方法中创建类,然后对其进行修改——在这种情况下,通过调用其中定义的类方法。这就是我的意思:

    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)
    

    第一次运行时产生的输出(即没有预先存在的 sample.data 文件时):

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

    请注意,SSD 类属性是一个打开的文件——这很奇怪,但如果它是可运行的,你的代码也会这样做。

    【讨论】:

      【解决方案3】:

      当您调用save 时,该类尚未定义。解决这个问题的一种方法是使用继承并在基类中定义save

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

      当然,A 头部中的变量在 B.save 中是未知的,必须作为参数提供给 save

      好吧,或者像这样:

      class B:
          SSD = None
      
          @classmethod
          def save(cls):
              print(f"Saving {cls.SSD}")
      
      class A(B):
          B.SSD = 3.14
      
          B.save()
      

      【讨论】:

      • 为什么你需要一个单独的类呢?只需将B.save() 放在类定义之后即可。
      • true, @deceze, 想一想,我通常会避免在类头中使用任何代码(静态变量的简单赋值除外),然后将所有逻辑例如进入一个类方法,正如你所说,之后调用它来完成初始化。 ...或者过度考虑设计并避免过多地使用这种静态的东西。
      猜你喜欢
      • 1970-01-01
      • 2016-01-26
      • 2021-03-10
      • 1970-01-01
      • 2020-12-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多