Programmering är en konst. Och precis som inom konst är det viktigt att välja rätt penslar och färger för att producera de bästa arbetena. Pythons objektorienterade programmering är en sådan färdighet.

Att välja rätt programmeringsspråk är en viktig del av ett projekt, och det kan antingen leda till en smidig och trevlig utveckling eller en fullständig mardröm. Därför skulle det vara bäst om du använde det bäst anpassade språket för just dina behov.

Det är den främsta anledningen till att lära sig objektorienterad programmering i Python, som också är ett av de mest populära programmeringsspråken.

Vi tar och lär oss tillsammans!

Ett exempel på ett Python-program

Innan vi går in på huvudämnet, låt oss ställa en fråga: har du någonsin skrivit ett Python-program som det nedan?

secret_number = 20
 
while True:
   number = input('Guess the number: ')
 
   try:
       number = int(number)
   except:
       print('Sorry that is not a number')
       continue
 
   if number != secret_number:
       if number > secret_number:
           print(number, 'is greater than the secret number')
 
       elif number < secret_number:
           print(number, 'is less than the secret number')
   else:
       print('You guessed the number:', secret_number)
       break

Denna kod är en enkel siffergissare. Försök att kopiera in den i en Python-fil och kör den i ditt system. Den gör vad den ska.

Men här kommer ett stort problem: tänk om vi bad dig att lägga till en ny funktion? Det kan vara något enkelt – till exempel:

”Om inmatningen är en multipel av det hemliga numret, ge användaren en ledtråd.”

Programmet skulle snabbt bli komplext och tungt om du ökar antalet funktioner och därmed det totala antalet inkapslade villkor.

Det är just det problemet som objektorienterad programmering försöker lösa.

Programmering är en konst som kräver rätt verktyg för att skapa något vackert 🎨 Läs mer om Pythons objektorienterade programmering här👇Click to Tweet

Krav för att lära sig Python OOP

Innan vi går in på objektorienterad programmering rekommenderar vi starkt att du har ett fast grepp om Pythons grunder.

Att kalla något ”grunder” kan vara svårt. Därför har vi utformat en lathund med alla de viktigaste begreppen som behövs för att lära sig objektorienterad programmering i Python.

Nu när dessa begrepp är klart som spad kan du gå vidare till att förstå dig på objektorienterad programmering.

Vad är objektorienterad programmering i Python?

Objektorienterad programmering (OOP) är ett programmeringsparadigm där vi kan tänka på komplexa problem som objekt.

Ett paradigm är en teori som levererar basen för att lösa problem.

Så när vi pratar om OOP hänvisar vi till en uppsättning begrepp och mönster som vi använder för att lösa problem med objekt.

Ett objekt i Python är en enskild samling data (attribut) och beteenden (metoder). Se objekt som faktiska saker omkring dig. Tänk till exempel en miniräknare:

En miniräknare kan vara ett objekt.
En miniräknare kan vara ett objekt.

Som du kanske märker är data (attributen) alltid substantiv, medan beteenden (metod) alltid är verb.

Denna uppdelning är det centrala konceptet inom objektorienterad programmering. Du bygger objekt som lagrar data och innehåller specifika typer av funktioner.

Varför använder vi objektorienterad programmering i Python?

OOP låter dig skapa säker och pålitlig programvara. Många Python-ramverk och bibliotek använder detta paradigm för att bygga sin kodbas. Några exempel är Django, Kivy, pandas, NumPy och TensorFlow.

Låt oss ta en titt på de viktigaste fördelarna med OOP i Python.

Fördelar med Python OOP

Följande anledningar kommer säkert få dig att välja objektorienterad programmering i Python.

Alla moderna programmeringsspråk använder OOP

Detta paradigm är språkoberoende. Om du lär dig OOP i Python kommer du att kunna använda det i följande:

Alla dessa språk är antingen objektorienterade eller inkluderar alternativ för objektorienterad funktionalitet. Om du vill lära dig något av dem efter Python blir det lättare – du kommer se många likheter mellan språk som arbetar med objekt.

OOP låter dig koda snabbare

Att koda snabbare betyder inte att du kommer skriva färre rader kod. Det innebär att du kan implementera fler funktioner på kortare tid utan att äventyra stabiliteten i ett projekt.

Objektorienterad programmering låter dig återanvända kod genom att implementera abstraktion. Denna princip gör din kod mer koncis och läsbar.

Som du kanske vet spenderar programmerare mycket mer tid på att läsa kod än att skriva den. Det är anledningen till att läsbarhet alltid är viktigare än att få ut funktioner så snabbt som möjligt.

Produktiviteten minskar med kod som inte är lika läsbar
Produktiviteten minskar med kod som inte är lika läsbar

Du får se mer om abstraktionsprincipen senare.

OOP hjälper dig att undvika spaghettikod

Minns du siffergissningsprogrammet i början av den här artikeln?

Om du fortsätter att lägga till funktioner, får du många inkapslade if-uttryck till slut. Denna härva av oändliga kodrader kallas spaghettikod, och du bör undvika det så mycket som möjligt.

OOP ger oss möjlighet att komprimera all logik i objekt, och därför undvika långa bitar av inkapslade if-satser.

OOP förbättrar din analys av situationen

När du fått lite erfarenhet med OOP kommer du att kunna tänka på problem som små och specifika objekt.

Denna förståelse leder till en snabb projektinitiering.

Strukturerad programmering vs objektorienterad programmering

Strukturerad programmering är det mest använda paradigmet för nybörjare eftersom det är det enklaste sättet att bygga ett litet program.

Det innebär att köra ett Python-program sekventiellt. Det betyder att du ger datorn en lista över uppgifter och sedan kör dem ovanifrån och ned.

Låt oss se ett exempel på strukturerad programmering med ett kaféprogram.

small = 2
regular = 5
big = 6
 
user_budget = input('What is your budget? ')
 
try:
   user_budget = int(user_budget)
except:
   print('Please enter a number')
   exit()
 
if user_budget > 0:
   if user_budget >= big:
       print('You can afford the big coffee')
       if user_budget == big:
           print('It\'s complete')
       else:
           print('Your change is', user_budget - big)
   elif user_budget == regular:
       print('You can afford the regular coffee')
       print('It\'s complete')
   elif user_budget >= small:
       print('You can buy the small coffee')
       if user_budget == small:
           print('It\'s complete')
       else:
           print('Your change is', user_budget - small)

Koden ovan fungerar som en kaféleverantör. Den kommer att be dig om en budget, sedan ”sälja” den största kaffekoppen du kan köpa.

Försök att köra koden i terminalen. Den kommer att exekveras steg för steg, beroende på din inmatning.

Denna kod fungerar perfekt, men vi har tre problem:

  1. Den har mycket upprepad logik.
  2. Den använder många kapslade if-villkor.
  3. Den blir svår att läsa och modifiera.

OOP uppfanns som en lösning på alla dessa problem.

Låt oss se ovanstående program med OOP. Oroa dig inte om du inte förstår det här än. Det är bara till för att jämföra strukturerad programmering och objektorienterad programmering.

class Coffee:
        # Constructor
        def __init__(self, name, price):
                self.name = name
                self.price = float(price)
        def check_budget(self, budget):
                # Check if the budget is valid
                if not isinstance(budget, (int, float)):
                        print('Enter float or int')
                        exit()
                if budget < 0: 
                    print('Sorry you don\'t have money') 
                    exit() 
        def get_change(self, budget):
                return budget - self.price
        
        def sell(self, budget):
                self.check_budget(budget)
                if budget >= self.price:
                        print(f'You can buy the {self.name} coffee')
                        if budget == self.price:
                                print('It\'s complete')
                        else:
                                print(f'Here is your change {self.get_change(budget)}$')

                        exit('Thanks for your transaction')

Observera: Alla följande begrepp kommer att förklaras mer under artikelns gång.

Ovanstående kod representerar en class som heter ”Coffee”. Den har två attribut – ”name” och ”price” – och de används båda i metoderna. Den primära metoden är ”sell”, som behandlar all logik som behövs för att slutföra försäljningsprocessen.

Om du försöker köra den klassen får du ingen utmatning. Det sker främst eftersom vi bara förklarad ”template” [mallen] för kaffet, inte själva kaffet.

Låt oss implementera den klassen med följande kod:

small = Coffee('Small', 2)
regular = Coffee('Regular', 5)
big = Coffee('Big', 6)
 
try:
   user_budget = float(input('What is your budget? '))
except ValueError:
   exit('Please enter a number')
  
for coffee in [big, regular, small]:
   coffee.sell(user_budget)

Här gör vi instances, eller kaffeobjekt, av klassen ”coffee”, och anropar sedan ”sell”-metoden för varje kaffe tills användaren har råd med ett alternativ.

Vi får samma utmatning med båda tillvägagångssätten men vi kan utöka programfunktionen mycket bättre med OOP.

Nedan följer en tabell som jämför objektorienterad programmering och strukturerad programmering:

OOP Strukturerad programmering
Lättare att underhålla Svår att underhålla
Upprepa inte dig själv (DRY)-metoden. Upprepad kod på många ställen
Små bitar kod återanvänds på många ställen En stor mängd kod på några ställen
Objektmetod Blockkodsmetod
Lättare att felsöka Svårare att felsöka
Stor inlärningskurva Enklare inlärningskurva
Används i stora projekt Optimerad för enkla program

 

För att avsluta jämförelsen:

Låt oss gå vidare till inbyggda objekt i Python.

Allt är ett objekt i Python

Vi ska berätta en hemlighet: du har använt OOP hela tiden utan att märka det.

Till och med när du använder andra paradigmer i Python använder du fortfarande objekt för att göra nästan allt.

Det beror på att i Python är allt ett objekt.

Kom ihåg definitionen av objekt: ett objekt i Python är en enskild samling data (attribut) och beteenden (metoder).

Det matchar alla datatyper i Python.

En sträng är en samling data (tecken) och beteenden (upper(), lower(), osv..). Detsamma gäller för heltal, flyttal, booleska uttryck, listor, och ordböcker.

Innan vi fortsätter, låt oss granska betydelsen av attribut och metoder.

Attribut och metoder

Attribut är interna variabler inuti objekt, medan metoder är funktioner som skapar ett visst beteende.

Låt oss göra en enkel övning i Pythonskalet. Du kan öppna det genom att skrivapython eller python3 i din terminal.

Pythonskal
Pythonskal

Låt oss nu arbeta med Pythonskalet för att upptäcka metoder och typer.

>>> kinsta = 'Kinsta, Premium WordPress hosting'
>>> kinsta.upper()
'KINSTA, PREMIUM WORDPRESS HOSTING'

I den andra raden anropar vi en strängmetod, upper(). Det returnerar innehållet i strängen helt i versaler. Det ändrar dock inte den ursprungliga variabeln.

>>> kinsta
'Kinsta, Premium WordPress hosting'

Låt oss gå in mer på värdefulla funktioner när vi arbetar med objekt.

type()-funktionen ger dig ett objekts typ. ”Typen” är den klass som objektet tillhör.

>>> type(kinsta)
# class 'str'

dir()-funktionen returnerar alla attribut och metoder för ett objekt. Låt oss testa det med kinsta-variabeln.

>>> dir(kinsta)
['__add__', '__class__',  ........... 'upper', 'zfill']

Försök nu mata ut några av de dolda attributen för det här objektet.

 >>> kinsta.__class__ # class ‘str’ e>

Detta kommer att mata ut klassen som objektet kinsta tillhör. Så vi kan säga att det enda type-funktionen returnerar är __class__ -attributet för ett objekt.

Du kan experimentera med alla datatyper, upptäcka alla deras attribut och metoder direkt på terminalen. Du kan läsa mer om de inbyggda datatyperna i den officiella dokumentationen.

Ditt första objekt i Python

En klass är som en mall. Den låter dig skapa egna objekt baserat på de attribut och metoder du definierar.

Du kan se det som ett kakmått som du ändrar för att baka de perfekta kakorna (objekt, inte spårningscookies), med definierade egenskaper: form, storlek och mer.

Å andra sidan har vi instanser. En instans är ett enskilt objekt i en klass, som har en unik minnesadress.

Instanser i Python
Instanser i Python

Nu när du vet vad klasser och instanser är för något, låt oss definiera några!

För att definiera en klass i Python använder du class följt av dess namn. I det här fallet skapar du en klass som heter Cookie.

Observera: I Python använder vi camel case-namnkonventionen för att namnge klasser.

class Cookie:
	pass

Öppna ditt Python-skal och skriv koden ovan. För att skapa en instans av en klass, skriv bara dess namn och parentes efter det. Det är samma process som att åberopa en funktion.

cookie1 = Cookie()

Grattis – du har just skapat ditt första objekt i Python! Du kan kontrollera dess id och typ med följande kod:

id(cookie1)
140130610977040 # Unique identifier of the object

type(cookie1)
<class '__main__.Cookie'>

Som du kan se har denna cookie en unik identifierare i minnet, och dess typ är Cookie.

Du kan också kontrollera om ett objekt är en instans av en klass med isinstance()-funktionen.

isinstance(cookie1, Cookie)
# True
isinstance(cookie1, int)
# False
isinstance('a string', Cookie)
# False

Constructor Method

__ init__()-metoden kallas också för konstruktören. Den kallas Python varje gång vi instansierar ett objekt.

Konstruktören skapar objektets ursprungliga tillstånd med minsta uppsättning parametrar den behöver existera. Låt oss ändra Cookie-klassen så den accepterar parametrar i sin konstruktör.

class Cookie:
	# Constructor
	def __init__(self, name, shape, chips='Chocolate'):
		# Instance attributes
		self.name = name
		self.shape = shape
		self.chips = chips

I Cookie-klassen måste varje kaka ha ett namn, form och chips. Vi har definierat den sista som ”choklad.”

Self avser klassens instans (själva objektet).

Försök att klistra in klassen i skalet och skapa en instans av kakan som vanligt.

cookie2 = Cookie()
# TypeError

Du får ett fel. Det beror på att du måste tillhandahålla den minsta uppsättningen data som objektet behöver för att överleva – i det här fallet, name och form eftersom vi redan har satt chips till ”choklad”.

cookie2 = Cookie('Awesome cookie', 'Star')

För att komma åt attributen för en instans måste du använda punktnotationen.

cookie2.name
# 'Awesome cookie'
cookie2.shape
# 'Star'
cookie2.chips
# 'Chocolate'

För tillfället har Cookie-klassen inget alltför saftigt. Låt oss lägga till en provmetod, bake(), för att göra saker och ting mer intressanta.

class Cookie:
	# Constructor
	def __init__(self, name, shape, chips='Chocolate'):
		# Instance attributes
		self.name = name
		self.shape = shape
		self.chips = chips

	# The object is passing itself as a parameter
	def bake(self):
		print(f'This {self.name}, is being baked with the shape {self.shape} and chips of {self.chips}')
		print('Enjoy your cookie!')

För att anropa en metod, använd punktnotationen och åberopa den som en funktion.

cookie3 = Cookie('Baked cookie', 'Tree')
cookie3.bake()
# This Baked cookie, is being baked with the shape Tree and chips of Chocolate
Enjoy your cookie!

De 4 pelarna av OOP i Python

Objektorienterad programmering innehåller fyra huvudpelare:

1. Abstraktion

Abstraktion döljer den interna funktionaliteten hos ett program från användaren. Användaren kan vara antingen slutklienten eller andra utvecklare.

Behöver du en hosting-lösning som ger dig en konkurrensfördel? Kinsta hjälper dig med otrolig hastighet, toppmodern säkerhet och automatisk skalning. Kolla in våra planer

Vi kan hitta abstraktion i vårt dagliga liv. Du vet till exempel hur du använder telefonen, men du vet förmodligen inte exakt vad som händer i den varje gång du öppnar en app.

Ett annat exempel är Python själv. Du vet hur du använder det för att bygga funktionell programvara, och du kan göra det även om du inte förstår hur Python fungerar.

Med samma kod kan du samla alla objekt i ett problem och abstrahera standardfunktionalitet i olika klasser.

2. Arv

Arv låter oss att definiera flera underklasser från en redan definierad klass.

Det primära syftet med det är att följa DRY-principen. Du kommer att kunna återanvända mycket kod genom att implementera alla delningskomponenter i superklasser.

Du kan tänka på det som det verkliga begreppet genetiskt arv. Barn (underklass) är resultatet av arv mellan två föräldrar (superklasser). De ärver alla fysiska egenskaper (attribut) och några vanliga beteenden (metoder).

3. Polymorfism

Polymorfism låter oss ändra metoder och attribut något för underklasser som tidigare definierats i superklassen.

Den bokstavliga betydelsen är ”flera former.” Det beror på att vi bygger metoder med samma namn men olika funktioner.

Vi tar ett steg tillbaka till föregående idé, där barn också är ett perfekt exempel på polymorfism. De kan ärva ett definierat beteende get_hungry() men på ett något annorlunda sätt, till exempel, blir hungrig var 4:e timme i stället för var 6:e.

4. Inkapsling

Inkapsling är processen där vi skyddar den interna integriteten hos data i en klass.

Även om det inte finns ett privat uttryck i Python kan du använda inkapsling genom att använda mangling i Python. Det finns speciella metoder som heter getters och setters som låter oss komma åt unika attribut och metoder.

Låt oss föreställa oss en människa-klass som har ett unikt attribut som heter _längd. Du kan ändra detta attribut endast inom vissa begränsningar (det är nästan omöjligt att vara längre än 3 meter).

Bygg en areaberäkningskalkylator

En av de bästa sakerna med Python är att det låter oss skapa ett brett utbud av programvara, från ett CLI-program (kommandoradsgränssnitt) till en komplex webbapp.

Nu när du har lärt dig pelarbegreppen i OOP är det dags att tillämpa dem på ett verkligt projekt.

Observera: All följande kod kommer att finnas tillgänglig i detta GitHub-förråd. Ett kodrevisionsverktyg som hjälper oss att hantera kodversioner med Git.

Din uppgift är att skapa en areakalkylator för följande former:

Formbasklass

Först och främst, skapa en fil calculator.py och öppna den. Eftersom vi redan har objekten att arbeta med blir det lätt att abstrahera dem i en klass.

Du kan analysera de vanliga egenskaperna och märka att alla dessa är 2D-former. Därför är det bästa alternativet att skapa en klass för Shape med en metod get_area() från vilken varje form kommer att ärva.

Observera: Alla metoder borde vara verb. Det beror på att den här metoden heter get_area() och inte area().

class Shape:
	def __init__(self):
		pass

	def get_area(self):
		pass

Koden ovan definierar klassen; det finns dock inget intressant i den ännu.

Låt oss implementera standardfunktionen hos de flesta av dessa former.

class Shape:
	def __init__(self, side1, side2):
		self.side1 = side1
		self.side2 = side2

	def get_area(self):
		return self.side1 * self.side2

	def __str__(self):
		return f'The area of this {self.__class__.__name__} is: {self.get_area()}'

Låt oss gå igenom vad vi gör med den här koden:

Rectangle-klass

Eftersom vi genomfört formeln för arean av rektangeln kan vi skapa en enkel Rectangle-klass som bara ärver från Shape-klassen.

För att tillämpa inheritence i Python skapar du en klass som vanligt och omger den superclass du vill ärva från med parenteser.

# Folded base class
class Shape: ...
 
class Rectangle(Shape): # Superclass in Parenthesis
	pass

Square-klass

Vi kan ta en utmärkt approach till polymorfism med Square-klassen.

Kom ihåg att en kvadrat bara är en rektangel vars fyra sidor alla är lika långa. Det betyder att vi kan använda samma formel för att beräkna arean.

Vi kan göra detta genom att ändra init-metoden till att endast acceptera en side som parameter, och skicka det sidvärdet till konstruktören av Rectangle-klassen.

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
 
class Square(Rectangle):
	def __init__(self, side):
		super().__init__(side, side)

Som ni kan se skickar superfunktionen side-parametern två gånger till superclass. Med andra ord, skickas side som både side1 och side2 till den tidigare definierade konstruktören.

Triangle-klass

En triangel är hälften så stor som rektangeln som omger den.

Förhållande mellan trianglar och rektanglar
Förhållande mellan trianglar och rektanglar (bildkälla: Varsity tutors).

Därför kan vi ärva från Rectangle-klassen och ändra get_area-metoden för att matcha areaformel för en triangel, som är hälften av basen multiplicerat med höjden.

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
 
class Triangle(Rectangle):
	def __init__(self, base, height):
		super().__init__(base, height)
 
	def get_area(self):
		area = super().get_area()
		return area / 2

Ett annat användningsfall för Super()-funktionen är att anropa en metod som definieras i superclass och lagra resultatet som en variabel. Det är vad som händer inuti get_area()-metoden.

Circle-klass

Du kan hitta cirkelarean med formeln πr², där r är cirkelns radie. Det innebär att vi måste ändra get_area()-metoden för att implementera denna formel.

Observera: Vi kan importera det ungefärliga värdet av π från matematikmodulen

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
 
# At the start of the file
from math import pi
 
class Circle(Shape):
	def __init__(self, radius):
		self.radius = radius
 
	def get_area(self):
		return pi * (self.radius ** 2)

Koden ovan definierar Circle-klassen som använder en annan konstruktör och get_area()-metod.

Även om Circle ärver från Shape kan du omdefiniera varje enskild metod och attribuera den efter eget tycke.

Hexagon-klass

Vi behöver bara längden på en sida av en vanlig hexagon för att beräkna dess area. Det liknar Square-klassen där vi bara skickar ett argument till konstruktören.

Hexagon areaformel
Hexagon areaformel (bildkälla: BYJU S)

Formeln är dock ganska annorlunda, och inkluderar användning av en kvadratrot. Det är därför du använder sqrt()-funktion från matematikmodulen.

# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
class Circle(Shape): …
 
# Import square root
from math import sqrt
 
class Hexagon(Rectangle):
	
	def get_area(self):
		return (3 * sqrt(3) * self.side1 ** 2) / 2

Testa våra klasser

Du kan öppna ett interaktivt läge när du kör en Python-fil med en felsökare. Det enklaste sättet att göra detta är att använda den inbyggda breakpoint-funktionen.

Observera: Denna funktion är endast tillgänglig i Python 3.7 eller senare.

from math import pi, sqrt
# Folded classes
class Shape: ...
class Rectangle(Shape): ...
class Square(Rectangle): ...
class Triangle(Rectangle): …
class Circle(Shape): …
class Hexagon(Rectangle): …
 
breakpoint()

Kör nu Python-filen och lek lite med de klasser du skapade.

$ python calculator.py
 
(Pdb) rec = Rectangle(1, 2)(Pdb) print(rec)
The area of this Rectangle is: 2
(Pdb) sqr = Square(4)
(Pdb) print(sqr)
The area of this Square is: 16
(Pdb) tri = Triangle(2, 3)
(Pdb) print(tri)
The area of this Triangle is: 3.0
(Pdb) cir = Circle(4)
(Pdb) print(cir)
The area of this Circle is: 50.26548245743669
(Pdb) hex = Hexagon(3)
(Pdb) print(hex)
The area of this Hexagon is: 23.382685902179844

Utmaning

Skapa en klass med metoden run där användaren kan välja en form och beräkna dess area.

När du har slutfört utmaningen kan du skicka en pull-förfrågan till GitHub-repot eller publicera din lösning i kommentarfältet.

Redo att börja lära dig objektorienterad programmering i Python? ✅ Du har kommit till rätt ställe 😄Click to Tweet

Sammanfattning

Objektorienterad programmering är ett paradigm där vi löser problem genom att tänka på dem som objekt. Om du förstår Python OOP kan du också enkelt tillämpa det på språk som Java, PHP, JavaScript, och C#.

I den här artikeln har du fått lära dig om:

Nu är det din tur!

Låt oss veta din lösning på utmaningen nedan i kommentarerna! Och glöm inte att kolla in vår jämförelseguide mellan Python och PHP.


Spara tid, kostnad och maximera webbplatsens prestanda med:

  • Omedelbar hjälp från WordPress -hostingexperter, 24/7.
  • Cloudflare Enterprise-integration.
  • Global publik räckvidd med 29 datacenter över hela världen.
  • Optimering med vår inbyggda Application Performance Monitoring.

Allt detta och mer, i en plan utan långsiktiga kontrakt, assisterad migration och en 30-dagars pengarna-tillbaka-garanti. Kolla in våra paket, eller prata med säljteamet för att hitta den plan som fungerar för dig.