Python中是否可以使用静态类变量?
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
>>> 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