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


当前回答

类工厂python3.6中的静态变量

对于使用python3.6及更高版本的类工厂的任何人,请使用非本地关键字将其添加到正在创建的类的作用域/上下文中,如下所示:

>>> def SomeFactory(some_var=None):
...     class SomeClass(object):
...         nonlocal some_var
...         def print():
...             print(some_var)
...     return SomeClass
... 
>>> SomeFactory(some_var="hello world").print()
hello world

其他回答

关于静态财产和实例财产,需要注意一件特殊的事情,如下例所示:

class my_cls:
  my_prop = 0

#static property
print my_cls.my_prop  #--> 0

#assign value to static property
my_cls.my_prop = 1 
print my_cls.my_prop  #--> 1

#access static property thru' instance
my_inst = my_cls()
print my_inst.my_prop #--> 1

#instance property is different from static property 
#after being assigned a value
my_inst.my_prop = 2
print my_cls.my_prop  #--> 1
print my_inst.my_prop #--> 2

这意味着在将值分配给实例属性之前,如果我们试图通过“实例”访问属性,则使用静态值。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

类变量并允许子类化

假设你不是在寻找一个真正的静态变量,而是一个类似于蟒蛇的东西,它可以为同意的成年人做同样的工作,那么就使用一个类变量。这将为您提供一个所有实例都可以访问(和更新)的变量

注意:其他许多使用类变量的答案都会破坏子类化。应避免直接按名称引用类。

from contextlib import contextmanager

class Sheldon(object):
    foo = 73

    def __init__(self, n):
        self.n = n

    def times(self):
        cls = self.__class__
        return cls.foo * self.n
        #self.foo * self.n would give the same result here but is less readable
        # it will also create a local variable which will make it easier to break your code
    
    def updatefoo(self):
        cls = self.__class__
        cls.foo *= self.n
        #self.foo *= self.n will not work here
        # assignment will try to create a instance variable foo

    @classmethod
    @contextmanager
    def reset_after_test(cls):
        originalfoo = cls.foo
        yield
        cls.foo = originalfoo
        #if you don't do this then running a full test suite will fail
        #updates to foo in one test will be kept for later tests

将为您提供与使用Sheldon.foo处理变量相同的功能,并将通过以下测试:

def test_times():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        assert s.times() == 146

def test_update():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        s.updatefoo()
        assert Sheldon.foo == 146

def test_two_instances():
    with Sheldon.reset_after_test():
        s = Sheldon(2)
        s3 = Sheldon(3)
        assert s.times() == 146
        assert s3.times() == 219
        s3.updatefoo()
        assert s.times() == 438

它还允许其他人简单地:

class Douglas(Sheldon):
    foo = 42

这也将起作用:

def test_subclassing():
    with Sheldon.reset_after_test(), Douglas.reset_after_test():
        s = Sheldon(2)
        d = Douglas(2)
        assert d.times() == 84
        assert s.times() == 146
        d.updatefoo()
        assert d.times() == 168 #Douglas.Foo was updated
        assert s.times() == 146 #Seldon.Foo is still 73

def test_subclassing_reset():
    with Sheldon.reset_after_test(), Douglas.reset_after_test():
        s = Sheldon(2)
        d = Douglas(2)
        assert d.times() == 84 #Douglas.foo was reset after the last test
        assert s.times() == 146 #and so was Sheldon.foo

有关创建课程时要注意的事项的最佳建议,请查看Raymond Hettinger的视频https://www.youtube.com/watch?v=HTLu2DFOdTg

与@staticmethod不同,但类变量是类的静态方法,并与所有实例共享。

现在您可以像这样访问它

instance = MyClass()
print(instance.i)

or

print(MyClass.i)

必须为这些变量赋值

我在努力

class MyClass:
  i: str

并在一个方法调用中赋值,在这种情况下,它将不起作用,并将抛出错误

i is not attribute of MyClass

总结其他人的回答并补充,在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文档。