Object oriented programming is not difficult for beginners to understand, but it is difficult to apply , Although we have summarized the object-oriented three-step method for you ( Defining classes 、 Create objects 、 Send messages to objects ), But easier said than done . A lot of programming practice and Read good code It may be the two things that can help you most at this stage . Next, we will analyze the knowledge of object-oriented programming through classic cases , At the same time, through these cases, I will explain how to use what I have learned before Python knowledge .
explain : Simplicity , Our poker is only 52 card ( There is no king or king ), The game needs to 52 Cards are dealt to 4 Players' hands , Each player has 13 card , According to spades 、 Red hearts 、 Grass flower 、 The order of the squares and the number of points are arranged from small to large , Do not realize other functions for the time being .
Using object-oriented programming methods , First, you need to find the object from the requirements of the problem and abstract the corresponding class , In addition, find the properties and behavior of the object . Of course , This is not particularly difficult , We can find nouns and verbs from the description of requirements , Nouns are usually objects or attributes of objects , Verbs are usually the actions of objects . There should be at least three types of objects in a poker game , They are cards 、 Poker and players , card 、 Poker 、 The three categories of players are not isolated . The relationship between classes can be roughly divided into is-a Relationship ( Inherit )、has-a Relationship ( relation ) and use-a Relationship ( rely on ). Obviously poker and cards are has-a Relationship , Because a deck of poker has (has-a)52 card ; There are not only correlations but also dependencies between players and cards , Because players have (has-a) And the player used (use-a) card .
The nature of the card is obvious , There are decors and points . We can use 0 To 3 To represent four different designs and colors , But the readability of such code would be very bad , Because we don't know spades 、 Red hearts 、 Grass flower 、 Square heel 0 To 3 The corresponding relationship between the numbers of . If a variable has only a limited number of options , We can use enumeration . And C、Java The language difference is ,Python There is no keyword declaring enumeration type in , But it can be inherited enum
Modular Enum
Class to create enumeration types , The code is as follows .
from enum import Enum
class Suite(Enum):
""" Design and color ( enumeration )"""
SPADE, HEART, CLUB, DIAMOND = range(4)
SPADE
、HEART
etc. . Each symbolic constant has a corresponding value , In this way, the spades can be expressed without numbers 0
, It's about using Suite.SPADE
; Empathy , It means that the square can be without numbers 3
, It's about using Suite.DIAMOND
. Be careful , Using symbolic constants is certainly better than using literal constants , Because I can understand the meaning of symbolic constants by reading English , The readability of the code will be improved a lot .Python The enumeration type in is an iteratable type , Simply put, you can put the enumeration type into for-in
In circulation , Take out each symbolic constant and its corresponding value in turn , As shown below .for suite in Suite:
print(f'{
suite}: {
suite.value}')
class Card:
""" card """
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __repr__(self):
suites = ''
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
# Get the corresponding character according to the design and color of the card and the number of points
return f'{suites[self.suite.value]}{faces[self.face]}'
Card
class .card1 = Card(Suite.SPADE, 5)
card2 = Card(Suite.HEART, 13)
print(card1, card2) # 5 K
import random
class Poker:
""" Poker """
def __init__(self):
# Create a package by using the list's generative syntax 52 A list of cards
self.cards = [Card(suite, face) for suite in Suite
for face in range(1, 14)]
# current Attribute indicates the location of the deal
self.current = 0
def shuffle(self):
""" Shuffle """
self.current = 0
# adopt random Modular shuffle Function to realize the random disorder of the list
random.shuffle(self.cards)
def deal(self):
""" Licensing """
card = self.cards[self.current]
self.current += 1
return card
@property
def has_next(self):
""" There are no cards to deal """
return self.current < len(self.cards)
Poker
class .poker = Poker()
poker.shuffle()
print(poker.cards)
class Player:
""" The player """
def __init__(self, name):
self.name = name
self.cards = []
def get_one(self, card):
""" Touch the card """
self.cards.append(card)
def arrange(self):
self.cards.sort()
poker = Poker()
poker.shuffle()
players = [Player(' Dongxie '), Player(' Western poison '), Player(' South Emperor '), Player(' North beggar ')]
for _ in range(13):
for player in players:
player.get_one(poker.deal())
for player in players:
player.arrange()
print(f'{
player.name}: ', end='')
print(player.cards)
Executing the above code will result in player.arrange()
There is an exception , because Player
Of arrange
Method uses the... Of the list sort
Sort the cards in the player's hand , Sorting requires comparing two Card
Size of object , and <
The operator cannot directly act on Card
type , So there it is TypeError
abnormal , The exception message is :'<' not supported between instances of 'Card' and 'Card'
.
To solve this problem , We can Card
Class code is slightly modified , Make two Card
Objects can be used directly <
Compare sizes . The technology used here is called Operator overloading ,Python To realize the <
operator overloading , You need to add a class named __lt__
The magic of . Obviously , Magic methods __lt__
Medium lt
It 's an English word “less than” Abbreviation , And so on , Magic methods __gt__
Corresponding >
Operator , Magic methods __le__
Corresponding <=
Operator ,__ge__
Corresponding >=
Operator ,__eq__
Corresponding ==
Operator ,__ne__
Corresponding !=
Operator .
The modified Card
The class code is as follows .
class Card:
""" card """
def __init__(self, suite, face):
self.suite = suite
self.face = face
def __repr__(self):
suites = ''
faces = ['', 'A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']
# Get the corresponding character according to the design and color of the card and the number of points
return f'{
suites[self.suite.value]}{
faces[self.face]}'
def __lt__(self, other):
# Compare the size of points with the same design and color
if self.suite == other.suite:
return self.face < other.face
# Compare the values corresponding to different decors
return self.suite.value < other.suite.value
explain : You can try to write a simple poker game based on the above code , Such as 21 Click game (Black Jack), The rules of the game can be found on the Internet .
requirement : There are three types of employees in a company , Department managers 、 Programmers and salesmen . We need to design a salary settlement system , Calculate the employee's monthly salary according to the employee information provided . among , The monthly salary of the Department Manager is fixed 15000 element ; Programmers work by hours ( In hours ) Pay monthly salary , Every hour 200 element ; The monthly salary of the salesperson is paid by 1800 Yuan base salary plus sales 5% A commission of two parts .
Employee
Parent class of , Then the Department Manager is derived from this parent class by inheritance 、 Programmers and salespeople are three sub categories . Obviously , Subsequent code will not create Employee
Class object , Because what we need is a specific employee , So this class can be designed as an abstract class for inheritance .Python There are no keywords for defining abstract classes in , But it can go through abc
Module named ABCMeta
To define abstract classes . Knowledge of metaclasses , There will be special explanations in the later courses , There is no need to struggle with this concept , Just remember the usage .from abc import ABCMeta, abstractmethod
class Employee(metaclass=ABCMeta):
""" staff """
def __init__(self, name):
self.name = name
@abstractmethod
def get_salary(self):
""" Settle monthly salary """
pass
get_salary
This method is used to settle the monthly salary , But since it has not been determined what kind of employees it is , Therefore, although the settlement of monthly salary is a public behavior of employees, there is no way to achieve it here . For methods that cannot be implemented temporarily , We can use abstractmethod
Decorator declares it as an abstract method , So-called An abstract method is a method that has only a declaration but no implementation , This method is declared so that subclasses can override it . The following code shows how to derive a department manager from an employee class 、 The programmer 、 Salesperson these three subclasses and how subclasses override the abstract methods of the parent class .class Manager(Employee):
""" division manager """
def get_salary(self):
return 15000.0
class Programmer(Employee):
""" The programmer """
def __init__(self, name, working_hour=0):
super().__init__(name)
self.working_hour = working_hour
def get_salary(self):
return 200 * self.working_hour
class Salesman(Employee):
""" Salesperson """
def __init__(self, name, sales=0):
super().__init__(name)
self.sales = sales
def get_salary(self):
return 1800 + self.sales * 0.05
above Manager
、Programmer
、Salesman
All three classes inherit from Employee
, Each of the three classes overrides get_salary
Method . Rewriting is a subclass's re - Implementation of an existing method of a parent class . I believe you have noticed , Of the three subclasses get_salary
Each are not identical , So this method will produce when the program is running Polymorphic behavior , Polymorphism simply means Call the same method , Different subclass objects do different things .
We use the following code to complete the salary settlement system , As programmers and salespeople need to enter the working hours and sales volume of this month respectively , So in the following code we use Python Built in isinstance
Function to determine the type of employee object . We talked about it before type
Function can also identify the type of object , however isinstance
Functions are more powerful , Because it can determine whether an object is a subtype of an inheritance structure , You can simply understand it as type
Functions are exact matches of object types , and isinstance
Function is a fuzzy matching of object types .
emps = [
Manager(' Liu bei '), Programmer(' Zhugeliang '), Manager(' Cao Cao '),
Programmer(' Emperor Xu '), Salesman(' Lyu3 bu4 '), Programmer(' Zhang liao '),
]
for emp in emps:
if isinstance(emp, Programmer):
emp.working_hour = int(input(f' Please enter {
emp.name} Working hours of this month : '))
elif isinstance(emp, Salesman):
emp.sales = float(input(f' Please enter {
emp.name} Sales this month : '))
print(f'{
emp.name} The salary of this month is : ¥{
emp.get_salary():.2f} element ')