这是以下帖子的后续问题(不需要检查链接就可以理解问题)
Counter variable for class
我们将idCounter
设置为类student的类变量,它计算创建的实例数。
这是班级:
class Student:
# A student ID counter
idCounter = 0
def __init__(self):
self.gpa = 0
self.record = {}
# Each time I create a new student, the idCounter increment
Student.idCounter += 1
self.name = 'Student {0}'.format(Student.idCounter)
现在,我们实例化几个实例,然后检查
idCounter
的值:student1 = Student()
student2 = Student()
student3 = Student()
student4 = Student()
Student.idCounter
4
但是,如果您可以这样做,则维护计数器将变得毫无意义:
Student.idCounter = 2000
现在创建新实例:
student5 = Student()
检查一下:
Student.idCounter
2001
idCounter
可以简单地将计数器调高,而无需运行idCounter
。如何创建只在
__init__
运行时递增的计数器(或任何类变量)?不能通过调用类中的类变量独立修改,如上图所示。有没有一种通用的方法来限制使用语法修改类变量?
ClassName.ClassVariable = new_value
谢谢您。
最佳答案
编辑
改进版具有property
但原则相同:
class Meta(type):
def __init__(cls, *args, **kwargs):
cls.__value = 0
super().__init__(*args, **kwargs)
@property
def idCounter(cls):
return cls.__value
class Student(metaclass=Meta):
def __init__(self):
self.__class__._Meta__value += 1
现在:
>>> s1 = Student()
>>> Student.idCounter
1
>>> s2 = Student()
>>> Student.idCounter
2
>>> Student.idCounter = 100
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-64-a525899df18d> in <module>()
----> 1 Student.idCounter = 100
AttributeError: can't set attribute
旧版本
使用描述符和元类:
class Counter:
def __init__(self):
self.value = 0
def __get__(self, instance, cls):
return getattr(instance, '_{}__hidden_counter'.format(instance.__name__ ))
def __set__(self, instance, value):
raise NotImplementedError
class Meta(type):
idCounter = Counter()
class Student(metaclass=Meta):
__hidden_counter = 0
def __init__(self):
Student.__hidden_counter += 1
似乎实现了这一点:
>>> s1 = Student()
>>> Student.idCounter
1
>>> s2 = Student()
>>> Student.idCounter
2
>>> Student.idCounter = 200
---------------------------------------------------------------------------
NotImplementedError Traceback (most recent call last)
<ipython-input-51-dc2483b583f6> in <module>()
----> 1 Student.idCounter = 200
<ipython-input-46-b21e03bf3cb3> in __set__(self, instance, value)
5 return getattr(instance, '_{}__hidden_counter'.format(instance.__name__ ))
6 def __set__(self, instance, value):
----> 7 raise NotImplementedError
8
9 class Meta(type):
NotImplementedError:
>>> Student.idCounter
2
这仍然可以故意打破:
>>> Student._Student__hidden_counter = 100
>>> Student.idCounter
100
但不是偶然的。