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.
Related
(I'm fairly new to programming, so understand that my query might not make sense. I've tried my best to explain it but if you are still confused, you can ask me to clarify)
I understand the that we can call the class attribute number_of_people and increment by one so that when we create a new instance (in this context, a person), the number of people increases by one:
class Person:
# Class attribute
number_of_people = 0
# Constructor
def __init__(self, name):
self.name = name
# Every time we call the constructor, we increment the number of people.
Person.number_of_people += 1
# Driver code
p1 = Person("Jack")
print(Person.number_of_people)
# output gives 1
However, I'm having trouble with understanding the output of the code when we change the we choose to increment p1.number_of_people instead of Person.numer_of_people:
class Person:
# Class attribute
number_of_people = 0
# Constructor
def __init__(self, name):
self.name = name
# Every time we call the constructor, we increment the number of people.
p1.number_of_people += 1
# Driver code
p1 = Person("Jack")
print(p1.number_of_people)
# output gives 0 (I expected the output to be 1)
I thought that since class attributes can be accessed by both the class and instances, my change wouldn't make a difference. I suspect it has to do with p1 being mentioned in the class before it's mentioned in the driver code, but I'm not sure where to go from there.
I suspect the demonstration you were trying to do for yourself is to examine the difference between using the class attribute as a class attribute, vs as an instance attribute. Consider this difference:
class Person:
population = 0
def __init__(self,name):
self.name = name
Person.population += 1
p1 = Person("Jack")
p2 = Person("Tom")
p3 = Person("Bill")
print(p1.population)
print(p2.population)
print(p3.population)
Output:
3
3
3
Compared to:
class Person:
population = 0
def __init__(self,name):
self.name = name
self.population += 1
p1 = Person("Jack")
p2 = Person("Tom")
p3 = Person("Bill")
print(p1.population)
print(p2.population)
print(p3.population)
Output:
1
1
1
In the second example, the instance starts out using the class attribute, but as soon we change it, it creates an instance attribute that has a separate life.
class Person:
number_of_people = 0 #class atribute,define for the entire class
def __init__(self,name):
self.name=name
p1 = Person('tim') # adding of object to class
p2 = Person('jill')
p3 = Person('Bill')
for x in range(Person.number_of_people): #will loop 3 time this case
print(Person.name) # how do i print all the names in a class
i cant seem to get this working
You would need a global variable to keep track of each instance this way, but more likely you would define a parent class, like People, and then have your Person class inherit from People. People would instead be in charge of tracking how many Person instances you've created. The latter option would be best if you have to look at more than just this one relationship between your Person instances. If you wanted to iterate through your Persons, for example, that could be a methods of your People class.
You could initialize a variable NUMBER_OF_PEOPLE=0 outside your class declaration and then each time someone call __init__ you can add one:
class Person:
# Declare class variables
NUMBER_OF_PEOPLE = 0
LIST_OF_PEOPLE = []
def __init__(self, name):
self.name = name
# Change the class variables
Person.LIST_OF_PEOPLE.append(self)
Person.NUMBER_OF_PEOPLE += 1
#classmethod
def get_number_of_people(cls):
return Person.NUMBER_OF_PEOPLE
p1 = Person("tim")
p2 = Person("jill")
people = [p1, p2] # create a list o two people
# Iterate through the list
for p in Person.LIST_OF_PEOPLE:
# Access the name by calling p.name
print("Name of the current person is: {}.".format(p.name))
# You can still access the NUMBER_OF_PEOPLE variable either by calling Person.get_number_of_people() (since it is a class method)
# or by simply using the NUMBER_OF_PEOPLE variable.
print("Currently, there are {} number of people in the class!".format(Person.get_number_of_people()))
# This will give 1 person.
Your issue here is that you don't completely understand object-oriented programming. You will get better by practising.
I want to initialize variables with default values in a constructor without parameters, like this:
class Persons()
def __init__(self):
self.name="Joan"
p1=Persons()
print(p1.name)
So the result for this, will be "Joan". It will print the name of the person. All good. But how do I do this for multiple objects? I want to print p2.name, p3.name, with different names, just like above.
I got this from an exercise that asks me to "create a constructor without parameters that initializes variables with default data".
Just add name as a parameter:
class Persons()
def __init__(self, name):
self.name = name
p1=Persons(“Joan”)
print(p1.name)
Or
p1.name = “Jim”
If your class can provide a set of possible names, you can create an object from which each call to Person.__init__ gets a different name. For example:
from itertools import cycle
class Person:
names = cycle(["Alice", "Bob", "Carol", "Dan"])
def __init__(self):
self.name = next(Person.names)
Add as many names to the pool as desired.
Names will necessarily repeat once the initial set of names is exhausted and the cycle begins again. With a little more work, we can at least vary the order in which names are produced on each cycle:
from itertools import cycle
import random
class Person:
def shuffled_cycle(names):
while True:
random.shuffle(names)
yield from names
names = shuffled_cycle(["Alice", "Bob", "Carol", "Dan"])
def __init__(self):
self.name = next(Person.names)
Of course, if repeated names aren't a concern, just call random.choice from inside __init__. This is much simpler:
import random
class Person:
def __init__(self):
self.name = random.choice(["Alice", "Bob", "Carol", "Dan"])
Taken to its extreme, just generate random names from a primordial soup of letters:
import random
import string
class Person:
def __init__(self):
k = random.randint(3, 10)
self.name = ''.join(random.sample(string.ascii_lowercase, k)).title()
So the thing is you want to initialize with default values, The code you wrote is correct.Every new instance of "Person" class will initialize with the same default value which is good coding practice.Since it is "default" value thus same. However for the sake of knowledge I have written a small program that can give new names to 5 new instances of class Person however do not use this in production as it is a bad practice but good for learning.
class Person :
#class Variable
name_list=["Jhon","Naruto","James","Smith","Neo"]
instance_count = 0
def __init__(self):
#Resets instance count when instances become greater that 5
instance_count = instance_count%5
#Sets new name
self.name = name_list[instance_count]
#increment instance_count
instance_count = instance_count + 1
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)
Today I am wondering what are the advantages of a class over a callable function. I know it seems like a weird question, but I am coding a space-based game, and I would like to make something that shows lifesupport(oxygen, nitrogen)
Basically, I have this function:
oxygen = 100
nitrogen = 100
air = [oxygen, nitrogen]
print("You can use check(air) to see the quantities of n2 and o2 available.")
def check(variable):
if variable == air:
print("Your oxygen level is {0}% and your nitrogen level is {1}%.".format(oxygen, nitrogen))
So whenever the player types check(air), they can see the amount of nitrogen and oxygen in their ship. Using this I can also allow them to see other functions by expanding the check() function. I'm wondering if it's better to do this for a game rather than to do this:
class Lifesupport(object):
def __init__(self, oxygen, nitrogen):
self.oxygen = oxygen
self.nitrogen = nitrogen
air = Lifesupport(40, 60)
#This part is for checking functionality
print("Your air has {0}% oxygen and {1}% nitrogen".format(air.oxygen, air.nitrogen))
Personally, I prefer the function, though I don't really know which is better to use for this purpose. I know you can type air.oxygen to see just oxygen levels, and I could probably use a check() function to solely print a class "bundle" like 'air'.."
Basically... What are the real advantages of using a class over a function like the code I showed? Is it better to use a class or a function, or both, for my purposes?
For printing the oxygen and nitrogen, you would do:
class Lifesupport(object):
def __init__(self, oxygen, nitrogen):
self.oxygen = oxygen
self.nitrogen = nitrogen
def __str__(self):
return "Your air has {0}% oxygen and {1}% nitrogen".format(self.oxygen, self.nitrogen)
Then later, whenever you want to show the Lifesupport levels, you simply do:
air = Lifesupport(40, 60)
print(air)
The __str__ method overrides the default __str__ method of a class and so when you do print(air), it will print the custom text.
As for class vs. method, it is recommended that you use classes, especially when you know that are going to be expanding your program, since you can create multiple instances of a class that will all have attributes that can be modified independent of each other. Below is an example:
Example
class A:
def __init__(self,num):
self.val = num
a = A(4)
b = A(5)
>>> print(a.val)
4
>>> a.val = 6
>>> print(a.val)
6
>>> print(b.val)
5
Class is an Instance factory. You can create multiple instance (a.k.a copy) of class customize & extend it to your need (by Inheritance & overloading methods).
If you ever want to re-use or customize already written function, then using it inside the class is way to go. I suggest you go through the class coding basic if you have not already done that to make up your mind. a simple example could be
class Person:
def __init__(self, name, job=None, pay=0):
self.name = name
self.job = job
self.pay = pay
def giveRaise(self, percent):
self.pay = int(self.pay * (1 + percent))
class Manager(Person):
def __init__(self, name, pay): # Redefine constructor
Person.__init__(self, name, 'mgr', pay) # Run original with 'mgr'
def giveRaise(self, percent, bonus=.10):
Person.giveRaise(self, percent + bonus)
I'm customizing the original class 'init' method by inheriting original class & adding new information in Manager Class