Iterate through instantiated objects of a class - python

Isit possible to loop through the objects of class person and extract the attributes?
so for e.g. from below code after looping the output would be for each object as such
Object mike, name-Mike, age-20
class Person(object):
def__init__(self,name,age):
self.name = name
self.age = age
mike = Person('Mike',20)
john = Person('John',20)
jack = Person('Jack',20)
adam = Person('Adam',20)
Thanks

Python classes don't automatically track all their instances. You can use a class attribute to track them yourself if you need to:
class Person(object):
people = []
def __init__(self, name, age):
self.name = name
self.age = age
self.people.append(self)
Even better would be to have a separate object that tracked people. The Person.people attribute here is a single global value for the process, which can limit the usability and testability of the class.

To loop the attributes of a given instance, I think you're looking for the builtin function vars:
>>> mike = Person('Mike', 20)
>>> vars(mike)
{'age': 20, 'name': 'Mike'}
To loop through all instances of a given class is not possible, unless you add some code to maintain the list of instances yourself.

if my understanding is right, you are asking about looping the class person
then it can be done like this.
class person(object):
def __init__(self,name,age):
self.name=name
self.age=age
for name,age in {'mike':20,'john':20,'jack':20}.iteritems():
p = person(name,age)
print ('I am %s my age is %d' %(p.name,p.age))
## answer
I am mike my age is 20
I am john my age is 20
I am jack my age is 20

Related

Outputting Specific Prosperities of an Array(List) of Objects in Python

I have an class Student which has an array(list) of Objects called Students. I am trying to output the names of all the students in the array.
class Student(object):
name = ""
age = 0
major = ""
# The class "constructor" - It's actually an initializer
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
Students = []
Students.append(Student("Dave",23,"Chem"))
Students.append(Student("Emma",34,"Maths"))
Students.append(Student("Alex",19,"Art"))
print(Students[0].__dict__)
print(Students[1].__dict__)
print (Students[0])
Both the ways I have found and tired do not output the specific name but the location or the whole object. Is there a way to just output the name? For example output Students[0] name Dave
{'name': 'Emma', 'age': 34, 'major': 'Maths'}
<__main__.Student object at 0x000001FCDE4C2FD0>```
If you just want the name, you can print(Students[0].name). If you want to see the relevant attributes when printing a Student object, you can implement the __repr__ method.
class Student:
# The class "constructor" - It's actually an initializer
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def __repr__(self):
return f"<Student name={self.name} age={self.age} major={self.major}>"
This way you can simply do print(Students[0]) to see the name, age and major of a student.
By the way, for a normal class definition, you want to initialize instance attributes inside the __init__ method, instead of declaring them above __init__: those are class attributes. Please read this section of the documentation to familiarize yourself with the syntax.

Make a class iterable over its instances using a decorator

I came across code which makes the class Person allow iteration here and here. It worked great for a single class, but I tried to modify it to allow iteration of multiple classes (separately) by changing _ClassRegistry to a dict, which would store
{class_str_name_1: [instance_obj_1, instance_obj_2, ...], ...}
instead of a list. My code is:
class ClassIter(type):
def __iter__(cls):
# iterate over the list in the dict value
return iter(cls._ClassRegistry[cls.__name__])
def __len__(cls):
return len(cls._ClassRegistry[cls.__name__])
class Person(metaclass=ClassIter):
_ClassRegistry = {}
def __init__(self, name, age):
if type(name).__name__ in self._ClassRegistry.keys():
self._ClassRegistry[type(self).__name__].append(self)
else:
self._ClassRegistry[type(self).__name__] = [self]
self.name, self.age = name, age
class Dog(metaclass=ClassIter):
_ClassRegistry = {}
def __init__(self, name, age, owned_by):
if type(name).__name__ in self._ClassRegistry.keys():
self._ClassRegistry[type(self).__name__].append(self)
else:
self._ClassRegistry[type(self).__name__] = [self]
self.name, self.age = name, age
self.owned_by = type(owned_by).__name__
Alice = Person("Alice", 20)
Bob = Person("Bob", 25)
Spud = Dog("Spud", 6, Alice)
Buster = Dog("Buster", 12, Bob)
for p in Person:
print(p.name, p.age)
for d in Dog:
print(d.name, d.age, d.owned_by)
Unfortunately this did not work, and the output is
Bob 25
Buster 12 Person
while I was hoping it would produce
Alice 20
Bob 25
Spud 6 Alice
Buster 12 Bob
so not only is it using the class name Person instead of the name attribute (which is probably an easy fix but I've lost myself in the code) but also not storing the previous instances.
How can I either:
(1) convert this program to a class decorator (such as #iterator; class Person:) to make it easier to implement this for multiple classes? or
(2) fix the program to work as expected using the current implementation?
Any help much appreciated, I am unexperienced in OOP.

How do I create variable defined for each object?

So I've been creating Person classes, which hold variables like name and age. I would then create multiple Person classes which have different variables unique to each class. What I want to add next is to give each Person a "relationship" variable shared between each of these classes.
For example:
The relationship between George and Alex is -31.
How would I approach this? I've thought about just making a variable for each object, but this doesn't seem convenient when there's just too much Person classes in the program.
First, I'm not sure you want to make each person a different class. The idea behind classes is that a class describes a type of object (like a Person), and then each Person is an instance of that type of object (like George).
So if your Person class is like:
class Person:
def __init__(name: str, age: int):
self.name = name
self.age = age
then you might have:
george = Person("George", 20)
alex = Person("Alex", 22)
Both george and alex are instances of Person, not their own class. This make sense so far?
Now, the way you'd add a relationship might be to have a dictionary that associates other Persons with this relationship score. While we're at it, let's add a __repr__ function to our class so we can pretty-print our people:
class Person:
def __init__(name: str, age: int):
self.name = name
self.age = age
self.relationships: Dict["Person", int] = {}
def __repr__(self) -> str:
return "%s, age %d" % (self.name, self.age)
Now you can do:
george.relationships[alex] = -31
alex.relationships[george] = -31
If we print out George's relationships, we get:
>>> print(george.relationships)
{Alex, age 22: -31}
And you can do this regardless of how many people and how many relationships between them you want to model (a dictionary can hold an arbitrary number of values associated with an arbitrary number of keys, which in this case is a Person instance).
Assuming that a person can have a "relationship" with more than one other person, you will need a dictionary to store all of the relationships that a person has. I suggest mapping the other person's name to the "relationship" number (-31 in your example).
class Person:
def __init__(self, name):
self.name
self.relationships = dict()
def set_relationship(self, other, value):
self.relationships[other.name] = value
other.relationships[self.name] = value
def get_relationship(self, other):
return self.relationships[other.name]
def has_relationship(self, other):
return other.name in self.relationships
The set_relationships method updates both objects' dictionaries, because the way you've described the relationship, it should be symmetric.
Usage:
>>> alice = Person('alice')
>>> bob = Person('bob')
>>> clive = Person('clive')
>>> alice.set_relationship(bob, 12)
>>> alice.relationships
{'bob': 12}
>>> bob.get_relationship(alice)
12
>>> clive.has_relationship(alice)
False
If you genuinely need each person to be represented by a different class (instead of just objects of the same class), you can write your other classes as subclasses of Person. That way you won't have to duplicate the code above across many different classes.

Python OOP Exercise

I'm trying to learn using classes in Python, and have written this test program.
It is to some extent based on code I found in another question I found here on
Stack OverFlow.
The code looks as follows:
class Student(object):
name = ""
age = 0
major = ""
# The class "constructor" - It's actually an initializer
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def list_values():
print "Name: ", self.name
print "Age: ", self.age
print "Major: ", self.major
def make_student(name, age, major):
student = Student(name, age, major)
return student
print "A list of students."
Steve = make_student("Steven Schultz",23,"English")
Johnny = make_student("Jonathan Rosenberg",24,"Biology")
Penny = make_student("Penelope Meramveliotakis",21,"Physics")
Steve.list_values()
Johnny.list_values()
Penny.list_values()
When I run this, get the error "TypeError: list_values() takes no arguments (1 given)".
In my oppinion I have not given any arguments, but I remove the parenthesis, giving the
code
Steve.list_values
Johnny.list_values
Penny.list_values
This renders no errors, but does not do anything - nothing gets printed.
My questions:
What's the deal with the parenthesis?
What's the deal with the print statements?
The list_values method needs to be bound to your Student instance:
You should change:
def list_values()
to:
def list_values(self)
For an explanation of why, see:
Why do you need explicitly have the "self" argument into a Python method?
What is the purpose of self?
Also this blog post by Guido covers the subject too:
http://neopythonic.blogspot.com.au/2008/10/why-explicit-self-has-to-stay.html
Python requires you explicitly add the self arguments to member functions, you forgot to add self to your function decleration:
def list_values(self):
This defines it as a member function of the Student class. see here. When you call the functions as members of the Student instances, the self variable is added implicitly, thus triggering the exception, since you did not define a function named list_values that receives one parameter.
As for removing the parenthesis, this means you are not calling the functions but only referring to the function objects, doing nothing.
def list_values(): should be: def list_values(self):
In Python, instance methods take self as the first argument.
As others have mentioned, you should use self in list_values.
But you should really define one of the magic method __str__ or __repr__ instead. Additionally, you're setting some class properties that aren't necessary.
A simpler implementation would be:
class Student(object):
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def __str__(self):
fs = "<name: {}, age: {}, major: {}>"
return fs.format(self.name, self.age, self.major)
Use it like this:
In [9]: Steve = Student("Steven Schultz", 23, "English")
In [10]: Johnny = Student("Jonathan Rosenberg", 24, "Biology")
In [11]: Penny = Student("Penelope Meramveliotakis", 21, "Physics")
In [12]: print Steve
<name: Steven Schultz, age: 23, major: English>
In [13]: print Johnny
<name: Jonathan Rosenberg, age: 24, major: Biology>
In [14]: print Penny
<name: Penelope Meramveliotakis, age: 21, major: Physics>
Since you're not defining special methods, you might as well use a named tuple:
In [16]: from collections import namedtuple
In [17]: Student = namedtuple('Student', ['name', 'age', 'major'])
In [18]: Steve = Student("Steven Schultz", 23, "English")
In [19]: print Steve
Student(name='Steven Schultz', age=23, major='English')

Python, creating objects

I'm trying to learn python and I now I am trying to get the hang of classes and how to manipulate them with instances.
I can't seem to understand this practice problem:
Create and return a student object whose name, age, and major are
the same as those given as input
def make_student(name, age, major)
I just don't get what it means by object, do they mean I should create an array inside the function that holds these values? or create a class and let this function be inside it, and assign instances? (before this question i was asked to set up a student class with name, age, and major inside)
class Student:
name = "Unknown name"
age = 0
major = "Unknown major"
class Student(object):
name = ""
age = 0
major = ""
# The class "constructor" - It's actually an initializer
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def make_student(name, age, major):
student = Student(name, age, major)
return student
Note that even though one of the principles in Python's philosophy is "there should be one—and preferably only one—obvious way to do it", there are still multiple ways to do this. You can also use the two following snippets of code to take advantage of Python's dynamic capabilities:
class Student(object):
name = ""
age = 0
major = ""
def make_student(name, age, major):
student = Student()
student.name = name
student.age = age
student.major = major
# Note: I didn't need to create a variable in the class definition before doing this.
student.gpa = float(4.0)
return student
I prefer the former, but there are instances where the latter can be useful – one being when working with document databases like MongoDB.
Create a class and give it an __init__ method:
class Student:
def __init__(self, name, age, major):
self.name = name
self.age = age
self.major = major
def is_old(self):
return self.age > 100
Now, you can initialize an instance of the Student class:
>>> s = Student('John', 88, None)
>>> s.name
'John'
>>> s.age
88
Although I'm not sure why you need a make_student student function if it does the same thing as Student.__init__.
Objects are instances of classes. Classes are just the blueprints for objects. So given your class definition -
# Note the added (object) - this is the preferred way of creating new classes
class Student(object):
name = "Unknown name"
age = 0
major = "Unknown major"
You can create a make_student function by explicitly assigning the attributes to a new instance of Student -
def make_student(name, age, major):
student = Student()
student.name = name
student.age = age
student.major = major
return student
But it probably makes more sense to do this in a constructor (__init__) -
class Student(object):
def __init__(self, name="Unknown name", age=0, major="Unknown major"):
self.name = name
self.age = age
self.major = major
The constructor is called when you use Student(). It will take the arguments defined in the __init__ method. The constructor signature would now essentially be Student(name, age, major).
If you use that, then a make_student function is trivial (and superfluous) -
def make_student(name, age, major):
return Student(name, age, major)
For fun, here is an example of how to create a make_student function without defining a class. Please do not try this at home.
def make_student(name, age, major):
return type('Student', (object,),
{'name': name, 'age': age, 'major': major})()
when you create an object using predefine class, at first you want to create a variable for storing that object. Then you can create object and store variable that you created.
class Student:
def __init__(self):
# creating an object....
student1=Student()
Actually this init method is the constructor of class.you can initialize that method using some attributes.. In that point , when you creating an object , you will have to pass some values for particular attributes..
class Student:
def __init__(self,name,age):
self.name=value
self.age=value
# creating an object.......
student2=Student("smith",25)

Categories