Infinite call to python class variable - python

So, I'm fairly new to Python, and I am trying to learn how the OOP paradigm works there.
One thing that confuses me at this stage are the class variables. To be more specific, consider the following example taken from the Python 3 Object-Oriented Programming book by Dusty Phillips (Chapter 3 - When objects are alike):
class Contact:
all_contacts = []
def __init__(self, name, email):
self.name = name
self.email = email
Contact.all_contacts.append(self)
So, here we see a simple example of a class that has the class variable all_contacts which is an empty list. Besides that there are two instance variables, name and email.
Now, if we were to create two different instances of the class Contact, e.g.
c1 = Contact('John', 'john#gmail.com')
c2 = Contact('Mark', 'mark#yahoo.com')
there are two ways how we can access properties name and email, i.e.
c1.name
c1.all_contacts[0].name
But this is where I have a problem - all_contacts is a class variable, meaning that it is common to all instances of the class Contact. Not only that it is common to all instances, but due to the way how this list is being populated, there is nothing that prevents me from doing this:
c1.all_contacts[1].name
which gives me the name property of the instance c2.
In fact, it seems that I can go deep as much as I want:
c1.all.contacts[0].all_contacts[1].all_contacts[0]...
In other words, I am worried if in Python we have a class with a class variable as a list and then in the initializer method we store self to that list, are we then creating a structure that can reference itself infinite many times? Is there some kind of workaround for this?
I would really appreciate if anyone can comment on this behavior.
Kind regards

Related

Not sure if I have to use class attribute or instance attribute

I'm a beginner in python so I already apologize for the very basic question.
I have an assignment where I have to create a list of sentences and tokens from a given text and save them as attributes in the class. Further, I have to make sure that the tokens are saved in a data structure that still represents the sentences (as in: I can still see if a token stands at the beginning of a sentence or not).
I know how to create the class and, in theory, how to tokenize the text using NLTK.
class Text:
sentences = []
sentences.append(sent_tokenize(text))
tokens = [word_tokenize(text)]
tokens.append()
def __init__(self, text):
self.raw_text = text
In the example above I used (as far as my understanding goes) class attributes. However, I'm not sure if I really have to code it like that or if I have to use instance attributes.
I'm very grateful for any help!
The point of instance attributes is so that you can have more than one instance of the class, each with its own attribute values.
To illustrate this, imagine an Employee class:
class Employee:
company = "ACME Corp"
def __init__(self, name, id_number, salary):
self.name = name
self.id_number = id_number
self.salary = salary
bob = Employee("Bob", 1, 10000)
alice = Employee("Alice", 2, 15000)
craig = Employee("Craig", 3, 18000)
This class has a company class attribute that is shared among all instances (because we assume all employees work for this company), and it also has name, id_number, and salary attributes that are specific to individual employees.
So, to answer your question, it depends on how you will use the Text class. If you plan on having multiple instances at once, each with their own separate texts, then it sounds like you need instance attributes.
But if you will only have one instance of the class, then class attributes will do the job.

Python - cannot access instances of a class

I am stuck with a problem that is probably quite simple, yet I cannot figure it out. I am trying to develop a desktop application for creating timetables. I am using Tkinter and Python 3.6. I have a Teacher class, so the user can create new instances with various attributes.
class Teacher:
"""The properties of the teachers"""
allTeachers = []
def __init__(self, name, lessons, timeframe):
self.name = name
Teacher.allTeachers.append(self.name)
self.lessons = lessons # number of lessons
self.timeframe = timeframe
Once a new instance is created I check that it exists:
for obj in gc.get_objects():
if isinstance(obj, Teacher):
print(obj.name)
However, when the user adds another teacher, the above code says that the Teacher class still has only one instance (the latest one). Moreover, when I run the same code from another module (in the same directory), Python tells me that the Teacher class has no instances. In spite of this the class variable (allTeachers) keeps track of all the teachers that have been added.
Am I missing something basic about accessing objects?
Python frees memory, if you do not hold any reference to your instances. You are only storing the Teacher's names - not the instances of it. So if you happen to just create them like this:
Teacher("Hugo", None, "8am to 2pm")
Teacher("Claas", "some", "9am to 10am")
there is no reference to the actual instance and they get garbage collected.
Additionally information can be read here: Python garbage collector documentation
If you want to look up things, lists are bad if you have more then around 4 items, they got a Lookup of O(n). Use a set or dict for O(1) instead. If you want to lookup Teacher by name, dict would be convenient:
class Teacher:
"""The properties of the teachers"""
allTeachers = {} # dict as lookup is faster then list for 4+ teachers
def __init__(self, name, lessons, timeframe):
self.name = name
Teacher.allTeachers[self.name] = self # store the instance under its name
self.lessons = lessons # number of lessons
self.timeframe = timeframe
#classmethod
def hasTeacher(cls,name):
return name in Teacher.allTeachers
Teacher("Hugo", None, "8am to 2pm")
Teacher("Claas", "some", "9am to 10am")
import gc
print(Teacher.hasTeacher("Judith"))
print(Teacher.hasTeacher("Claas"))
for obj in gc.get_objects():
if isinstance(obj, Teacher):
print(obj.name)
Output:
False # no teacher called Judith
True # a teacher called Claas
# all the Teacher instances
Hugo
Claas
If you store Teacher instances this way, you probably should provide a way to remove them by name from the class variable instance as well - and maybe return the Teacher-instance by name from it

How to call an instance of a class without knowing the name beforehand

Say I have different instances of a class;
class Person(object):
def __init__(self, id):
self.id = id
Joe = Person('123')
Sarah = Person('321')
My question now is, how would I be able use one of the instances without knowing the name before hand, for example, I could have something that requests for a name or even id. How would I associate it with the appropriate object? Say an input of an id, '123' was given, how do I get to know that it belongs to the Joe object and then use that object dynamically? I am running Python 3.6 if that info is of much use.
As you study computer programming, you will probably hear a not-really-a-joke that there are only three important numbers: 0, 1, and infinity. In other words, you can have none of something or one of something, but if you can have more than one, you have to be prepared to handle any number of them.
When you can only have zero or one of something, putting it in a variable is fine. But this solution quickly becomes unwieldy when you can have any number of something. The solution favored by programmers is to put the objects in a container, like a list or dictionary.
For example, the dictionary approach:
people = {"123": Person("123"), "321": Person("321")}
Then Joe is people["123"].
In reality you want to store the person's name in the object as well, otherwise you can't tell who it actually represents, so you'd add that to your Person class. You could also have the object add itself to the master people dict when it's instantiated:
people = {}
class Person(object):
def __init__(self, id, name):
self.id = id
self.name = name
people[id] = self
joe = Person("123", "Joe")
sarah = Person("321", "Sarah")
Now when you instantiate objects they are added to the people dict by their ID automatically, and you can access them as such. (You could also add them by name, assuming the names are unique: even to the same dictionary if IDs and names can never clash.)
N.B. "calling" has a specific meaning in programming: you call a function. You are not calling anything here.

Naming practice for objects of a class in Python

I have this weird problem as to how to name objects of a class.
For example, consider the class:
>>> class DoSomething:
pass
What should I call the object of this class? do_something or what? Since I came out of the learning stage, I used to use x, y or z or whatever came to my mind. But now since I am learning to write proper code and not the language, I always face this problem. Any suggestions?
Name it something representative of what it's actually being used for. For instance:
class Cereal:
def eat(self):
print 'yum'
breakfast = Cereal()
breakfast.eat()
or
class User:
def __init__(self, userid):
# ...
admin_user = User(ADMIN_ID)
You should name it after what it represents. For example if I have a class User in a web application and I want to refer to the currently logged-in user, I name the variable current_user.
And if you have more objects of one class, your approach fails immediately. Giving the variable an index like do_something1, do_something2 is not and will never be an option.
Use something meaningful, so that a reader of your code knows what this variable represents.
Btw. this applies to all programming languages, not just Python.
One good naming practise is to give plural names to collections such as sets and lists.

Need help with the class and instance concept in Python

I have read several documentation already but the definition of "class" and "instance" didnt get really clear for me yet.
Looks like that "class" is like a combination of functions or methods that return some result is that correct? And how about the instance? I read that you work with the class you creat trough the instance but wouldnt be easier to just work direct with the class?
Sometimes geting the concepts of the language is harder than working with it.
Your question is really rather broad as classes and instances/objects are vital parts of object-oriented programming, so this is not really Python specific. I recommend you buy some books on this as, while initially basic, it can get pretty in-depth. In essense, however:
The most popular and developed model of OOP is a class-based model, as opposed to an object-based model. In this model, objects are entities that combine state (i.e., data), behavior (i.e., procedures, or methods) and identity (unique existence among all other objects). The structure and behavior of an object are defined by a class, which is a definition, or blueprint, of all objects of a specific type. An object must be explicitly created based on a class and an object thus created is considered to be an instance of that class. An object is similar to a structure, with the addition of method pointers, member access control, and an implicit data member which locates instances of the class (i.e. actual objects of that class) in the class hierarchy (essential for runtime inheritance features).
So you would, for example, define a Dog class, and create instances of particular dogs:
>>> class Dog():
... def __init__(self, name, breed):
... self.name = name
... self.breed = breed
... def talk(self):
... print "Hi, my name is " + self.name + ", I am a " + self.breed
...
>>> skip = Dog('Skip','Bulldog')
>>> spot = Dog('Spot','Dalmatian')
>>> spot.talk()
Hi, my name is Spot, I am a Dalmatian
>>> skip.talk()
Hi, my name is Skip, I am a Bulldog
While this example is silly, you can then start seeing how you might define a Client class that sets a blueprint for what a Client is, has methods to perform actions on a particular client, then manipulate a particular instance of a client by creating an object and calling these methods in that context.
Sometimes, however, you have methods of a class that don't really make sense being accessed through an instance of the class, but more from the class itself. These are known as static methods.
I am not sure of what level of knowledge you have, so I apologize if this answer is too simplified (then just ignore it).
A class is a template for an object. Like a blueprint for a car. The instance of a class is like an actual car. So you have one blueprint, but you can have several different instances of cars. The blueprint and the car are different things.
So you make a class that describes what an instance of that class can do and what properties it should have. Then you "build" the instance and get an object that you can work with.
It's fairly simple actually. You know how in python they say "everything is an object". Well in simplistic terms you can think of any object as being an 'instance' and the instructions to create an object as the class. Or in biological terms DNA is the class and you are an instance of DNA.
class HumanDNA(): # class
... class attributes ...
you = HumanDNA() # instance
See http://homepage.mac.com/s_lott/books/python/htmlchunks/ch21.html
Object-oriented programming permits us
to organize our programs around the
interactions of objects. A class
provides the definition of the
structure and behavior of the objects;
each object is an instance of a class.
Objects ("instances") are things which interact, do work, persist in the file system, etc.
Classes are the definitions for the object's behavior.
Also, a class creates new objects that are members of that class (share common structure and behavior)
In part it is confusing due to the dynamically typed nature of Python, which allows you to operate on a class and an instance in essentially the same way. In other languages, the difference is more concrete in that a class provides a template by which to create an object (instance) and cannot be as directly manipulated as in Python. The benefit of operating on the instance rather than the class is that the class can provide a prototype upon which instances are created.

Categories