面向对象的编程 - 语言python
#python #oop

什么是面向对象的编程?

  • 编程范式,该范式围绕对象组织代码:
    我们代表现实世界中的实体,例如代码行中的汽车,建筑物,动物和其他各种选项,以便它们按对象定义进行分类。使用概念来改善组织和维护。

  • 是具有状态(data)的实体:就像具有在对象方向内特征的真实世界对象一样,我们可以使用属性表示。

  • 它也具有行为(方法):在对象取向中,它不会忽略现实世界中实体(对象)的功能。我们可以通过代表对象行为的函数的定义表示。

Created by the author

OOP的优点和缺点是什么?

好处:

代码重复使用

将无需为具有相同属性的不同对象创建每个类。像汽车类一样,我不需要为每个汽车模型创建一个类(代码行)。例如,让我们认为有一家称为“ OO汽车”的工厂,该工厂生产两种类型的汽车“ OO Turbo”和“ OO 4x4”。您同意我的看法,这些汽车有一个工厂,4个轮子,1个引擎,颜色.....和其他几个部分。我们不会介绍所有细节。但是,想象一下您是程序员,为每辆车定义一堂课,并且大多数时候他们都会有相同的细节。在这种情况下,公司“ OO汽车”开发了一辆新车。同样,您将必须创建一个与以前的汽车相同特征的类。因此,您将不必做出巨大的重复性。这是对象方向的来源。我们仅定义一个类,以便我们可以重用不同的汽车。

错误



class Car_OO_Turbo():

     def __init__(self, model, engine, color):
         self.model = model
         self.engine = engine
         self.color = color

class Car_OO_4x4():

     def __init__(self, model, engine, color):
         self.model = model
         self.engine = engine
         self.color = color

正确



class Car():

     def __init__(self, model, engine, color):
         self.model = model
         self.engine = engine
         self.color = color

易于维护

对象方向使在代码中进行更改变得容易,从而在与外部代码隔离的类中进行维护,从而避免问题。除了将重点放在发生的问题上。

缺点:

复杂性

,但并非一切都是一个优势,随着代码的发展,我们可以遇到庞大的类声明,对属性和方法越来越复杂。班级之间的关系,因此可能影响维护的几个相关类。

调试难度

具有继承,多态性,关联和其他模式的越来越多的类。他们彼此之间更加相关。这使得很难寻找代码提出的问题和错误。花更多时间调试代码。

概念


目的

该对象被定义为实体,因此我们可以代表现实世界中的某些东西。例如:

  • 汽车
  • 地址
  • 主页
  • 食物
  • 飞机

仅由于标签是汽车或房屋而没有定义该物体。对象具有特征(属性)和过程(方法)。因此,当我们打算在OOP中代表对象时,我们添加了这些规格,以便其在要开发的系统中具有全面的表示。

Created by the author


班级

类是一个模板,或者是我们想要在项目中设计一个现实世界对象的模板。在类中,我们避免创建几个对象,使用类来表示不同的对象,它们的特征是不同的,在以下步骤中,这种形式的表示形式将变得更加清晰。

示例

  • 汽车类
  • 客户类
  • 书类

只有一个类,我们可以定义其属性和方法。

使用Python语言,我们可以创建一个类似于下面的示例的类。

class Car:
    ...
class Client:
    ...
class Book:
    ...

属性

属性是对象的特征,以餐厅为例,有序对象可以表示为类。定义后,我们将请求的特征(属性)添加到类中。就像客户的名字,选择的零食,肉类等。您可以在大型快餐中观察到订单对象的示例,当您选择,付款和等待以获取收据时,在这种情况下,这是您的收据您的名字和另一份副本去了厨房,以准备您请求的特征。在某些人中,您甚至不再需要收据纸。您的订单内有一台显示器,外面有一个,外面有准备订单的订单。

  • “ __ init __()” :此方法在Python语言类中具有构造函数定义,在此方法中,我们将定义类属性。

  • “ self” :此参数的定义是由我们将在下一步中看到的类的内部方法使用。在我们不需要将类的参数传递给类的每种方法的地方。一旦实例化, self 就会在内部函数内定义。可以使用属性的使用。

class Order:

     def __init__(
         self,
         customer_name: str,
         snack: str,
         meat_stitch: str,
         soda: bool,
         potato: bool,
     ):
         self.customer_name = customer_name
         self.snack = snack
         self.meat_point = meat_stitch
         self.soda = soda
         self.potato = potato

order1 = Order('Severius', 'X-Bacon','To the point', False, False)

print(
     f'Customer name: {order1.customer_name}\n'
     f'Snack Chosen: {order1.snack}\n'
     f'Meat point: {order1.meat_point}\n'
     f'Ordered soda: {order1.soda}\n'
     f'Ordered Potato: {order1.potato}\n'
)

# OUTPUT:
# Customer name: Severius
# Snack Chosen: X-Bacon
# Meat point: To the point
# Ordered soda: False
# Ordered Potato: False
order2 = Order('Kratos', 'X-Fish','To the point', True, True)
print(
     f'Customer name: {order2.customer_name}\n'
     f'Snack Chosen: {order2.snack}\n'
     f'Meat point: {order2.meat_point}\n'
     f'Ordered soda: {order2.soda}\n'
     f'Ordered Potato: {order2.potato}\n'
)

# output:
# Customer name: Kratos
# Snack Chosen: X-Fish
# Meat point: To the point
# Ordered soda: True
# Ordered Potato: True


方法

方法是我们在类中代表对象的函数。以汽车为例,我们可以定义功能,例如打开引擎,关闭引擎,打开大灯,关闭大灯,激活警报,停用警报,移动,停止,打开门... .....和数千个汽车可以具有的其他功能。如果您熟悉Python。我们通过编写类的内部函数来定义类中的方法,该函数仅保留在其范围内。除非我们实例化对象,否则班级以外什么都不会访问。

class Car:

    def __init__(self, model):
        self.model = model

    def turn_on_car(self):
        return 'Car On'

    def turn_off_car(self):
        return 'Car off'
car.turn_on_car()
#output: 'Car On'
car.turn_off_car()
#output: 'Car off'

属性可见性

属性可见性为共享类功能提供了Python语言中的选项。这可能在外部或内部发生。并非总是需要开发软件时,我们需要使用外部属性或方法,因此代码的其他部分不能外部访问该类,而只能内部保护属性和方法。用Python语言,有3个公开,受保护,私人。但是他们有与其他编程语言有所不同的语言特点。

公共

Python语言具有的访问修饰符之一。它是 public ,它允许访问代码中任何地方的属性和方法。

class House:
    def __init__(self, color):
        self.color = color
house_public = House('Blue public')
print(house_public.color)
# output: Blue public

受保护

受保护的访问修饰符的功能与Java语言的功能不同,它在Python语言中按照惯例或标准存在。它表示为“ _” 。要用Python语言声明,我们将其添加为属性或方法的前缀。但这并不意味着它受到保护,而是它是开发人员中的惯例。以指示属性和方法的访问的方式,仅在子类中。

class House:
    def __init__(self, color):
        self._color = color

    def print_color(self):
        print(f'Color this house is {self._color}')
house_protected = House('Blue protected')
print(house_protected._color)
print(house_protected.print_color())

# output : Blue protected
# Color this house is Blue protected
# None

私人

现在我们拥有私有它也可以作为Python语言约定。它表示为“ __” 。要用Python语言声明,我们将其添加为属性或方法的前缀。但这并不意味着它是私人的,它可以作为开发人员之间的惯例。以指示属性和方法访问的方式,仅在定义的类中。

class House:
    def __init__(self, color):
        self.__color = color

    def print_color(self):
        print(f'Color this house is {self.__color}')

但是,因为私人也是一个约定,因此发生了错误。这是因为当我们用“ __” 声明属性时,语言知道我们正在使用私人属性并在其名称上执行转换。称为“名称杂交”,它添加了“ _” 前缀,使其仅在类中访问,而不是像Java语言一样私有。

try:
    house_private = House('Blue private')
    print(house_private.__color)
    print(house_private.print_color())
except Exception as e:
    print(e)
#output: 'House' object has no attribute '__color'

要访问修改后的名称,您必须以与名称Mangling返回相同的方式传递。

class House:
    def __init__(self, color):
        self.__color = color

    def print_color(self):
        print(f'Color this house is {self.__color}')
try:
    house_private = House('Blue private')
    print(house_private._House__color)
    print(house_private.print_color())
except Exception as e:
    print(e)

# output:
# Blue private
# Color this house is Blue private
# None

封装

作为OOP的主要基础之一,封装旨在确保班级内部属性和方法的完整性。除了改进代码维护外,因为必要的更改仅是类的内部,这带来了一个受控的环境,其更改不会影响外部代码。

错误

在此阶段,这并不意味着它是错误的,而是因为我们宣布私人属性。我们不想使用“名称杂货”,并且能够使用封装。

class Car:
    def __init__(self, model, motor):
        self.model = model
        self.__motor = motor
car = Car('Ferrari', 'V8')
try:
    print(
        car.model,
        car.motor,
    )
except Exception as e:
    print(e)
# output: 'Car' object has no attribute 'motor'

正确

getters和setter受控制和安全的方法,以便我们可以访问(获取)并修改(设置)将在类中分配的数据。

  • getter:返回分配的值。不必直接处理类属性。创建保护层。在此示例中,我将使用称为 @property 的装饰器。此装饰器允许定义的方法可以访问属性。

  • 设置器:更改分配的值。它的原理是为属性定义一个新值。在此示例中,我将使用称为 @setter 的装饰器。该装饰器允许定义的方法修改属性。

class Car:
    def __init__(self, model, motor):
        self.model = model
        self.__motor = motor

    #Getter
    @property
    def motor(self):
        return self.__motor

    #Setter
    @motor.setter
    def motor(self, motor):
        self.__motor = motor

car = Car('Ferrari', 'V8')  
print(
        car.model,
        car.motor,
    )
# output: Ferrari V8

方法超载

方法过载将在类中为同一类创建多个功能(方法)的可能性。不需要为不同功能创建新类。但是,用Python语言,它不像其他语言那样支持超载。在下面,我创建了一个班级。但是请注意,捕获该错误表明缺少论点。因为下一个方法覆盖了上一个。

class UnifyStrings:
    def unify(self, first_text, second_text):
        return first_text + second_text

    def unify(self, first_test, second_text, separator):
        group_text_input = [first_test, second_text]
        return separator.join(group_text_input)
try:
    all_join = UnifyStrings()
    print(all_join.unify("Hey", "Python")) 
    print(all_join.unify("Hey", "Python", ", ")) 
except Exception as e:
    print(e)
# output: UnifyStrings.unify() missing 1 required positional argument: 'separator'

协会

关联是一个解释对象之间关系的概念。至于两个对象或类别可以共享信息的关系。

在代码中注意,我要定义两个具有其特征的类别

class Kitchen:
     def __init__(self, boss_kitchen, time):
         self.boss_kitchen = boss_kitchen
         self.time = time
         self._order = None

     @property
     def order(self):
         return self._order

     @order.setter
     def order(self, order):
         self._order = order


class Request:
     def __init__(
         self,
         order_number,
         customer_name,
         hamburguer,
         observation,
         ):
         self.order_number = order_number
         self.customer_name = customer_name
         self.hamburguer = hamburguer
         self.observation = observation

     def deliver_kitchen_order(self):
         return f'Order number: {self.order_number}\n'\
             f'Customer Name: {self.customer_name}\n'\
             f'Hamburg: {self.hamburguer}\n'\
             f'Note: {self.observation}\n'

我实例化了厨房课程,获得了厨师和他的时间。

kitchen = Kitchen('Frinaldio', 'nocturnal')
print(kitchen.boss_kitchen, kitchen.time)
# output: Frinaldio nocturnal

此时,客户到达并下订单。以与上一类相同的方式,我创建了一个具有您的订单定义的新对象。

request1 = Request(
     order_number=1671,
     customer_name='Rorismaldo Cruz',
     hamburguer='X-All',
     observation='No onion',
)

print(
     request1.order_number,
     request1.customer_name,
     request1.hamburguer,
     request1.observation,
)
# output: 1671 Rorismaldo Cruz X-All No onion

但是订单必须去某个地方,厨房收到订单。在厨房课程中注意,我只有设置器和Getter方法。我将分配一个类别的订单,然后将订单关联到厨房,在那里它将接收订单类的方法,即“ degar_order_cozinha()”。然后请注意,我在厨房对象上使用了这种相关方法。我在哪里可以访问订单属性。

kitchen.order = request1
print(kitchen.order.deliver_kitchen_order())

# output: Order number: 1671
#Customer Name: Rorismaldo Cruz
#Hamburg: X-All
#Note: No onion

kitchen = Kitchen('Crilzancar', 'Morning')
print(kitchen.boss_kitchen, kitchen.time)

# output: Crilzancar Morning

request123 = Request(
     order_number=9012,
     customer_name='Jorolmir Cunha',
     hamburguer='X-Egg',
     observation='No egg',
)

print(
     request123.order_number,
     request123.customer_name,
     request123.hamburguer,
     request123.observation,
)
# output: 9012 Jorolmir Cunha X-Egg No egg
kitchen.order = request123
print(kitchen.order.deliver_kitchen_order())

# output: Order number: 9012
# Customer Name: Jorolmir Cunha
# Hamburg: X-Egg
# Note: No egg

聚合

在聚合中,一类在其结构中具有其他类别。

# This step below I just created to simulate an order time and then the time it will take to prepare

import time
import datetime

named_tuple = time.localtime()
year = named_tuple.tm_year
month = named_tuple.tm_mon
day = named_tuple.tm_mday
hour = named_tuple.tm_hour
minute = named_tuple.tm_min
second = named_tuple.tm_sec

start_request_time = datetime.datetime(year, month, day, hour, minute, second)
final_order_time = start_request_time + datetime.timedelta(minutes = 40)
print(start_request_time)
print(final_order_time)

# output: 2023-05-21 15:10:29
# 2023-05-21 15:50:29
class Kitchen:
     def __init__(self, head_kitchen):
         self.head_kitchen = head_kitchen
         self._orders = []

     def new_order(self, order):
         self._orders.append(order)

     def kitchen_orders(self):
         for order in self._orders:
             print(
                 f'Order number: {order.order_number}\n'\
                 f'Customer Name: {order.customer_name}\n'\
                 f'Head of Kitchen: {self.head_kitchen}\n'\
                 f'Hamburg: {order.hamburguer}\n'\
                 f'Note: {order.observation}\n'
                 f'Request Time: {start_request_time}\n'
                 f'Time ready: {final_order_time}\n'
             )


class Request:
     def __init__(
         self,
         order_number,
         customer_name,
         hamburguer,
         observation,
         ):
         self.order_number = order_number
         self.customer_name = customer_name
         self.hamburguer = hamburguer
         self.observation = observation

再次在“哈哈哈”厨房情况下。我要定义一个新的厨房对象。

kitchen = Kitchen('Terequelzio')

但是,想象一下这个厨房收到了几个要求,而不是关联。我将在一个类中团结几个对象,在那里我可以在单个类中使用它们的方法和属性。对于厨房物体,您将可以访问到达的订单,无论厨房内的人都会看到订单的特征并开始准备。

request1 = Request(
     order_number=1671,
     customer_name='Rorismaldo Cruz',
     hamburguer='X-All',
     observation='No onion',
)

request2 = Request(
     order_number=9012,
     customer_name='Jorolmir Cunha',
     hamburguer='X-Egg',
     observation='No egg',
)

kitchen.new_order(request1)
kitchen.new_order(request2)

kitchen.kitchen_orders()

# output:
# Order number: 1671
# Customer Name: Rorismaldo Cruz
# Head of Kitchen: Terequelzio
# Hamburg: X-All
# Note: No onion
# Request Time: 2023-05-21 15:10:29
# Time ready: 2023-05-21 15:50:29

# Order number: 9012
# Customer Name: Jorolmir Cunha
# Head of Kitchen: Terequelzio
# Hamburg: X-Egg
# Note: No egg
# Request Time: 2023-05-21 15:10:29
# Time ready: 2023-05-21 15:50:29

作品

构图是关于将类与其他类相结合而无需父级(主类)的类。这样,我们就可以拥有一个看起来像构建基础的课程。我们将其作为基础创建,而在其他类中,我们可以逐件组成我们想要的结构。

# This step below I just created to simulate an order time and then the time it will take to prepare

import time
import datetime

named_tuple = time.localtime()
year = named_tuple.tm_year
month = named_tuple.tm_mon
day = named_tuple.tm_mday
hour = named_tuple.tm_hour
minute = named_tuple.tm_min
second = named_tuple.tm_sec

start_request_time = datetime.datetime(year, month, day, hour, minute, second)
final_order_time = start_request_time + datetime.timedelta(minutes = 40)
print(start_request_time)
print(final_order_time)

# output:
# 2023-05-21 15:10:29
# 2023-05-21 15:50:29

class Potato:
     def __init__(self, size, quantity):
         self.size = size
         self.quantity = quantity

class Hamburguer:
     def __init__(self, size, quantity):
         self.size = size
         self.quantity = quantity

class Soda:
     def __init__(self, size, quantity):
         self.size = size
         self.quantity = quantity


class Request:
     def __init__(self, customer_name):
         self.customer_name = customer_name
         self._potato = None
         self._hamburguer = None
         self._soda = None

     @property
     def potato(self):
         return self._potato

     @potato.setter
     def potato(self, potato):
         self._potato = potato

     @property
     def hamburguer(self):
         return self._hamburguer

     @hamburguer.setter
     def hamburguer(self, hamburguer):
         self._hamburguer = hamburguer

     @property
     def soda(self):
         return self._soda

     @soda.setter
     def soda(self, soda):
         self._soda = soda


     def add_potato(self, quantity, size):
         self.potato = Potato(quantity, size)

     def add_hamburguer(self, quantity, size):
         self.hamburguer = Hamburguer(quantity, size)

     def add_soda(self, quantity, size):
         self.soda = Soda(quantity, size)

     def show_order(self):
             print(
                 f'Customer Name: {self.customer_name}\n'\
                 f'Burger: {self.hamburguer.quantity}| {self.hamburguer.size}\n'\
                 f'Potato: {self.potato.quantity}| {self.potato.size}\n'\
                 f'Soda: {self.soda.quantity}| {self.soda.size}\n'\
                 f'Request Time: {start_request_time}\n'
                 f'Time ready: {final_order_time}\n'
             )

构图概念是通过一堂课使用的最有趣的概念之一。基类(顺序)可以使用您的定义。这非常好,因为您避免在课程中添加许多参数。以有组织的方式,每个功能将被隔离。我将能够部分组成。如下面的顺序示例。

request1 = Request(
     customer_name='Rorismaldo Cruz',

)

request1.add_potato(2, 'medium')
request1.add_hamburguer(2, 'medium')
request1.add_soda(2, 'medium')
request1.show_order()

# output: 
# Customer Name: Rorismaldo Cruz
# Burger: medium| 2
# Potato: medium| 2
# Soda: medium| 2
# Request Time: 2023-05-21 15:10:29
# Time ready: 2023-05-21 15:50:29
request1 = Request(customer_name='Mericliendes Bento')

request1.add_potato(8, 'small')
request1.add_hamburguer(2, 'big')
request1.add_soda(3, 'small')
request1.show_order()

# output: 
# Customer Name: Mericliendes Bento
# Burger: big| 2
# Potato: small| 8
# Soda: small| 3
# Request Time: 2023-05-21 15:10:29
# Time ready: 2023-05-21 15:50:29

遗产

继承带来了代码重复使用的主要点。使用下面的汽车类示例,我们在示例中传递了其特征。然后,我们声明了一个新课程,例如Micro_car,Sedans,sports_car,它们正在从汽车班上借用其特征。然后,我们可以使用这些类实例化新对象。

# parent class
class Car:

    def __init__(self, modelo):
        self.modelo = modelo


    def print_car(self):
        print("")

#child class
class Micro_Car(Car):

    def print_car(self):
        print(f"Your microcar is : {self.modelo}")

#child class
class Sedans(Car):

    def print_car(self):
        print(f"Your sedan is: {self.modelo}")

#child class 
class Sports_Cars(Car):

    def print_car(self):
        print(f"Your Sport Car is: {self.modelo}")

#We create the object
bond_bug = Micro_Car("Bond Bug")
fiat_cinquecento= Sedans("Fiat Cinquecento")
porsche_911= Sports_Cars("Porsche 911")


bond_bug.print_car()
fiat_cinquecento.print_car() 
porsche_911.print_car() 

# output:
# Your microcar is : Bond Bug
# Your sedan is: Fiat Cinquecento
# Your Sport Car is: Porsche 911

多态性

多态性是另一个面向对象的概念,我们如何修改在父类中具有其定义的子类方法。通过这种方式,我们通过继承重复了已经定义的方法。子类中的修改方法结构


# Parent class
class Time_Activite:
    def time(self):
        pass

# Child class
class Total_Time_kilimeter(Time_Activite):

    def __init__(self, total_kilimeter, time_input):
        self.total_kilimeter = total_kilimeter
        self.time_input = time_input

    # Method modification
    def time(self):

        #Note that the results are different, being able to create the same methods more for different behaviors
        return f'Your activite => Kilimeter: {self.total_kilimeter} | Time: {self.time_input}'

# Child class
class Time_Per_Kilimeter(Time_Activite):

    def __init__(self, total_kilimeter, time_input):
        self.total_kilimeter = total_kilimeter
        self.time_input = time_input

    # Method modification
    def time(self):
        time = (self.time_input * 60)
        time = (time / self.total_kilimeter)
        time = (time / 60)

        #Note that the results are different, being able to create the same methods more for different behaviors
        return f'Your time per kilometer: {time} minutes'


results = [Total_Time_kilimeter(5, 20), Time_Per_Kilimeter(7, 35)]

for result in  results:
    print(result.time())

# output:
# Your activite => Kilimeter: 5 | Time: 20
# Your time per kilometer: 5.0 minutes

界面

Python语言中的接口没有类型的实现的Java语言的结构。通常,使用属性和方法将其视为示例结构,但缺乏严格的验证。请参阅下面的跑步和山地自行车课。这些类正在从Interface_sport接口中获得示例类。使用activate_activity函数您可以利用使用start_activite方法声明的接口。

class InterfaceSport:
    def start_activite(self):
        pass

class Run(InterfaceSport):
    def start_activite(self):
        return "Race start, let's go !!!"

class MountainBike(InterfaceSport):
    def start_activite(self):
        return "MTB start, let's go !!!"

def activate_activity(activity):
    print(activity.start_activite())

run = Run()
mtb = MountainBike()

activate_activity(run)
activate_activity(mtb)

# output:
# Race start, let's go !!!
# MTB start, let's go !!!

评论

感谢您阅读这篇文章。希望我能帮助您理解。任何代码或文本错误,请随时返回。不要忘记离开这样的人,以便您可以吸引更多的人。

资源

在这里,我离开了上面的代码笔记本。如果您从未使用过Jupyter笔记本。我建议下载文件并将其上传到Google驱动器,然后使用Google Colab打开。单击以运行您将避免创建环境,很快您将能够测试代码。

工具

Repository — OOP