如何在Python中创建类(即静态)变量或方法?


当前回答

python中的静态方法称为classmethods。查看以下代码

class MyClass:

    def myInstanceMethod(self):
        print 'output from an instance method'

    @classmethod
    def myStaticMethod(cls):
        print 'output from a static method'

>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]

>>> MyClass.myStaticMethod()
output from a static method

注意,当我们调用方法myInstanceMethod时,会得到一个错误。这是因为它要求在此类的实例上调用该方法。方法myStaticMethod使用decorator@classmethod设置为类方法。

为了好玩,我们可以通过传入类的实例来调用类上的myInstanceMethod,如下所示:

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method

其他回答

总结其他人的回答并补充,在python中声明静态方法或变量有很多种方法。

1.使用staticmethod()作为装饰符:

可以简单地在声明的方法(函数)上方放置一个修饰符,使其成为静态方法。例如。

class Calculator:
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res

print(Calculator.multiply(1, 2, 3, 4))              # 24

2.使用staticmethod()作为参数函数:

此方法可以接收函数类型的参数,并返回传递函数的静态版本。例如。

class Calculator:
    def add(n1, n2, *args):
        return n1 + n2 + sum(args)

Calculator.add = staticmethod(Calculator.add)
print(Calculator.add(1, 2, 3, 4))                   # 10

3.使用classmethod()作为装饰符:

@classmethod对函数的影响与@staticmethod类似,但是这一次,需要在函数中接受一个额外的参数(类似于实例变量的self参数)。例如。

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num

print(Calculator.get_digits(314159))                # 314159

4.使用classmethod()作为参数函数:

@classmethod也可以用作参数函数,以防不想修改类定义。例如。

class Calculator:
    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res

Calculator.divide = classmethod(Calculator.divide)

print(Calculator.divide(15, 3, 5))                  # 1.0

5.直接申报

在所有其他方法外部但在类内部声明的方法/变量自动是静态的。

class Calculator:   
    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)

print(Calculator.subtract(10, 2, 3, 4))             # 1

整个计划

class Calculator:
    num = 0
    def __init__(self, digits) -> None:
        Calculator.num = int(''.join(digits))
    
    
    @staticmethod
    def multiply(n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 * n2 * Res


    def add(n1, n2, *args):
        return n1 + n2 + sum(args)
    

    @classmethod
    def get_digits(cls, num):
        digits = list(str(num))
        calc = cls(digits)
        return calc.num


    def divide(cls, n1, n2, *args):
        Res = 1
        for num in args: Res *= num
        return n1 / n2 / Res


    def subtract(n1, n2, *args):
        return n1 - n2 - sum(args)
    



Calculator.add = staticmethod(Calculator.add)
Calculator.divide = classmethod(Calculator.divide)

print(Calculator.multiply(1, 2, 3, 4))              # 24
print(Calculator.add(1, 2, 3, 4))                   # 10
print(Calculator.get_digits(314159))                # 314159
print(Calculator.divide(15, 3, 5))                  # 1.0
print(Calculator.subtract(10, 2, 3, 4))             # 1

有关掌握Python中的OOP,请参阅Python文档。

@数据类定义提供用于定义实例变量和初始化方法__init__()的类级名称。如果要在@dataclass中使用类级变量,则应使用typeing.ClassVar类型提示。ClassVar类型的参数定义类级别变量的类型。

from typing import ClassVar
from dataclasses import dataclass

@dataclass
class Test:
    i: ClassVar[int] = 10
    x: int
    y: int
    
    def __repr__(self):
        return f"Test({self.x=}, {self.y=}, {Test.i=})"

用法示例:

> test1 = Test(5, 6)
> test2 = Test(10, 11)

> test1
Test(self.x=5, self.y=6, Test.i=10)
> test2
Test(self.x=10, self.y=11, Test.i=10)

用这种方式,静态变量是在用户定义的类出现时创建的,

class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10

python中的静态方法称为classmethods。查看以下代码

class MyClass:

    def myInstanceMethod(self):
        print 'output from an instance method'

    @classmethod
    def myStaticMethod(cls):
        print 'output from a static method'

>>> MyClass.myInstanceMethod()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method myInstanceMethod() must be called [...]

>>> MyClass.myStaticMethod()
output from a static method

注意,当我们调用方法myInstanceMethod时,会得到一个错误。这是因为它要求在此类的实例上调用该方法。方法myStaticMethod使用decorator@classmethod设置为类方法。

为了好玩,我们可以通过传入类的实例来调用类上的myInstanceMethod,如下所示:

>>> MyClass.myInstanceMethod(MyClass())
output from an instance method

使用Object数据类型是可能的。但是对于bool、int、float或str等原始类型,bahaviour与其他OOP语言不同。因为在继承类中不存在静态属性。若继承类中不存在该属性,Python将开始在父类中查找该属性。如果在父类中找到,将返回其值。当您决定更改继承类中的值时,将在运行时创建静态属性。在下一次读取继承的静态属性时,将返回其值,因为它已经定义。对象(列表、字典)用作引用,因此可以安全地将它们用作静态属性并继承它们。对象地址在更改其属性值时不会更改。

整数数据类型示例:

class A:
    static = 1


class B(A):
    pass


print(f"int {A.static}")  # get 1 correctly
print(f"int {B.static}")  # get 1 correctly

A.static = 5
print(f"int {A.static}")  # get 5 correctly
print(f"int {B.static}")  # get 5 correctly

B.static = 6
print(f"int {A.static}")  # expected 6, but get 5 incorrectly
print(f"int {B.static}")  # get 6 correctly

A.static = 7
print(f"int {A.static}")  # get 7 correctly
print(f"int {B.static}")  # get unchanged 6

基于refdatatypes库的解决方案:

from refdatatypes.refint import RefInt


class AAA:
    static = RefInt(1)


class BBB(AAA):
    pass


print(f"refint {AAA.static.value}")  # get 1 correctly
print(f"refint {BBB.static.value}")  # get 1 correctly

AAA.static.value = 5
print(f"refint {AAA.static.value}")  # get 5 correctly
print(f"refint {BBB.static.value}")  # get 5 correctly

BBB.static.value = 6
print(f"refint {AAA.static.value}")  # get 6 correctly
print(f"refint {BBB.static.value}")  # get 6 correctly

AAA.static.value = 7
print(f"refint {AAA.static.value}")  # get 7 correctly
print(f"refint {BBB.static.value}")  # get 7 correctly