如何在Python中定义类的变量时,请参考类的方法?

问题描述 投票:2回答:4

我有以下类和类变量:

class MyClass:
    class_var_1 = "a"
    class_var_2 = run_class_method()

    @classmethod
    def run_class_method(cls):
        return "ran class method"

然而,解释说,run_class_method没有定义。使用MyClass.run_class_method()也不行。从Java背景的,我不明白为什么这是行不通的。那么,如何解决这个问题?

另外,我发现这个作品,如果我在课程结束时定义类变量。在Python这被认为是不好的做法?

python python-3.x class class-method
4个回答
2
投票

MyClass仍然被定义它的类属性的时候还没有确定,所以当时class_var_2被定义,MyClass还没有可供参考。您可以解决这个由class_var_2定义块定义之后MyClass

class MyClass:
    class_var_1 = "a"

    @classmethod
    def run_class_method(cls):
        return "ran class method"

MyClass.class_var_2 = MyClass.run_class_method()

2
投票

在Python类的身体是一个可执行的背景下,不喜欢的Java只包含声明。这是什么最终意味着是该执行顺序是一个类定义中重要的。

引述的文件:

类定义是一个可执行语句。

...

类的套件,然后在新的执行框架(见命名和有约束力的)执行,使用新创建的本地名字空间和原来的全局命名空间。 (通常,该套件包含了大部分功能的定义。)当类的套件完成执行,其执行帧会被丢弃,但它的局部名字空间被保存。 [4] A类对象,然后使用用于基础类和属性字典保存的本地名称空间中的继承列表创建。类名被绑定到原来的本地命名空间此类对象。

一些更lengthier explanations

如果你想调用一个函数定义一个类变量,你可以用以下方式之一做到这一点:

  1. 使用静态方法: class MyClass: def _run_instance_method(): return "ran instance method" run_instance_method = staticmethod(_run_instance_method) class_var_1 = "a" class_var_2 = _run_instance_method() # or run_instance_method.__func__()
  2. 或将它定义为一个独立的功能: def run_method(): return "ran method" class MyClass: class_var_1 = "a" class_var_2 = run_method() # optional run_method = staticmethod(run_method)
  3. 或与__func__访问原始功能,并提供一虚设cls值: class MyClass: @classmethod def run_class_method(cls): return "ran class method" class_var_1 = "a" class_var_2 = run_class_method.__func__(object())
  4. 或者设置类创建后的类变量: class MyClass: @classmethod def run_class_method(cls): return "ran class method" class_var_1 = "a" MyClass.class_var_2 = MyClass.run_class_method()

1
投票

首先要注意的事情是,Java没有类方法。它有静态方法和常规方法。一个普通的方法接收该实例它是从作为一个参数调用。一类方法接收类,由(不是类它是在定义的)称为作为参数。静态方法得到什么特别和行为像正常功能 - 静态方法只是分组逻辑相关的方法的一种方式。

要注意的第二件事情是一个Java类的定义被解析成一个单独的类定义和隐式静态构造函数。当初始化类属性这使您能够调用它们在类体内定义之前的方法。这是因为在实际的程序类已经被创造后才这些语句将被调用/加载到内存中。在Python中没有这样的区别。取而代之的是,创建一个类你执行了一系列专门的命名空间内声明的,然后将此用于创建类。就像在代码的函数或模块块的身体,你不能用一个变量是存在之前。这包括使用类体中的类(因为它还不存在!)

例如。这是有效的Java:

class X {
    static int i = 1;
    static X obj = newInstance();
    // ^-- executed after the class has been created, but is still being initialised.
    static X newInstance() {
        return new X();
    }
}

但是,这不是有效的Python

class X:
    val = 1
    obj = new_instance()
    # ^-- We're still in the body of X, and neither new_instance nor X has been created yet
    @classmethod
    def new_instance(cls):
        return cls()
    # even if new_instance was defined before obj, Python still wouldn't be able to fill
    # in the cls argument as X still doesn't exist when new_instance is first invoked

在Python中,你必须明确地做你的类的静态结构。牢记这正是在Java中会发生什么,它只是背后隐藏的语法糖。

class X:
    val = 1 # this can still be done in the class body as it doesn't need the class
    obj = None # not necessary, but can help type checkers know that X has an
    # attribute obj -- you can use type annotations to further help
    @classmethod
    def new_instance(cls):
       return cls()
# explicit class initialisation of attributes
X.obj = X.new_instance()

0
投票

另一种方式做,这将是确定这是它在创造它的子类(或一元类)控制一个父类。下面,我们用__init_subclass__在父类中设置类的创建过程中的属性。

class InitVar():
    def __init_subclass__(cls, varname, funcname, **kwargs):
        class_method = getattr(cls, funcname)
        setattr(cls, varname, class_method())

class MyClass(InitVar, varname="class_var_2", funcname="run_class_method"):
    class_var_1 = "a"
    @classmethod
    def run_class_method(cls):
        return "ran class method"

print(MyClass.class_var_2)
# ran class method
© www.soinside.com 2019 - 2024. All rights reserved.