30天拿下Python之面向对象编程

简介: 30天拿下Python之面向对象编程

概述

在上一节,我们介绍了Python的函数,包括:函数的定义、函数的调用、参数的传递、lambda函数等内容。在本节中,我们将介绍Python的面向对象编程。面向对象编程(Object-Oriented Programming, 即OOP)是一种编程范型,它以对象为基础,将数据和操作封装在一个类(Class)中。在Python中,类是一种定义对象结构和行为的模板,而对象则是类的实例。类定义了一个新的类型,用于创建具有特定属性和方法的对象。类是面向对象编程的核心,它允许程序员使用对象来组织代码和复用代码。

类的定义

在Python中,类的基本语法如下:

class ClassName:
    # class attribute
    class_variable = "class variable"
  
    def __init__(self, arg1, arg2):
        # instance variable
        self.instance_variable = arg1 + arg2
  
    # instance method
    def instance_method(self):
        print("I am an instance method")
  
    # class method
    @classmethod
    def class_method(cls):
        print("I am a class method")
  
    # static method
    @staticmethod
    def static_method():
        print("I am a static method")

下面逐一介绍上面示例代码中的各个元素。

class ClassName:这是类定义的开始,以class关键字作为开头,ClassName是要定义的类的名称;最后面是冒号,冒号后面的内容需要缩进。

class_variable = "class variable":这是类变量,它是一个在类中定义的全局变量,所有实例共享同一个变量。

def __init__(self, arg1, arg2):这是类的构造函数,当一个类实例被创建时会自动调用。在这个例子中,构造函数接受两个参数:arg1和arg2。self是对当前实例的引用,调用时不需要写,由系统自动填入。构造函数可以不带参数,也可以带一个或多个参数。

self.instance_variable = arg1 + arg2:这是一个实例变量,每个实例都有自己独立的实例变量。在这个例子中,实例变量是arg1和arg2的和。

def instance_method(self):这是一个实例方法,它需要一个实例作为其第一个参数(通常命名为self,也可以使用其他名称)。self是对当前实例的引用,调用时不需要写,由系统自动填入。

@classmethod:这是一个类方法装饰器,标识后面是一个类方法。它不需要实例作为其第一个参数,而是使用类名本身作为第一个参数(通常命名为cls,也可以使用其他名称)。cls是对当前类的引用,调用时不需要写,由系统自动填入。

@staticmethod:这是一个静态方法装饰器,标识后面是一个静态方法。它不需要实例或类作为其参数。

类的使用

定义好类之后,我们就可以实例化该类的对象,并调用其属性和方法了。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show_info(self):
        print(f'name is {self.name}, {self.age} years old')

    @staticmethod
    def show_skill():
        print('walk, run, swim')
          
# 创建一个Person类的实例
person1 = Person('xiaoxiao', 20)
# 访问实例变量,输出:xiaoxiao 20
print(person1.name, person1.age)
# 访问实例方法,输出:name is xiaoxiao, 20 years old
person1.show_info()
# 访问静态方法,输出:walk, run, swim
person1.show_skill()
Person.show_skill()

可以看到,访问实例变量和实例方法时,必须使用实例对象。访问静态方法时,既可以使用实例对象,也可以使用类名。

类的__init__方法是类的构造函数,当一个类实例被创建时会自动调用。同样的,类的__del__方法是类的析构函数,在释放实例对象时,也会被自动调用。

class Animal:
    def __init__(self, name):
        self.name = name
        print(f'animal {name} constructed')

    def __del__(self):
        print(f'animal {self.name} destructed')

    def show(self):
        print(f'{self.name} is preset')
          
def test():
    animal = Animal('seagull')
    animal.show()

''' test作用域结束时,animal会销毁,故依次输出:
animal seagull constructed
seagull is preset
animal seagull destructed
'''
test()

类变量和实例变量

类变量是在类的所有实例中共享的变量,这就意味着,如果你改变了一个类变量的值,那么这个改变将影响到类的所有实例。类变量在类定义时声明,通常在类的方法中使用。

class MyClass:  
    # 类变量  
    class_variable = 0  
  
    def __init__(self, instance_variable):  
        self.instance_variable = instance_variable  
        MyClass.class_variable = self.instance_variable + 100  
   
instance1 = MyClass(66)
# 输出:166
print(MyClass.class_variable)
  
instance2 = MyClass(88)
# 均输出:188
print(MyClass.class_variable)
print(instance1.class_variable)
print(instance2.class_variable)

在上面的示例代码中,class_variable是一个类变量,它被所有实例共享。每次创建一个新的实例时,都会改变class_variable的值。因此,当创建了instance2并给它一个值为88的参数时,class_variable的值就从166变成了188。

实例变量是在类的每个实例中单独存储的变量,这就意味着,如果你改变了一个实例的状态,那么这个改变只影响那个特定的实例。实例变量在类的__init__方法中声明,通常在实例的方法中使用。


class MyClass:
    def __init__(self, instance_variable):
        # 实例变量
        self.instance_variable = instance_variable  
  
instance1 = MyClass(66)
# 输出:66
print(instance1.instance_variable)
  
# 创建实例2
instance2 = MyClass(88)
# 输出:88
print(instance2.instance_variable)
# 输出:66
print(instance1.instance_variable)

# 改变实例1的实例变量值
instance1.instance_variable = 100
# 输出:100
print(instance1.instance_variable)
# 输出:88
print(instance2.instance_variable)

在上面的示例代码中,instance_variable是一个实例变量,每个实例都有它自己的副本。当你改变instance1的 instance_variable值时,instance2的值不会受到影响。

在Python中,两个下划线开头的属性被声明为私有属性,不能在类的外部被使用或直接访问。否则,运行时会报AttributeError的错误信息。

class MyNumber:
    def __init__(self, value):
        self.__value = value

num = MyNumber(66)
# 访问私有属性,运行时报错:'MyNumber' object has no attribute '__value'
print(num.__value)

实例方法、类方法和静态方法

实例方法是定义在类中的普通函数,它需要一个实例作为第一个参数(通常命名为self)。实例方法只能通过类的实例来调用,可以访问类变量和实例变量。

类方法是定义在类中的普通函数,它需要一个类作为第一个参数(通常命名为cls)。类方法可以通过类和类的实例来调用,只能访问类变量,不能访问实例变量。在定义类方法时,可以使用@classmethod装饰器进行声明。

静态方法是定义在类中的普通函数,它不需要任何参数(包括 self)。静态方法可以通过类和类的实例来调用,不可以访问类变量和实例变量。在定义静态方法时,可以使用@staticmethod装饰器进行声明。

class Person:
    # 类变量
    skills: ['walk', 'run', 'swim']

    def __init__(self, name, age):
        # 示例变量
        self.name = name
        self.age = age

    # 实例方法,可以访问类变量和实例变量
    def show_info(self):
        print(f'name is {self.name}, {self.age} years old')
        print(self.skills)

    # 类方法,可以访问类变量
    @classmethod
    def show_skill(cls):
        print(cls.skills)

    # 静态方法,不可以访问类变量和实例变量
    @staticmethod
    def show_basic():
        print('a person here')

在Python中,两个下划线开头的方法被声明为私有方法,不能在类的外部被使用或直接访问。否则,运行时会报AttributeError的错误信息。

class MyNumber:
    def __init__(self, value):
        self.__value = value

    def __show(self):
        print(self.__value)

num = MyNumber(66)
# 访问私有属性,运行时报错:'MyNumber' object has no attribute '__show'
num.__show()

与C++、Java等语言不同,Python不支持函数重载。当类的定义中有多个同名的函数时,将以最后一个声明的函数为准。

class MyNumber:
    def __init__(self, value):
        self.__value = value

    def show(self):
        print(self.__value)

    def show(self, a):
        print(self.__value, a)

num = MyNumber(100)
num.show(66)
# 运行时报错:MyNumber.show() missing 1 required positional argument: 'a'
num.show()

类的运算符重载

可以通过定义特定方法来重载类对象的运算符,以下是一些常见的运算符重载方法。

__add__(self, other):重载加法运算符 +,用于实现两个对象的相加。

__sub__(self, other):重载减法运算符 -,用于实现两个对象的相减。

__mul__(self, other):重载乘法运算符 *,用于实现两个对象的相乘。

__truediv__(self, other):重载除法运算符 /,用于实现两个对象的相除。

__floordiv__(self, other):重载整数除法运算符 //,用于实现两个对象的整数相除。

__mod__(self, other):重载取模运算符 %,用于实现两个对象的取模运算。

__pow__(self, other):重载幂运算运算符 **,用于实现两个对象的幂运算。

__eq__(self, other):重载相等运算符 ==,用于判断两个对象是否相等。

__ne__(self, other):重载不等运算符 !=,用于判断两个对象是否不相等。

__lt__(self, other):重载小于运算符 <,用于判断两个对象是否小于。

__le__(self, other):重载小于等于运算符 <=,用于判断两个对象是否小于等于。

__gt__(self, other):重载大于运算符 >,用于判断两个对象是否大于。

__ge__(self, other):重载大于等于运算符 >=,用于判断两个对象是否大于等于。

 假如我们定义了一个名为MyNumber的类,可以按照以下方式重载加法运算符。

class MyNumber:
    def __init__(self, value):
        self.value = value
     
    def __add__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value + other.value)
       
        return MyNumber(self.value + other)
num1 = MyNumber(100)
num2 = MyNumber(200)
num = num1 + num2
# 输出:300
print(num.value)

继承

继承是一种实现面向对象编程的重要机制,它允许我们基于已有的类创建新的类,从而继承已有类的属性和方法。在Python中,使用class语句定义一个类时,可以在类名后面使用(base_classes)的形式指定该类要继承的父类。base_classes可以为一个类,也可以为多个类。多个类时,各个类之间用逗号进行分隔,属于多重继承的内容。

class Animal:
    def __init__(self, name):
        self.name = name
     
    def eat(self):
        print(self.name + " is eating...")
 
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
dog = Dog('Sky', 'Corgi')
# 输出:Sky is eating...
dog.eat()
# 输出:Corgi
print(dog.breed)


在上面的示例代码中,Dog类继承了Animal类,因此Dog类具有了Animal类的属性和方法。在Dog类的定义中,我们可以通过调用super().__init__(name)来调用父类的构造函数,从而初始化Dog类实例的name属性。

除了继承父类的属性和方法,子类还可以重写父类的方法,从而实现对父类行为的修改。


class Animal:
    def __init__(self, name):
        self.name = name
     
    def eat(self):
        print(self.name + " is eating...")
 
class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)
        self.breed = breed
    def eat(self):
        print(self.breed + " eats more")
dog = Dog('Sky', 'Corgi')
# 覆盖父类方法,输出:Corgi eats more
dog.eat()
# 强制调用父类方法,输出:Sky is eating...
super(Dog, dog).eat()



在上面的示例代码中,我们直接在Dog类中定义了一个与父类同名的eat方法,从而完全覆盖了父类的行为。如果想强制调用父类的方法,可以使用类似super(Dog, dog)的方式获得父类的实例,再调用父类的方法。


相关文章
|
2月前
|
Java C# Python
Python学习七:面向对象编程(中)
这篇文章是关于Python面向对象编程的中级教程,涵盖了析构函数、对象的三大特征(封装、继承、多态)、类属性与实例属性、以及类方法与静态方法的对比。
27 2
|
2月前
|
设计模式 安全 JavaScript
Python学习八:面向对象编程(下):异常、私有等
这篇文章详细介绍了Python面向对象编程中的私有属性、私有方法、异常处理及动态添加属性和方法等关键概念。
27 1
|
7月前
|
Python
Python编程作业五:面向对象编程
Python编程作业五:面向对象编程
76 1
|
7月前
|
Python
【Python进阶(三)】——面向对象编程
【Python进阶(三)】——面向对象编程
|
3月前
|
Java Python
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
【9月更文挑战第18天】在 Python 中,虽无明确的 `interface` 关键字,但可通过约定实现类似功能。接口主要规定了需实现的方法,不提供具体实现。抽象基类(ABC)则通过 `@abstractmethod` 装饰器定义抽象方法,子类必须实现这些方法。使用抽象基类可使继承结构更清晰、规范,并确保子类遵循指定的方法实现。然而,其使用应根据实际需求决定,避免过度设计导致代码复杂。
|
3月前
|
Python
全网最适合入门的面向对象编程教程:Python函数方法与接口-函数与方法的区别和lamda匿名函数
【9月更文挑战第15天】在 Python 中,函数与方法有所区别:函数是独立的代码块,可通过函数名直接调用,不依赖特定类或对象;方法则是与类或对象关联的函数,通常在类内部定义并通过对象调用。Lambda 函数是一种简洁的匿名函数定义方式,常用于简单的操作或作为其他函数的参数。根据需求,可选择使用函数、方法或 lambda 函数来实现代码逻辑。
|
2月前
|
Java Python
Python学习六:面向对象编程(上)
这篇文章是关于Python面向对象编程的基础知识,包括类和对象的概念、实例方法、属性、self关键字以及魔法方法等。
18 0
|
4月前
|
Python
Python 中的面向对象编程 (OOP)
【8月更文挑战第29天】
43 7
|
4月前
|
机器学习/深度学习 PHP 开发者
探索PHP中的面向对象编程构建你的首个机器学习模型:以Python和scikit-learn为例
【8月更文挑战第30天】在PHP的世界中,面向对象编程(OOP)是一块基石,它让代码更加模块化、易于管理和维护。本文将深入探讨PHP中面向对象的魔法,从类和对象的定义开始,到继承、多态性、封装等核心概念,再到实战中如何应用这些理念来构建更健壮的应用。我们将通过示例代码,一起见证PHP中OOP的魔力,并理解其背后的设计哲学。
|
4月前
|
Python
下一篇
DataWorks