I am learning Python as a beginner and I'd like to create a class Person. In the constructor I would want to put every instance I create into a set called 'instances'. Then I'd like the instances() method to return all the instances. How can I do this?
class Person:
# Type annotations
__first_name: str
__last_name: str
instances: set
# Initializing variables
no_of_persons = 0
instances = set()
def __init__(self, firstname="unknown", lastname="unknown"):
self.__first_name = firstname
self.__last_name = lastname
Person.no_of_persons += 1
Person.instances.add() ## Here I have problems
#property
def first_name(self):
return self.__first_name
#first_name.setter
def first_name(self, firstname):
self.__first_name = firstname
#property
def last_name(self, ):
return self.__last_name
#last_name.setter
def last_name(self, lastname):
self.__last_name = lastname
def getFullName(self):
""" Returns a tuple of the firstname and the lastname """
return (self.__first_name, self.__last_name)
def summary(self):
""" Returns a dictionary of all instance variables """
return {'first_name': self.__first_name,
'last_name': self.__last_name}
#staticmethod
def number_of_persons():
return Person.no_of_persons
#staticmethod
def instances():
return Person.instances
p1 = Person()
Person.number_of_persons()
Person.instances()
You need to add self to the set.
Person.instances.add(self)
or more idiomatically
self.__class__.instances.add(self)
Also, you need to use a different name for the method that gets the instances; and it should be a classmethod, not a staticmethod.
#classmethod
def get_instances(cls):
return cls.instances
Although really you don't need a method here at all, as you can access Person.instances (the attribute) directly.
Related
I have a list of objects of the Person class. This list includes myself, so I need to remove "myself" from the list.
It means I need to remove the object from the list that calls this method.
class Population:
def __init__(self):
self.people = list()
class Person:
def __init__(self):
self.friends_list = list()
def make_friends(self, population, n):
temp_list = population.copy()
temp_list.remove(self)
self.friends_list.extend(random.sample(temp_list,n))
my test:
per = Person()
per2 = Person()
per3 = Person()
per4 = Person()
per5 = Person()
pop = [per,per2,per3,per4,per5]
for per in pop:
per.make_friends(pop, 2)
print('ME: ',per)
print(per.friends_list)
My tests run well, but there are general tests that check the code and they generate an error on this line:
try:
stud_res = person.make_friends(population, count)
except Exception:
print("\tPerson.make_friends() generated error")
return
Can I use self in this way, and if not, how can I better remove "myself" from the list?
It is a perfectly fine use case. By the way, note that you're overriding the builtin list.
To use self, you have to share a list collection between instances of a Person-class. In that case this collection should be declared as a class attribute or global list variable (not an instance attribute).
These samples of code are working:
with global list variable:
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
the_list = []
the_list.append(p1)
the_list.append(p2)
p1.make_friends(the_list)
print(the_list)
With class attribute:
class Person2:
class_list = []
def __init__(self, name):
self.name = name
Person2.class_list.append(self)
def make_friends(self):
Person2.class_list.remove(self)
def __repr__(self):
return self.name
p1 = Person2("Joe")
p2 = Person2("Barack")
print(Person2.class_list)
p1.make_friends()
print(Person2.class_list)
EDIT:
Variable 3 when a list of people is inside another class.
For accessing a list inside another class you could use attribute name or public method to get it if implemented:
class ClassWithList:
def __init__(self):
self.list_collection = []
def get_list(self):
return self.list_collection
class_with_list = ClassWithList()
class Person:
def __init__(self, name):
self.name = name
def make_friends(self, list):
list.remove(self)
def __repr__(self):
return self.name
p1 = Person("Joe")
p2 = Person("Barack")
# using implemented get-method of instance list attribute
class_with_list.get_list().append(p1)
class_with_list.get_list().append(p2)
print(class_with_list.get_list())
p1.make_friends(class_with_list.get_list())
print(class_with_list.get_list())
# instance list attribute of class`ClassWithList
print(class_with_list.list_collection)
p2.make_friends(class_with_list.list_collection)
print(class_with_list.list_collection)
how to return the name of the object-
class sampleclass:
def __init__(self):
pass
def __str__(self):
return self
dogfood = sampleclass
print(dogfood)
outputs this :
class '__main__.sampleclass'
..Trying to output dogfood
Reading the variable name is not possible easily.
You could instead use some kind of key-value store (dictionary). Then you can read out the name of the key under that a value is stored.
Attributes are one way to store a custom name string inside an object that can be retrieved later:
class sampleclass:
def __init__(self, name):
self.name = name
def __str__(self):
return self
sample_object = sampleclass('dogfood')
print(sample_object.name)
# Output: 'dogfood'
I am try to reference an object variable inside the class without passing it in parameters but it is throwing error
class Sample:
def __init__(self):
v = []
v.append(name)
v.append(email)
s = Sample()
s.name = "xxxx"
s.email = "ss#ss.com"
print s.v
error:
NameError: global name 'name' is not defined
I am assigning the variable name in the object now how can i call it inside the class without adding parameters to function
if you absolutely must avoid attributes:
class Sample:
def __init__(self):
self.v = []
def addName(self, name):
self.v.append(name)
def addEmail(self, email):
self.v.append(email)
s = Sample()
s.addName("xxxx")
s.addEmail("abc#def.com")
print(s.v)
Yet another way to do this is to use decorators and #property:
class Sample(object):
def __init__(self):
self.v = [None, None]
#property
def name(self):
return self.v[0]
#property
def email(self):
return self.v[1]
#name.setter
def name(self, value):
self.v[0] = value
#email.setter
def email(self, value):
self.v[1] = value
s = Sample()
s.name = "xxxx"
s.email = "ss#ss.com"
print s.v
Notes:
Your class must be extending object explicitly in python 2 for this to work
#property decorated methods are working as "getters" and return a value
#<name>.setter is a setter method responsible for setting <name> member, so #email.setter sets the email and is being invoked when x.email = ... is called
The above may be a bit long-winded but allows for a clean API which hides the details from the user... Some people do prefer to add get/set_name methods to be more explicit but the above is more pythonic
If your requirements are dynamic, you can create attributes at run time like,
class Sample:
pass
s = Sample()
setattr(s,"name","chanda")
setattr(s,"email","xyz#gmail.com")
setattr(s,"v",[s.name,s.email])
print(s.name) #chanda
print(s.email) #xyz#gmail.com
print(s.v) #['chanda', 'xyz#gmail.com']
print(s.__dict__) #{'email': 'xyz#gmail.com', 'v': ['chanda', 'xyz#gmail.com'], 'name': 'chanda'}
I want to create a list child class that can convert all elements automatically in it to an object no matter the element is create by init or append or extend. So by using both for loop or getitem. Here's a simple example code. What kind of magic method should I use?
class A():
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Object A with name {}'.format(self.name)
class CustomerList(list):
def __init__(self, *args):
super(CustomerList, self).__init__(*args)
c = CustomerList('a')
c.append('b')
c[0] # Object A with name a
c[1] # Object A with name b
for ele in c:
print(c)
# Object A with name a
# Object A with name b
are you asking how to override __append__?
class A():
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Object A with name {}'.format(self.name)
class CustomerList(list):
def __init__(self, *args):
super(CustomerList, self).__init__(*args)
def append(self,letter):
super(CustomerList, self).append(A(letter))
I guess???.. but as mentioned in the comments if you want
my_custom_list.extend(["A","B","V"])
my_custom_list[2] = "A"
to work you will need to override
def __setitem__(self,key,value): # cover a[2]='A'
super(CustomerList,self).__setitem__(key,A(value))
def extend(self,other):
super(CustomerList,self).extend([A(val) for val in other])
of coarse you probably then need to override both __add__,__iadd__ at a minimum as well
I think what you're trying to do is: When you append a new item into the list, it is an object of class A. What you can do is override list.append function:
class A():
def __init__(self, name):
self.name = name
def __repr__(self):
return 'Object A with name {}'.format(self.name)
class CustomerList(list):
def __init__(self, *args):
super(CustomerList, self).__init__(*args)
def append(self, arg):
new_obj = A(arg)
self.insert(len(self), new_obj)
Given that I need to operate a machine, I need a
VendingMachine class:
Property is a stock(list) that stores Food items.
Methods:
Constructor takes in no arguments.
get_stock_names(): returns a list of strings that represents the names of
all food items in the stock.
load(food): adds the Food object to stock
and others,
#predefined
class Food(object):
def __init__(self, name, nutrition, good_until):
self.name = name
self.nutrition = nutrition
self.good_until = good_until
self.age = 0
def get_name(self):
return str(self.name)
def get_age(self):
return self.age
def get_nutrition(self):
if self.age <= self.good_until:
return self.nutrition
else:
return 0
def ripen(self, days):
self.age = self.age + days
return self.age
def is_spoiled(self):
return self.good_until < self.age
#my code below
class VendingMachine:
def __init__(self):
Property = Food.get_name #no clue how to make a Property
self.load = Food.load #same here
def get_stock_names(self, Property):
lst = []
for i in Food:
i = str(i)
lst.append(i)
return lst
def has_stock(self, name):
return name in Property
def load(self, food):
Property.append(food)
return Property
def sell(self, name):
if name in Property:
Property.remove(name)
return name
else:
return None
What I get is
AttributeError: 'VendingMachine' object has no attribute 'load' (a variable)
I'm pretty sure you've misunderstood the line of your instructions telling you about the stock property. I suspect it is just telling you to make an instance variable named self.stock which holds a list of Food instances. Since the constructor takes no arguments, it presumably starts empty. Using the term "property" seems like a red herring, since property has a specific meaning in Python (a wrapper around a method to make it look like an attribute), which doesn't make much sense in this situation.
Anyway, here's what I think you want your constructor to look like:
def VendingMachine(object):
def __init__(self):
self.stock = [] # initially empty
Your later methods can inspect or manipulate self.stock as necessary.