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
Related
I am learning how to do OOP with python. I would like to create a class B that contains an array/list of classA and execute a function in a for loop.
Here is an example:
class A:
def __init__(self, name):
self.name = name
def printSomething(self):
print (self.name)
class B:
def __init__(self, listOfNames):
# struture to store a list of objects A based on the list of names supplied
def printSomething2(self):
for i in # struture to store a list of objects A based on the list of names supplied :
i.printSomething()
names = ["a,b,c,d"]
obj = B(names)
obj.printSomething2()
what python structure is suitable for storing multiple objects? How can I set the size of it based on the input of the class?
For can I iterate over the created structure to call a function?
Best Regards
You could just use:
class B():
def __init__(self,listOfNames):
self.name_objs = []
for name in listOfNames:
self.name_objs.append(A(name))
def printSomething2(self):
for i in self.name_objs:
i.printSomething()
Still this is dynamic and getting the size to set this before is rather hard but this would work
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.
Let's say I want to create a class 'House' that has some attributes of its own, but also has a (nested?) 'Resident' class which has some attributes and has a mandatory attribute 'surname'. A house instance may exist though without any residents. How can create this so that I can eventually do the following?
myhouse = House()
residentX = myhouse.resident('Smith')
Currently I set this up as a nested class but run into trouble when I try and initialise myhouse given that it is requiring a surname at this point for the nested Resident class (which I don't necessarily have at this point)
class House:
def __init__(self):
self.someattribute = <someattribute>
self.resident = self.Resident()
class Resident:
def __init__(self, surname):
self.surname = surname
I know I can restructure the code to not use nested classes and then explicitly tie any resident to a house in my code. However, I would like to use the dot notation here (myhouse.resident) to automatically tie a resident to a house.
Also, I understand that nested classes in python are somewhat frowned upon - I'm open to suggestions on how to do the above in a more pythonic manner.
I would break out the Resident class and use a property/setter for .resident
Like this:
class House:
def __init__(self):
self.someattribute = <someattribute>
self._resident = None
#property
def resident(self):
return self._resident
#resident.setter
def resident(self, surname):
r = Resident(surname)
self._resident = r
class Resident:
def __init__(self, surname):
self.surname = surname
However, if you want .resident to be callable but also want to track the house's residents, you can still break out the Resident class, and use:
class House:
def __init__(self):
self.someattribute = <someattribute>
self.residents = []
def resident(self, surname):
'''
Add a resident to the house
'''
r = Resident(surname)
self.residents.append(r)
return r
class Resident:
def __init__(self, surname):
self.surname = surname
Hi
I have created a List of Objects. Each object contains a Set. I want to update the set's contents for all the objects in the list. The code that i wrote to accomplish this is
class Player:
name = ""
cardsInHand = set()
hasBid = False
def __init__(self, name):
self.name = name
class CardDeck:
deck = []
def __init__(self):
for i in range(39) :
if i%10>0 and i%10<9 :
self.deck.append(i)
def dealCards(self,player):
cardIndex = 0
for tempPlayer in player:
for j in range(4): # since want to add four elements at a time
tempPlayer.cardsInHand.add(self.deck.pop(cardIndex))
cardIndex = cardIndex +1
in the main method I am calling the above classes with the following code
players = []
players.append(Player("Player0"))
players.append(Player("Player1"))
players.append(Player("Player2"))
players.append(Player("Player3"))
cards.dealCards(players)
The problem is that dealCards method adds the elements to all the sets of objects. Instead of 4 elements in each object's set, I endup with same 16 elements in each objects's set?
I am new to python, am i doing something wrong ?
You're creating class attributes.
class Player:
def __init__(self, name):
self.name = name
self.cardsInHand = set()
self.hasBid = False
You've defined cardsInHand (as well as name and hasBid) to be class variables instead of instance variables; by defining them in the class body, you're defining them to be variables shared by all instances. If you're familiar with Java, they are essentially like static variables. To make them instance variables, you need to declare them in the __init__ method, like so:
def __init__(self, name):
self.name = name
self.hasBid = False
self.cardsInHand = set()
In plain english: I am creating class instances dynamically in a for loop, the class then defines a few attributes for the instance. I need to later be able to look up those values in another for loop.
Sample code:
class A:
def __init__(self, name, attr):
self.name=name
self.attr=attr
names=("a1", "a2", "a3")
x=10
for name in names:
name=A(name, x)
x += 1
...
...
...
for name in names:
print name.attr
How can I create an identifier for these instances so they can be accessed later on by "name"?
I've figured a way to get this by associating "name" with the memory location:
class A:
instances=[]
names=[]
def __init__(self, name, attr):
self.name=name
self.attr=attr
A.instances.append(self)
A.names.append(name)
names=("a1", "a2", "a3")
x=10
for name in names:
name=A(name, x)
x += 1
...
...
...
for name in names:
index=A.names.index(name)
print "name: " + name
print "att: " + str(A.instances[index].att)
This has had me scouring the web for 2 days now, and I have not been able to find an answer. Maybe I don't know how to ask the question properly, or maybe it can't be done (as many other posts seemed to be suggesting).
Now this 2nd example works, and for now I will use it. I'm just thinking there has to be an easier way than creating your own makeshift dictionary of index numbers and I'm hoping I didn't waste 2 days looking for an answer that doesn't exist. Anyone have anything?
Thanks in advance,
Andy
Update: A coworker just showed me what he thinks is the simplest way and that is to make an actual dictionary of class instances using the instance "name" as the key.
Sometimes keeping it simple is best. Having a dict that stores your instances with their names as the keys would be both straightforward and fairly simple to implement.
class A:
instances={}
def __init__(self, name, attr):
self.name=name
self.attr=attr
A.instances[name] = self
and then to get the proper instance, just...
instance = A.instances[name]
No need to put the instance dict inside the class. Just create a dict, inst in the local scope:
class A:
def __init__(self, name, attr):
self.name=name
self.attr=attr
inst={}
names=("a1", "a2", "a3")
x=10
for name in names:
inst[name]=A(name, x)
x += 1
Then, whenever you want to access a certain instance by name, just use inst[name]:
for name in names:
print inst[name].attr
Yes, the dictionary approach should work well, and can be dovetailed into the class itself.
class A:
_instances = {}
#classmethod
def get(cls, name):
return A._instances[name]
def __init__(self, name, attr):
self.name=name
self.attr=attr
A._instances[name] = self
a = A('foo', 10)
aa = A.get('foo')
If you want to play around with __new__, you can even make this transparent:
a = A('foo', 10)
aa = A('foo') # 'a' and 'aa' refer to the same instance.
This is a bit complicated, so I'll leave it to you to research (and of course ask another question on SO if you get stuck).