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


当前回答

关于这个答案,对于常量静态变量,可以使用描述符。下面是一个示例:

class ConstantAttribute(object):
    '''You can initialize my value but not change it.'''
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        pass


class Demo(object):
    x = ConstantAttribute(10)


class SubDemo(Demo):
    x = 10


demo = Demo()
subdemo = SubDemo()
# should not change
demo.x = 100
# should change
subdemo.x = 100
print "small demo", demo.x
print "small subdemo", subdemo.x
print "big demo", Demo.x
print "big subdemo", SubDemo.x

导致。。。

small demo 10
small subdemo 100
big demo 10
big subdemo 10

如果您不喜欢忽略设置值(上面的传递),您总是可以引发异常。如果您正在寻找C++、Java风格的静态类变量:

class StaticAttribute(object):
    def __init__(self, value):
        self.value = value

    def __get__(self, obj, type=None):
        return self.value

    def __set__(self, obj, val):
        self.value = val

请查看此答案和HOWTO官方文件,以了解有关描述符的更多信息。

其他回答

在类定义中声明但不在方法中声明的变量是类或静态变量:

>>> class MyClass:
...     i = 3
...
>>> MyClass.i
3 

正如@millerdev所指出的,这会创建一个类级别i变量,但这与任何实例级别i变量都不同,因此您可以

>>> m = MyClass()
>>> m.i = 4
>>> MyClass.i, m.i
>>> (3, 4)

这与C++和Java不同,但与C#没有太大区别,在C#中,不能使用对实例的引用来访问静态成员。

看看Python教程对类和类对象的主题有什么看法。

@Steve Johnson已经回答了静态方法的问题,也在Python库参考中的“内置函数”中进行了说明。

class C:
    @staticmethod
    def f(arg1, arg2, ...): ...

@beidy推荐classmethods而不是staticmethod,因为该方法随后会接收类类型作为第一个参数。

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

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中声明静态方法或变量有很多种方法。

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文档。

所以这可能是一个黑客,但我一直在使用eval(str)来获取一个静态对象,这有点矛盾,在python 3中。

有一个Records.py文件,除了用保存一些参数的静态方法和构造函数定义的类对象外,它什么都没有。然后从另一个.py文件导入Records,但我需要动态选择每个对象,然后根据读入的数据类型按需实例化它。

因此,在object_name=“RecordOne”或类名的情况下,我调用cur_type=eval(object_name),然后要实例化它,请执行cur_inst=cur_type(args)然而,在实例化之前,您可以从cur_type.getName()调用静态方法,例如,类似于抽象基类实现或任何目标。然而,在后端,它可能是在python中实例化的,并不是真正静态的,因为eval返回一个对象。。。。必须已实例化。。。。这会产生类似静态的行为。

@Blair Conrad表示,在类定义中声明的静态变量,而不是在方法中声明的是类或“静态”变量:

>>> class Test(object):
...     i = 3
...
>>> Test.i
3

这里有几家餐厅。从以上示例继续:

>>> t = Test()
>>> t.i     # "static" variable accessed via instance
3
>>> t.i = 5 # but if we assign to the instance ...
>>> Test.i  # we have not changed the "static" variable
3
>>> t.i     # we have overwritten Test.i on t by creating a new attribute t.i
5
>>> Test.i = 6 # to change the "static" variable we do it by assigning to the class
>>> t.i
5
>>> Test.i
6
>>> u = Test()
>>> u.i
6           # changes to t do not affect new instances of Test

# Namespaces are one honking great idea -- let's do more of those!
>>> Test.__dict__
{'i': 6, ...}
>>> t.__dict__
{'i': 5}
>>> u.__dict__
{}

请注意,当直接在t上设置属性i时,实例变量t.i如何与“static”类变量不同步。这是因为我在t命名空间中重新绑定,这与Test命名空间不同。如果要更改“静态”变量的值,必须在其最初定义的范围(或对象)内更改它。我把“static”放在引号里,因为Python实际上没有C++和Java那样的静态变量。

尽管Python教程没有具体说明静态变量或方法,但它提供了一些关于类和类对象的相关信息。

@Steve Johnson还回答了静态方法的问题,也在Python库参考中的“内置函数”中进行了记录。

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...

@beid还提到了classmethod,它类似于staticmethod。类方法的第一个参数是类对象。例子:

class Test(object):
    i = 3 # class (or static) variable
    @classmethod
    def g(cls, arg):
        # here we can use 'cls' instead of the class name (Test)
        if arg > cls.i:
            cls.i = arg # would be the same as Test.i = arg1