A class is defined like this:
class IterRegistry(type):
def __iter__(cls):
return iter(cls._registry)
class Example:
__metaclass__ = IterRegistry
_registry =[]
def __init__(self,iD):
self.iD = iD
self.count = 40
self._registry.append(self)
def reduceCount(self):
self.count -= 1
Over the course of the program more and more instances of the class are created. I have an timer running, which then runs a for Loop over all the instances and reduces the count by 1 for each.
def timer():
for i in Example:
i.reduceCount()
if i.count < 0:
#then delete the instance
My question is how do I delete this instance?
You may use a del statement.
del can also be used to delete entire variables:
>>> del a
Referencing the name a hereafter is an error (at least until another value is assigned to it).
But at the end of the day, this is just a suggestion to the garbage collector. Object may be deleted right away, but it also may be deleted long after execution of this statement. It's not guaranteed by a language specification.
To answer my question I followed #Unholysheep advice and removed it from the registry in the class. To do this I had to change the code slightly by changing _reigstry to registry, so I can acess it from the rest of the program.
class IterRegistry(type):
def __iter__(cls):
return iter(cls.registry)
class Example:
__metaclass__ = IterRegistry
registry =[]
def __init__(self,iD):
self.iD = iD
self.count = 40
self.registry.append(self)
def reduceCount(self):
self.count -= 1
This now allows me to remove the instance from inside the loop by:
def timer():
for i in Example:
i.reduceCount()
if i.count < 0:
#then delete the instance
Example.registry.remove(i)
Related
I have two classes and one is using selenium to scrape like 25 different pages and it takes a really long time. I have another class that would take 1 second to run but its calling a variable from the other class. I want self.numbers to equal data.scores and somehow keep the value set so that testing will only take a second. The class that takes forever is AllData() and I want self.numbers to persist without having to copy and paste the printed value.
from collections import defaultdict
from data import *
class Test:
def __init__(self,):
data = AllData()
self.numbers = data.scores
I'm not sure I've fully understood. Would using a class variable solve your problem? This means that you can call the current value
class a:
var = {'init':'has', 'not':'run'}
def __new__(cls):
cls.var = {'new has':'run'}
return super(a, cls).__new__(cls)
def __init__(self):
self.var['so has'] = 'init'
class b:
def __init__(self, obj):
self.sav = obj.var
Example use:
>>> b(a).var
{'init':'has', 'not':'run'}
>>> b(a()).var
{'new has': 'run', 'so has': 'init'}
I understand that in Python there is no real notion of private/protected/public class members. Yet, using underscores this can be achieved to some extents. For example, consider an object that is supposed to count the number of even integers on a stream. The following would be a relatively safe implementation
class EvensCounter:
def __init__(self):
self._count = 0
def __call__(self, n):
if n % 2 == 0:
self._count += 1
#property
def count(self):
return self._count
This way, the user cannot accidentally change count for example in the following way:
counter = EvensCounter()
counter.count = 5 # Gives AttributeError: can't set attribute
I used to see this as an equivalent of defining count as a private member variable in C++ and then having only a getter that returns a const reference to the private member variable.
However, I realize that the above is not exactly correct. Suppose instead of a simple int, count was of a more sophisticated type of MyInt defined as follows:
class MyInt:
def __init__(self):
self._value = 0
def inc(self, n=1):
self._value += n
#property
def value(self):
return self._value
class EvensCounter:
def __init__(self):
self._count = MyInt()
def __call__(self, n):
if n % 2 == 0:
self._count.inc()
#property
def count(self):
return self._count
In this case, the following piece of code would work and effectively modify the count value:
counter = EvensCounter()
counter.count.inc(5)
While the user cannot change _count variable to reference another object, it can still call methods of that object that change its state. (Whereas in C++, because the inc() method is not a const method, it cannot be called on a const reference.)
I was wondering if there is a mechanism in Python that provides same safety guarantees as the const references of C++? Namely, I need a way to expose a reference to a (private) member of the class that only allows the user to 'read' that member variable, but does not permit him to change the state of that member variable.
No, there's no such thing. C++ is the only major language that supports it (by "major", i mean "top 10 in market popularity", don't want to start a flamewar). Python obviously has no const concept, but even in language that do, const prevents you from re-assigning the variable, but not changing the object it refers to.
So, the main distinction in most languages is whether the object returned to is mutable or immutable as your two examples already illustrate. There's nothing you can do but hope that users respect your API.
In general, no. Python's philosophy for preventing users from shooting themselves in the foot is "Hey, try not to shoot your foot please." With some effort, you can add in some extra safeties, but you won't be able to stop users who point at their foot and pull the trigger.
Does your member need to be a reference? Returning a deep copy will at least prevent the private member from being unintentionally modified.
You could also handle the const-ness yourself. For example:
class MyInt:
def __init__(self):
self._value = 0
self._is_locked = True
def inc(self, n=1):
if not self._is_locked:
self._value += n
else:
raise RuntimeError('Stop trying to modify the value outside of EvensCounter, dummy!')
#property
def value(self):
return self._value
class EvensCounter:
def __init__(self):
self._count = MyInt()
def __call__(self, n):
if n % 2 == 0:
self._count._is_locked = False # If I were *actually* writing code like this, I would make this a context manager
self._count.inc()
self._count._is_locked = True
#property
def count(self):
return self._count
You could also maybe return a proxy that uses something like frozendict under the hood, but I think that is susceptible to the same issue that you mentioned where nested members can be modified.
I want to change the name of the object each time a object is created so that there's an accumulator adding everytime an object is created. In this example i want the first object.name to be B1 and then the second object.name to be B2 and then B3 and so on. This is what im trying to get
class Object:
def __init__(self):
self.name = "B" + (accumulator)
this is what I tried but i am not really getting anywhere
class BankAccount:
def __init__(self, balance):
self.account_number = "B" + str(number = number + 1)
self.balance = balance
I cant think of a way to avoid the issue of trying to set a variable to equal plus one of itself because itself isn't defined yet.
The simplest approach here is a class variable that stores the next value to use, which you increment after use:
class BankAccount:
_nextnum = 1
def __init__(self, balance):
self.account_number = "B" + str(self._nextnum)
type(self)._nextnum += 1 # Must set it on the class, or you only make a shadowing instance attribute
self.balance = balance
This isn't thread safe without locking though, so if you want thread-safety, itertools.count can do the same job in a thread-safe (at least on CPython) manner:
import itertools
class BankAccount:
_numgenerator = itertools.count(1)
def __init__(self, balance):
self.account_number = "B" + str(next(self._numgenerator))
self.balance = balance
Since itertools.count's work is done at the C layer with the GIL held, it operates atomically, both returning the next number and moving the count along as a single atomic operation.
You can have a class level variable maintain how many objects were created, and then use that to determine the name
class BankAccount:
count = 0
def __init__(self):
self.name = "B" + str(BankAccount.count)
BankAccount.count += 1
This is not thread safe however, as mentioned by #ShadowRanger. It's likly a better idea to use itertools.count as they suggest.
I have this python code. The result is TopTest: attr1=0, attr2=1 for X which is fine but the result is SubTest: attr1=2, attr2=3 for Y which I don't quite understand.
Basically, I have a class attribute, which is a counter, and it runs in the __init__ method. When I launch Y, the counter is set to 2 and only after are the attributes are assigned. I don't understand why it starts at 2. Shouldn't the subclass copy the superclass and the counter restart at 0?
class AttrDisplay:
def gatherAttrs(self):
attrs = []
for key in sorted(self.__dict__):
attrs.append('%s=%s' % (key, getattr(self, key)))
return ', '.join(attrs)
def __repr__(self):
return '[%s: %s]' % (self.__class__.__name__, self.gatherAttrs())
class TopTest(AttrDisplay):
count = 0
def __init__(self):
self.attr1 = TopTest.count
self.attr2 = TopTest.count+1
TopTest.count += 2
class SubTest(TopTest):
pass
X, Y = TopTest(), SubTest()
print(X)
print(Y)
You access and use explicitly TopTest.count, and your subclass will stick to this explicitness. You might want to consider to use type(self).count instead, then each instance will use its own class's variable which can be made a different one in each subclass.
To make your subclass have its own class variable, just add a count = 0 to its definition:
class SubTest(TopTest):
count = 0
It looks like you want to keep a counter for each instance of each subclass of TopTest, but you do not want to repeat yourself by declaring a new count class variable for each subclass. You can achieve this using a Metaclass:
class TestMeta(type):
def __new__(cls, name, bases, attrs):
new_class = super().__new__(cls, name, bases, attrs)
new_class.count = 0
return new_class
class TopTest(AttrDisplay, metaclass=TestMeta):
def __init__(self):
self.attr1 = self.count
self.attr2 = self.count + 1
self.increment_count(2)
#classmethod
def increment_count(cls, val):
cls.count += val
class SubTest(TopTest):
pass
The count attribute of your x and y objects should now be independent, and subsequent instances of TopTest and SubTest will increment the count:
>>> x, y = TopTest(), SubTest()
>>> x.attr2
1
>>> y.attr2
1
>>> y2 = SubTest()
>>> y2.attr2
3
However, metaclasses can be confusing and should only be used if they are truly necessary. In your particular case it would be much simpler just to re-define the count class attribute for every subclass of TopTest:
class SubTest(TopTest):
count = 0
You're close - when you look up a property of an object, you're not necessarily looking up a property belonging to the object itself. Rather, lookups follow Python's method resolution order, which... isn't entirely simple. In this case, however, only three steps are performed:
Check if Y has a property named count.
It doesn't, so check if its class SubTest has a property named count.
It doesn't, so check if its parent TopTest has a property named count. It does, so access that.
Simply put, when you access Y.count, you're actually accessing TopTest.count.
There's also the fact that you have a bug in your code - SubTest increments TopTest's count and not its own. The title of your question says "subclass counter", but since you're counting in __init__() I assume you're looking for an instance counter (to count subclasses I'm fairly certain you'd need to use metaclasses). This is a perfect use case for self.__class__, a property which contains an object's class! In order to use it:
def __init__(self):
self.attr1 = self.__class__.count
self.attr2 = self.__class__.count + 1
self.__class__.count += 2
Using that, SubTest.count will be incremented instead of TopTest.count when you call SubTest().
When a new instance of SubTest is created TopTest.__init__() is called - since SubTest inherited TopTest.__init__() - which increments TopTest.count by two.
And since SubTest never defines a class level count variable, when SubTest.count is executed, Python falls back and uses TopTest.count.
This behavior can be fixed by redefining count local to SubTest.
class SubTest(TopTest):
count = 0
If you want each class to have it's own class variable implicitly, you can use a metaclass to add in this variable.
class MetaCount(type):
def __new__(cls, name, bases, attrs):
new_cls = super(MetaCount, cls).__new__(cls, name, bases, attrs)
new_cls.count = 0
return new_cls
class Parent(metaclass=MetaCount):
def __init__(self):
self.attr1 = self.count
self.attr2 = self.count + 1
type(self).count += 2 # self.count += 2 creates an *instance* variable
class Child(Parent):
pass
p, c = Parent(), Child()
print(p.count) # 2
print(c.count) # 2
One of my classes does a lot of aggregate calculating on a collection of objects, then assigns an attribute and value appropriate to the specific object: I.e.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
class LeagueDetails(object):
def __init__(self): # added for clarity, corrected another typo
self.team_list = [Team('name'), ...]
self.calculate_league_standings() # added for clarity
def calculate_league_standings(self):
# calculate standings as a team_place_dict
for team in self.team_list:
team.place = team_place_dict[team.name] # a new team attribute
I know, as long as the calculate_league_standings has been run, every team has team.place. What I would like to be able to do is to scan the code for class Team(object) and read all the attributes, both created by class methods and also created by external methods which operate on class objects. I am getting a little sick of typing for p in dir(team): print p just to see what the attribute names are. I could define a bunch of blank attributes in the Team __init__. E.g.
class Team(object):
def __init__(self, name): # updated for typo in code, added self
self.name = name
self.place = None # dummy attribute, but recognizable when the code is scanned
It seems redundant to have calculate_league_standings return team._place and then add
#property
def place(self): return self._place
I know I could comment a list of attributes at the top class Team, which is the obvious solution, but I feel like there has to be a best practice here, something pythonic and elegant here.
If I half understand your question, you want to keep track of which attributes of an instance have been added after initialization. If this is the case, you could use something like this:
#! /usr/bin/python3.2
def trackable (cls):
cls._tracked = {}
oSetter = cls.__setattr__
def setter (self, k, v):
try: self.initialized
except: return oSetter (self, k, v)
try: self.k
except:
if not self in self.__class__._tracked:
self.__class__._tracked [self] = []
self.__class__._tracked [self].append (k)
return oSetter (self, k, v)
cls.__setattr__ = setter
oInit = cls.__init__
def init (self, *args, **kwargs):
o = oInit (self, *args, **kwargs)
self.initialized = 42
return o
cls.__init__ = init
oGetter = cls.__getattribute__
def getter (self, k):
if k == 'tracked': return self.__class__._tracked [self]
return oGetter (self, k)
cls.__getattribute__ = getter
return cls
#trackable
class Team:
def __init__ (self, name, region):
self.name = name
self.region = region
#set name and region during initialization
t = Team ('A', 'EU')
#set rank and ELO outside (hence trackable)
#in your "aggregate" functions
t.rank = 4 # a new team attribute
t.ELO = 14 # a new team attribute
#see witch attributes have been created after initialization
print (t.tracked)
If I did not understand the question, please do specify which part I got wrong.
Due to Python's dynamic nature, I don't believe there is a general answer to your question. An attribute of an instance can be set in many ways, including pure assignment, setattr(), and writes to __dict__ . Writing a tool to statically analyze Python code and correctly determine all possible attributes of an class by analyzing all these methods would be very difficult.
In your specific case, as the programmer you know that class Team will have a place attribute in many instances, so you can decide to be explicit and write its constructor like so:
class Team(object):
def __init__(name ,place=None):
self.name = name
self.place = place
I would say there is no need to define a property of a simple attribute, unless you wanted side effects or derivations to happen at read or write time.