Python中是否可以使用静态类变量?

Python中是否可以使用静态类变量?,python,class,oop,static,class-variables,Python,Class,Oop,Static,Class Variables,Python中是否可以有静态类变量或方法?执行此操作需要什么语法?在类定义中声明但不在方法中声明的变量是类或静态变量: >>> class MyClass: ... i = 3 ... >>> MyClass.i 3 >>> class Test(object): ... i = 3 ... >>> Test.i 3 class A(object): label="Amazing" def

Python中是否可以有静态类变量或方法?执行此操作需要什么语法?

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

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

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!
正如@所指出的,这创建了一个类级
i
变量,但它不同于任何实例级
i
变量,因此您可以

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

这与C++和java不同,但与C语言不同,在这里,静态成员不能使用实例引用访问。 看

@Steve Johnson已经回答了关于的问题,也记录在下面


@beidy建议使用s而不是staticmethod,因为该方法随后会接收类类型作为第一个参数,但我仍然不清楚这种方法相对于staticmethod的优势。如果您也是,那么这可能无关紧要。

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

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

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!
正如@所指出的,这创建了一个类级
i
变量,但它不同于任何实例级
i
变量,因此您可以

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

这与C++和java不同,但与C语言不同,在这里,静态成员不能使用实例引用访问。 看

@Steve Johnson已经回答了关于的问题,也记录在下面


@beidy建议使用s而不是staticmethod,因为该方法随后会接收类类型作为第一个参数,但我仍然不清楚这种方法相对于staticmethod的优势。如果你也是,那可能没什么关系。

我个人认为,每当我需要静态方法时,我都会使用classmethod。主要是因为我把课堂当成了一个论点

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 
或者用一个装饰师

class myObj(object):
   @classmethod
   def myMethod(cls)
对于静态属性。。现在是查找python定义的时候了。。变量总是可以改变的。它们有两种类型:可变的和不可变的。。此外,还有类属性和实例属性。。没有什么真正像java&c意义上的静态属性++


如果静态方法与类没有任何关系,为什么要使用python意义上的静态方法呢!如果我是你,我要么使用classmethod,要么定义独立于类的方法。

就我个人而言,每当我需要静态方法时,我都会使用classmethod。主要是因为我把课堂当成了一个论点

class myObj(object):
   def myMethod(cls)
     ...
   myMethod = classmethod(myMethod) 
或者用一个装饰师

class myObj(object):
   @classmethod
   def myMethod(cls)
对于静态属性。。现在是查找python定义的时候了。。变量总是可以改变的。它们有两种类型:可变的和不可变的。。此外,还有类属性和实例属性。。没有什么真正像java&c意义上的静态属性++


如果静态方法与类没有任何关系,为什么要使用python意义上的静态方法呢!如果我是你,我要么使用classmethod,要么定义独立于类的方法。

python中的静态方法称为s。看看下面的代码

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

python中的静态方法称为s。看看下面的代码

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

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

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

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 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__
{}
注意当属性
i
直接设置在
t
上时,实例变量
t.i
如何与“静态”类变量不同步。这是因为
i
被重新绑定到
t
命名空间中,这与
Test
命名空间不同。如果要更改“静态”变量的值,必须在最初定义该变量的范围(或对象)内进行更改。我把“static”放在引号中,因为Python在C++和java的意义上没有真正的静态变量。 虽然它没有说任何关于静态变量或方法的具体内容,但是有一些关于静态变量或方法的相关信息

@SteveJohnson还回答了关于静态方法的问题,也在Python库参考中的“内置函数”下进行了说明

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...
@贝德还提到了classmethod,它类似于staticmethod。classmethod的第一个参数是类对象。例如:

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

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

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

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 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__
{}
注意当属性
i
直接设置在
t
上时,实例变量
t.i
如何与“静态”类变量不同步。这是因为
i
被重新绑定到
t
命名空间中,这与
Test
命名空间不同。如果要更改“静态”变量的值,必须在最初定义该变量的范围(或对象)内进行更改。我把“static”放在引号中,因为Python在C++和java的意义上没有真正的静态变量。 虽然它没有说任何关于静态变量或方法的具体内容,但是有一些关于静态变量或方法的相关信息

@SteveJohnson还回答了关于静态方法的问题,也在Python库参考中的“内置函数”下进行了说明

class Test(object):
    @staticmethod
    def f(arg1, arg2, ...):
        ...
@贝德还提到了classmethod,它类似于staticmethod。classmethod的第一个参数是类对象。例如:

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

为了避免任何潜在的混淆,我想对比静态变量和不可变对象

一些基本对象类型,如整数、浮点、字符串和touple在Python中是不可变的。这意味着,如果给定名称引用的对象属于上述对象类型之一,则该对象无法更改。可以将名称重新分配给其他对象,但对象本身不能更改

通过禁止变量名指向除它当前指向的对象之外的任何对象,使变量成为静态变量可以更进一步
class Test(object):

    _i = 3

    @property
    def i(self):
        return type(self)._i

## ALTERNATIVE IMPLEMENTATION - FUNCTIONALLY EQUIVALENT TO ABOVE ##
## (except with separate methods for getting i) ##

class Test(object):

    _i = 3

    def get_i(self):
        return type(self)._i

    i = property(get_i)
x = Test()
assert x.i == 3  # success
x.i = 12         # ERROR
x = Test()
assert x.i == Test.i  # ERROR

# x.i and Test.i are two different objects:
type(Test.i)  # class 'property'
type(x.i)     # class 'int'
    i = property(get_i) 
type(int)  # class 'type'
type(str)  # class 'type'
class Test(): pass
type(Test) # class 'type'
class MyMeta(type): pass
class MyClass(metaclass = MyMeta):
    pass

type(MyClass)  # class MyMeta
from functools import wraps

class StaticVarsMeta(type):
    '''A metaclass for creating classes that emulate the "static variable" behavior
    of other languages. I do not advise actually using this for anything!!!

    Behavior is intended to be similar to classes that use __slots__. However, "normal"
    attributes and __statics___ can coexist (unlike with __slots__). 

    Example usage: 

        class MyBaseClass(metaclass = StaticVarsMeta):
            __statics__ = {'a','b','c'}
            i = 0  # regular attribute
            a = 1  # static var defined (optional)

        class MyParentClass(MyBaseClass):
            __statics__ = {'d','e','f'}
            j = 2              # regular attribute
            d, e, f = 3, 4, 5  # Static vars
            a, b, c = 6, 7, 8  # Static vars (inherited from MyBaseClass, defined/re-defined here)

        class MyChildClass(MyParentClass):
            __statics__ = {'a','b','c'}
            j = 2  # regular attribute (redefines j from MyParentClass)
            d, e, f = 9, 10, 11   # Static vars (inherited from MyParentClass, redefined here)
            a, b, c = 12, 13, 14  # Static vars (overriding previous definition in MyParentClass here)'''
    statics = {}
    def __new__(mcls, name, bases, namespace):
        # Get the class object
        cls = super().__new__(mcls, name, bases, namespace)
        # Establish the "statics resolution order"
        cls.__sro__ = tuple(c for c in cls.__mro__ if isinstance(c,mcls))

        # Replace class getter, setter, and deleter for instance attributes
        cls.__getattribute__ = StaticVarsMeta.__inst_getattribute__(cls, cls.__getattribute__)
        cls.__setattr__ = StaticVarsMeta.__inst_setattr__(cls, cls.__setattr__)
        cls.__delattr__ = StaticVarsMeta.__inst_delattr__(cls, cls.__delattr__)
        # Store the list of static variables for the class object
        # This list is permanent and cannot be changed, similar to __slots__
        try:
            mcls.statics[cls] = getattr(cls,'__statics__')
        except AttributeError:
            mcls.statics[cls] = namespace['__statics__'] = set() # No static vars provided
        # Check and make sure the statics var names are strings
        if any(not isinstance(static,str) for static in mcls.statics[cls]):
            typ = dict(zip((not isinstance(static,str) for static in mcls.statics[cls]), map(type,mcls.statics[cls])))[True].__name__
            raise TypeError('__statics__ items must be strings, not {0}'.format(typ))
        # Move any previously existing, not overridden statics to the static var parent class(es)
        if len(cls.__sro__) > 1:
            for attr,value in namespace.items():
                if attr not in StaticVarsMeta.statics[cls] and attr != ['__statics__']:
                    for c in cls.__sro__[1:]:
                        if attr in StaticVarsMeta.statics[c]:
                            setattr(c,attr,value)
                            delattr(cls,attr)
        return cls
    def __inst_getattribute__(self, orig_getattribute):
        '''Replaces the class __getattribute__'''
        @wraps(orig_getattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                return StaticVarsMeta.__getstatic__(type(self),attr)
            else:
                return orig_getattribute(self, attr)
        return wrapper
    def __inst_setattr__(self, orig_setattribute):
        '''Replaces the class __setattr__'''
        @wraps(orig_setattribute)
        def wrapper(self, attr, value):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__setstatic__(type(self),attr, value)
            else:
                orig_setattribute(self, attr, value)
        return wrapper
    def __inst_delattr__(self, orig_delattribute):
        '''Replaces the class __delattr__'''
        @wraps(orig_delattribute)
        def wrapper(self, attr):
            if StaticVarsMeta.is_static(type(self),attr):
                StaticVarsMeta.__delstatic__(type(self),attr)
            else:
                orig_delattribute(self, attr)
        return wrapper
    def __getstatic__(cls,attr):
        '''Static variable getter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    return getattr(c,attr)
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __setstatic__(cls,attr,value):
        '''Static variable setter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                setattr(c,attr,value)
                break
    def __delstatic__(cls,attr):
        '''Static variable deleter'''
        for c in cls.__sro__:
            if attr in StaticVarsMeta.statics[c]:
                try:
                    delattr(c,attr)
                    break
                except AttributeError:
                    pass
        raise AttributeError(cls.__name__ + " object has no attribute '{0}'".format(attr))
    def __delattr__(cls,attr):
        '''Prevent __sro__ attribute from deletion'''
        if attr == '__sro__':
            raise AttributeError('readonly attribute')
        super().__delattr__(attr)
    def is_static(cls,attr):
        '''Returns True if an attribute is a static variable of any class in the __sro__'''
        if any(attr in StaticVarsMeta.statics[c] for c in cls.__sro__):
            return True
        return False
class Static:
    def __init__(self, value, doc=None):
        self.deleted = False
        self.value = value
        self.__doc__ = doc
    def __get__(self, inst, cls=None):
        if self.deleted:
            raise AttributeError('Attribute not set')
        return self.value
    def __set__(self, inst, value):
        self.deleted = False
        self.value = value
    def __delete__(self, inst):
        self.deleted = True

class StaticType(type):
    def __delattr__(cls, name):
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__delete__(name)
        else:
            super(StaticType, cls).__delattr__(name)
    def __getattribute__(cls, *args):
        obj = super(StaticType, cls).__getattribute__(*args)
        if isinstance(obj, Static):
            obj = obj.__get__(cls, cls.__class__)
        return obj
    def __setattr__(cls, name, val):
        # check if object already exists
        obj = cls.__dict__.get(name)
        if isinstance(obj, Static):
            obj.__set__(name, val)
        else:
            super(StaticType, cls).__setattr__(name, val)
class MyStatic(metaclass=StaticType):
    """
    Testing static vars
    """
    a = Static(9)
    b = Static(12)
    c = 3

class YourStatic(MyStatic):
    d = Static('woo hoo')
    e = Static('doo wop')
ms1 = MyStatic()
ms2 = MyStatic()
ms3 = MyStatic()
assert ms1.a == ms2.a == ms3.a == MyStatic.a
assert ms1.b == ms2.b == ms3.b == MyStatic.b
assert ms1.c == ms2.c == ms3.c == MyStatic.c
ms1.a = 77
assert ms1.a == ms2.a == ms3.a == MyStatic.a
ms2.b = 99
assert ms1.b == ms2.b == ms3.b == MyStatic.b
MyStatic.a = 101
assert ms1.a == ms2.a == ms3.a == MyStatic.a
MyStatic.b = 139
assert ms1.b == ms2.b == ms3.b == MyStatic.b
del MyStatic.b
for inst in (ms1, ms2, ms3):
    try:
        getattr(inst, 'b')
    except AttributeError:
        pass
    else:
        print('AttributeError not raised on %r' % attr)
ms1.c = 13
ms2.c = 17
ms3.c = 19
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19
MyStatic.c = 43
assert ms1.c == 13
assert ms2.c == 17
assert ms3.c == 19

ys1 = YourStatic()
ys2 = YourStatic()
ys3 = YourStatic()
MyStatic.b = 'burgler'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
assert ys1.d == ys2.d == ys3.d == YourStatic.d
assert ys1.e == ys2.e == ys3.e == YourStatic.e
ys1.a = 'blah'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
ys2.b = 'kelp'
assert ys1.b == ys2.b == ys3.b == YourStatic.b == MyStatic.b
ys1.d = 'fee'
assert ys1.d == ys2.d == ys3.d == YourStatic.d
ys2.e = 'fie'
assert ys1.e == ys2.e == ys3.e == YourStatic.e
MyStatic.a = 'aargh'
assert ys1.a == ys2.a == ys3.a == YourStatic.a == MyStatic.a
>>> 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 A:
    counter =0
    def callme (self):
        A.counter +=1
    def getcount (self):
        return self.counter  
>>> x=A()
>>> y=A()
>>> print(x.getcount())
>>> print(y.getcount())
>>> x.callme() 
>>> print(x.getcount())
>>> print(y.getcount())
0
0
1
1
here object (x) alone increment the counter variable
from 0 to 1 by not object y. But result it as "static counter"
class A(object):

  label="Amazing"

  def __init__(self,d): 
      self.data=d

  def say(self): 
      print("%s %s!"%(self.label,self.data))

class B(A):
  label="Bold"  # overrides A.label

A(5).say()      # Amazing 5!
B(3).say()      # Bold 3!
    >>> class A:
        ...my_var = "shagun"

    >>> print(A.my_var)
        shagun
   >>> a = A()
   >>> a.my_var = "pruthi"
   >>> print(A.my_var,a.my_var)
       shagun pruthi
    >>> class A:
   ...     @staticmethod
   ...     def my_static_method():
   ...             print("Yippey!!")
   ... 
   >>> A.my_static_method()
   Yippey!!
class Fud:

     class_vars = {'origin_open':False}

     def __init__(self, origin = True):
         self.origin = origin
         self.opened = True
         if origin:
             self.class_vars['origin_open'] = True


     def make_another_fud(self):
         ''' Generating another Fud() from the origin instance '''

         return Fud(False)


     def close(self):
         self.opened = False
         if self.origin:
             self.class_vars['origin_open'] = False


fud1 = Fud()
fud2 = fud1.make_another_fud()

print (f"is this the original fud: {fud2.origin}")
print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is this the original fud: False
# is the original fud open: True

fud1.close()

print (f"is the original fud open: {fud2.class_vars['origin_open']}")
# is the original fud open: False
# -*- coding: utf-8 -*-
class Worker:
    id = 1

    def __init__(self):
        self.name = ''
        self.document = ''
        self.id = Worker.id
        Worker.id += 1

    def __str__(self):
        return u"{}.- {} {}".format(self.id, self.name, self.document).encode('utf8')


class Workers:
    def __init__(self):
        self.list = []

    def add(self, name, doc):
        worker = Worker()
        worker.name = name
        worker.document = doc
        self.list.append(worker)


if __name__ == "__main__":
    workers = Workers()
    for item in (('Fiona', '0009898'), ('Maria', '66328191'), ("Sandra", '2342184'), ('Elvira', '425872')):
        workers.add(item[0], item[1])
    for worker in workers.list:
        print(worker)
    print("next id: %i" % Worker.id)
class Student:

    the correct way of static declaration
    i = 10

    incorrect
    self.i = 10
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)
instance = MyClass()
print(instance.i)
print(MyClass.i)
class MyClass:
  i: str
i is not attribute of MyClass