想象一下,对于一个游戏,你有一个类NaveEspacial
,其中玩家有能力在创建船后更改船名:
class NaveEspacial:
def __init__(self, nombre, capitan):
self.nombre = nombre
self.capitan = capitan
def imprimir_datos(self):
datos = {
'nombre': self.nombre,
'capitan': self.capitan
}
print datos
def renombrar(self, nombre):
self.nombre = nombre
nave = NaveEspacial('Death Star', 'Cesitar')
nave.renombrar('Millennium Falcon')
nave.imprimir_datos()
# Resultado
{'nombre': 'Death Star', 'capitan': 'Cesitar'}
{'nombre': 'Millennium Falcon', 'capitan': 'Cesitar'}
如果您想知道船名被更改了多少次,您可以添加一个计数器:
class NaveEspacial:
def __init__(self, nombre, capitan):
self.nombre = nombre
self.capitan = capitan
self.total_renombres = 0
def imprimir_datos(self):
datos = {
'nombre': self.nombre,
'capitan': self.capitan,
'total_renombres': self.total_renombres
}
print datos
def renombrar(self, nombre):
self.nombre = nombre
self.total_renombres += 1
nave = NaveEspacial('Death Star', 'Cesitar')
nave.imprimir_datos()
nave.renombrar('Millennium Falcon')
nave.imprimir_datos()
# Resultado
{'nombre': 'Death Star', 'capitan': 'Cesitar', 'total_renombres': 0}
{'nombre': 'Millennium Falcon', 'capitan': 'Cesitar', 'total_renombres': 1}
但是上面的内容只能帮助我知道每个类的实例,即每艘船,被重命名了多少次:
nave = NaveEspacial('Death Star', 'Cesitar')
nave.imprimir_datos()
nave.renombrar('Millennium Falcon')
nave.imprimir_datos()
nave = NaveEspacial('USS Enterprise', 'Fiorella')
nave.imprimir_datos()
nave.renombrar('USS Centaur')
nave.imprimir_datos()
nave.renombrar('USS Challenger')
nave.imprimir_datos()
# Resultado
{'nombre': 'Death Star', 'capitan': 'Cesitar', 'total_renombres': 0}
{'nombre': 'Millennium Falcon', 'capitan': 'Cesitar', 'total_renombres': 1}
{'nombre': 'USS Enterprise', 'capitan': 'Fiorella', 'total_renombres': 0}
{'nombre': 'USS Centaur', 'capitan': 'Fiorella', 'total_renombres': 1}
{'nombre': 'USS Challenger', 'capitan': 'Fiorella', 'total_renombres': 2}
我需要的是计算对类方法的调用总数,而不是每个实例的总数。我知道一种方法可能是累积所有船只并添加total_renombres
每艘船的属性:
naves = [nave1, nave2, nave3]
total = sum([nave.total_renombres for nave in naves])
但我想知道是否可以在类级别上执行此操作,作为游戏生命周期中的某种持久变量。有没有办法做到这一点?
笔记:
现在我想保持简单并避免使用数据库。
更新 1(来自@RuslanLópezCarro 的回答)
可以通过创建类的变量来获得总数,但这意味着每次调用方法时都必须手动增加变量renombrar()
:
nave1 = NaveEspacial('Death Star', 'Cesitar')
nave1.renombrar('Millennium Falcon')
NaveEspacial.total_llamadas += 1 # Incrementar
nave2 = NaveEspacial('USS Enterprise', 'Fiorella')
nave2.renombrar('USS Centaur')
NaveEspacial.total_llamadas += 1 # Incrementar
nave2.renombrar('USS Challenger')
NaveEspacial.total_llamadas += 1 # Incrementar
nave3 = NaveEspacial('ABC', 'Tany')
nave3.renombrar('XYZ')
NaveEspacial.total_llamadas += 1 # Incrementar
print NaveEspacial.total_llamadas
# Resultado 4
这对我来说似乎不是一个选项,我想在每个方法调用中自动完成。
更新:
我刚刚修复了缺少的代码行,使装饰器不调用被装饰的函数。
我还包括计算类的多个方法的调用的方法。
在我看来,实现这一点的最佳方法是使用
decorador
静态变量处理程序(我为我编写的所有方法添加注释):此代码的输出与预期的一样:
因此,推荐的步骤是:
0
。------
奖金:
要实现对多个方法的调用计数,必须对装饰器函数进行小幅更改,以便它识别正在装饰的函数,从而知道哪个计数器对其递增进行排序:
在类定义中声明你的变量
这样它将是一个静态变量。有关更多信息,您可以参考这个问题。
我找到了一种方法,比@Nicolás 提供的方法简单一点,但同时也更“晦涩”一些。
根据有关方法
im_func
的文档,可以通过使用为类的实例方法提供的特殊只读属性来任意为其分配属性。这是不可能的:
如果可能的话:
这样就可以这样定义类:
通过这种方式,我能够拥有一个通用计数器,并且每个实例都有一个。
笔记:
我刚刚在 Python 3.x 中尝试过,似乎这是不可能的,至少不是按照这个答案中描述的方式。
最好的解决方案是使用描述符作为类属性。
代码可能是这样的:
为了使用,创建一个实例并将其分配给类的属性
NaveEspacial
:这段代码几乎每次都能正常工作。但是,仍然有可能将类属性与任意值(例如:)“混搭”
NaveEspacial.total_renombres = 0
。如果您需要完全隐藏它,请使用"name mangling",即使用双下划线重命名属性(例如:)__total_renombres
。El resto de respuestas ya dan diferentes soluciones para llevar la cuenta de los renombre a partir de la propia clase, pero que una nave tenga que llevar la cuenta de los renombres de todas las naves de la flota espacial no es una buena idea. Utilizando diseño orientado a objetos se puede obtener más flexibilidad y permite probar las cosas de forma separada.
Aplicando el principio de separación de intereses (separation of concerns) se puede crea una clase nueva que sea la responsable de llevar la cuenta de las naves y los renombres.
Para que cada nave se entere de a que comandancia ha de rendir cuentas se le ha de indicar, a esto se le llama inyección de dependecias
Al renombrar la nave podemos consultar a la comandancia que naves hay
Si no queremos andar especificando a cada nave a que comandancia ha de rendir cuentas podemos crear una factoría que se encargue de inyectar esa dependencia directamente y así no tener que especificarlo para todas las naves:
En mi opinión una de las mejores soluciones pasa por combinar conceptos expuestos en las otras respuestas en el caso de querer aplicarla a métodos concretos de una clase.
Utilizando un
descriptor
para decorar el método (que durante la decoración todavía es función) para controlar el accesso (get/set) al atributoUtilizando una clase auxiliar para envolver a la función convertida en método y controlar las llamadas al método
Utilizando el acceso al descriptor a nivel de clase, para poder acceder a sus métodos (como p.ej el que devuelve el número de renombrados)
De esta manera:
Podemos llevar la cuenta por clase
Evitamos que el atributo sea sobre-escribible a nivel de instancia (a nivel de clase lo es)
Código:
Resultado: