python类和对象判断问题请教个大神解决
如果我定义了一个class A,并且用此类实例化了很多对象。
那么通过什么方法能够查看A现在已经实例化了哪些对象?对象的个数,名字等?
Python 对象 类 实例
[解决办法]
python不直接支持这种功能,你要自己实现。(这儿记录了我尝试的各种办法以及它们的问题,没兴趣看的可以直接跳到最后一段代码,我觉得没有什么问题了。刚看完3个小时的有关meta programming的讲座,忍不住拿来用用,罗嗦了点,大家多多包涵)。
虽然我写了这么多,但我希望你用到它再想想:能否用一个list/set等保存你想保存的实例,而不是让类本身来保存。
In [246]: class InstanceTracking:
...: _instances = []
...: def __init__(self, name):
...: self.name = name
...: InstanceTracking._instances.append(self)
...: @classmethod
...: def listInstances(cls):
...: for instance in cls._instances:
...: print "obj:", instance.name
...: @classmethod
...: def totalInstances(cls):
...: return len(cls._instances)
...:
In [247]: InstanceTracking.totalInstances()
Out[247]: 0
In [248]: A = InstanceTracking('a')
In [249]: InstanceTracking.totalInstances()
Out[249]: 1
In [250]: InstanceTracking.listInstances()
obj: a
In [251]: B = InstanceTracking('b')
In [252]: InstanceTracking.listInstances()
obj: a
obj: b
In [253]: class Fruits(InstanceTracking):
...: pass
In [254]: apple = Fruits('apple')
In [255]: InstanceTracking.listInstances()
obj: a
obj: b
obj: apple
In [256]: Fruits.listInstances()
obj: a
obj: b
obj: apple
In [260]: class InstanceTracking2:
...: _instances = []
...: def __init__(self, name):
...: self.name = name
...: self.__class__._instances.append(self)
...: @classmethod
...: def listInstances(cls):
...: for instance in cls._instances:
...: print "obj:", instance.name
...: @classmethod
...: def totalInstances(cls):
...: return len(cls._instances)
In [261]: class Fruit2(InstanceTracking2):
...: _instances = []
In [262]: apple2 = Fruit2('apple')
In [263]: class Car2(InstanceTracking2):
...: _instances = []
...:
In [264]: changan = Car2('changan')
In [265]: Car2.listInstances()
obj: changan
In [266]: Fruit2.listInstances()
obj: apple
In [267]: class Ball2(InstanceTracking2):
...: pass
In [268]: tennis = Ball2('tennis')
In [269]: class City2(InstanceTracking2):
...: pass
In [270]: beijing = City2('Beijing')
In [271]: City2.listInstances()
obj: tennis
obj: Beijing
In [371]: def addInstanceTracking(cls):
...: cls._instances = []
...: @classmethod
...: def listInstances(cls):
...: for i in cls._instances:
...: print "obj:", i.name
...: @classmethod
...: def totalInstances(cls):
...: return len(cls._instances)
...: old_init = cls.__init__
...: def new_init(self, *arg, **args):
...: self.__class__._instances.append(self)
...: old_init(self, *arg, **args)
...: cls.listInstances = listInstances
...: cls.totalInstances = totalInstances
...: cls.__init__ = new_init
...:
...: return cls
In [372]: @addInstanceTracking
...: class Fruit6:
...: def __init__(self, name):
...: self.name = name
...:
In [373]: orange6 = Fruit6('orange')
In [374]: Fruit6.listInstances()
obj: orange
In [375]: class RedFruit6(Fruit6): #decorator对子类没用,所以这儿的效果就像上一个方案中
...: pass #子类忘了定义_instances一样
In [376]: strawberry = RedFruit6('strawberry')
In [377]: RedFruit6.listInstances() #子类共享父类的_instances
obj: orange
obj: strawberry
In [378]: Fruit6.listInstances()
obj: orange
obj: strawberry
In [379]: @addInstanceTracking #再加上decorator试试
...: class SummerFruit6(Fruit6):
...: pass
In [379]:
In [380]: watermalon = SummerFruit6('watermalon')
In [381]: SummerFruit6.listInstances() #由于SummerFruit6,Fruit6中的__init__
#都有_instances.append的调用,所以加了两遍
obj: watermalon
obj: watermalon
In [382]: Fruit6.listInstances()
obj: orange
obj: strawberry
In [319]: class InstTracking(type):
...: def __init__(cls, name, bases, dct):
...: type.__init__(cls, name, bases, dct)
...: cls._instances = []
...: @classmethod
...: def listInstances(cls):
...: for i in cls._instances:
...: print "obj:", i.name
...: @classmethod
...: def totalInstances(cls):
...: return len(cls._instances)
...: if '__init__' in dct:
...: old_init = dct['__init__']
...: def new_init(self, *arg, **args):
...: self.__class__._instances.append(self)
...: old_init(self, *arg, **args)
...: cls.__init__ = new_init
...: cls.totalInstances = totalInstances
...: cls.listInstances = listInstances
In [320]: class InstanceTracking4:
...: __metaclass__ = InstTracking
...: pass
In [321]: class Fruit4(InstanceTracking4):
...: def __init__(self, name):
...: self.name = name
In [322]: orange4 = Fruit4('orange')
In [323]: Fruit4.listInstances()
obj: orange
In [324]: class Car4(InstanceTracking4):
...: def __init__(self, name):
...: self.name = name
...:
In [325]: audi4 = Car4('audi')
In [326]: Car4.listInstances()
obj: audi
In [327]: class Truck4(Car4): # 孙子辈的也有这本事
...: pass
In [328]: dongfeng4 = Truck4('dongfeng')
In [330]: Truck4.listInstances()
obj: dongfeng
In [331]: Car4.listInstances()
obj: audi
In [354]: class InstTrackingWeakRef(type):
...: def __init__(cls, name, bases, dct):
...: type.__init__(cls, name, bases, dct)
...: cls._instances = weakref.WeakSet()
...: @classmethod
...: def listInstances(cls):
...: for i in cls._instances:
...: if i is not None:
...: print "obj:", i.name # 也许要定义的类没有name,用str(i)更好
...: else:
...: cls._instances.remove(i)
...: @classmethod
...: def totalInstances(cls):
...: return len(cls._instances)
...: if '__init__' in dct:
...: old_init = dct['__init__']
...: def new_init(self, *arg, **args):
...: self.__class__._instances.add(self)
...: old_init(self, *arg, **args)
...: cls.__init__ = new_init
...: cls.totalInstances = totalInstances
...: cls.listInstances = listInstances
...:
In [355]: class InstanceTrackingWeakRef:
...: __metaclass__ = InstTrackingWeakRef
...: pass
In [356]: class Fruit5(InstanceTrackingWeakRef):
...: def __init__(self, name):
...: self.name = name
...:
In [357]: orange5 = Fruit5('orange')
In [358]: Fruit5.listInstances()
obj: orange
In [359]: del orange5
In [360]: Fruit5.listInstances()
In [361]: Fruit5.totalInstances()
Out[361]: 0
In [362]: class RedFruit5(Fruit5):
...: pass
In [363]: strawberry5 = RedFruit5('strawberry')
In [364]: RedFruit5.listInstances()
obj: strawberry
In [365]: apple = Fruit5('apple')
In [366]: RedFruit5.listInstances()
obj: strawberry
In [367]: Fruit5.listInstances()
obj: apple
In [368]: del strawberry5
In [369]: RedFruit5.listInstances()
In [370]: RedFruit5.totalInstances()
Out[370]: 0
In [371]: