Objects & Classes
So far, every value we have written used a built-in type: int, float, str, bool, list, or dict. The class keyword defines a new type for the data we are modeling. Programming organized around classes is called object-oriented programming, or OOP (pronounced “oh oh pee”).
The final Twitter clone needs to store each tweet’s username, text, and like count, along with operations such as liking it.
A dictionary can bundle the data:
tweet = {'username': 'rtealwitter', 'text': 'my first tweet', 'likes': 0}The dictionary holds the three values, but Python sees only a dict, and a separate like(tweet) function has no defined relationship to it:
>>> type(tweet)
<class 'dict'>A class groups the data and operations under one name and defines a distinct type.
A first class
The simplest possible one is empty:
class Tweet:
passclass introduces a new type named Tweet, and pass is a do-nothing placeholder for the body. By convention a class name is capitalized, which is why it is Tweet and not tweet. This definition is enough to create objects of the new type:
>>> tweet = Tweet()
>>> type(tweet)
<class '__main__.Tweet'>Tweet() builds a new object, and type confirms its type. An object is what a variable refers to, so the variable tweet refers to one. An instance is an object whose type is a particular class, so tweet is an instance of Tweet. “Object” and “instance” refer to the same value, with “instance” naming its relationship to a class.
This first Tweet has no attributes yet.
The constructor
Every tweet should begin with a username, text, and zero likes. The constructor, a special method named __init__, sets those attributes when Python creates an instance:
class Tweet:
def __init__(self, username, text):
self.username = username
self.text = text
self.likes = 0__init__ is defined like any function, with def, but the double underscores front and back mark it as special. Its first parameter, self, is the instance being built. Python supplies it automatically to every method. The body stores the supplied username and text on the instance and initializes its likes to zero.
The variables stored on the object, username, text, and likes, are called attributes (some languages call them properties). Create a tweet by calling Tweet with its data, then access each attribute with a dot:
>>> tweet = Tweet('rtealwitter', 'my first tweet')
>>> tweet.username
'rtealwitter'
>>> tweet.likes
0The call passes two arguments, 'rtealwitter' and 'my first tweet', although __init__ lists three parameters. Python fills self with the new object automatically, and the explicit arguments correspond to the parameters after it.
Methods
Attributes store data; methods define related operations. A method is a function defined inside the class, and like __init__ its first parameter is self, the instance it acts on. Define a like method:
class Tweet:
def __init__(self, username, text):
self.username = username
self.text = text
self.likes = 0
def like(self):
self.likes = self.likes + 1like takes only self and adds one to that instance’s like count. Calling it twice changes likes to 2:
>>> tweet = Tweet('rtealwitter', 'my first tweet')
>>> tweet.like()
>>> tweet.like()
>>> tweet.likes
2When you write tweet.like(), Python passes tweet in as self, so self.likes refers to this tweet’s counter. tweet.like() returns None because it changes self.likes instead of returning a value, so the REPL prints nothing after each call.
Dunder methods
Methods with double underscores at the front and back are called dunder methods (short for “double underscore”) or magic methods. Python calls them for built-in operations rather than requiring you to call them by name. You never write tweet.__init__(...) yourself; Python calls __init__ when you write Tweet(...). Other dunder methods customize Python’s built-in behavior: __str__ controls what print shows, and __eq__ controls what == means.
Duck typing
Python often uses an object’s available operations instead of checking its declared type. Consider a function that shows a post:
def show(post):
print(post.text)show does not require a Tweet; it runs on any object with a .text attribute and fails on an object without one. This is called duck typing: if an object walks like a duck and quacks like a duck, Python treats it as a duck.
Private attributes
Many languages make some attributes private, allowing only the class’s methods to access them. Python instead uses a naming convention. Prefix an internal attribute with one underscore, as in self._likes, to tell other programmers not to access it directly. The underscore does not enforce this restriction.
The meme turns disagreements about private attributes into a class-structure joke:
When to use a class
Use a class when data and behavior belong together, as they do for Tweet, and use a plain function otherwise.
Edsger Dijkstra wrote the quote shown above. Automate the Boring Stuff, the book this course uses, does not need a chapter on classes. You can automate many tasks without defining a class yourself. You mainly need to recognize classes in libraries and other people’s code. Real Python’s object-oriented programming guide provides a more detailed introduction.
Naming conventions
Python’s official style guide, PEP 8 (a “Python Enhancement Proposal”), defines naming conventions. Class names use CamelCase: capitalize each word and run them together, like Tweet or HttpResponse. Everything else, meaning variables, functions, methods, and attributes, uses snake_case: lowercase words joined by underscores, like username, like, and input_name. Python code does not conventionally use lowerCamelCase (capitalized words but a lowercase first letter, like inputName), although other languages do.
Classes in the final project
The final Twitter clone uses User and Tweet classes similar to the example above. Each class defines its instances’ data in __init__ and provides methods that operate on that data.
The Pull Request tutorial covers git collaboration through branches, merges, and pull requests.