Python青少年简明教程:类和对象入门

Python青少年简明教程:类和对象入门

Python支持多种编程范式(programming paradigms),即支持多种不同的编程风格和方法。初学者开始重点学习关注的编程范式,一般而言是面向过程编程和面向对象编程。面向过程编程(Procedural Programming)它关注于通过过程(或称为函数、子程序)来组织程序的逻辑。它是命令式编程(Imperative Programming)的一种具体风格。

【Python也支持函数式编程(Functional Programming)的一些特性,如lambda函数、map()、filter()等。

Python也支持事件驱动编程(Event-Driven Programming),这编程范式特别适用于创建响应式和交互式的应用程序。Python提供了多种方式来实现事件驱动编程:使用标准的(内置的)库tkinter(Python的标准GUI库,适合创建简单的桌面应用), 标准库中的asyncio模块(提供了对异步编程的支持。它可以处理事件循环、协程、任务和事件驱动编程), 一些第三方库(如PyQt用于创建GUI应用,pygame:用于游戏开发)等。】

前面的介绍的编程,主要是面向过程编程(Procedural Programming)它关注于通过过程(或称为函数、子程序)来组织程序的逻辑。它是命令式编程(Imperative Programming)的一种具体风格。

作为对比,先概括面向过程编程风格的特点。面向过程编程是命令式编程的一种具体风格。它主要关注于:

    将程序分解为一系列的过程(也称为函数或子程序)

    这些过程按顺序执行,每个过程执行特定的任务

    强调代码的重用和模块化

示例:

def calculate_area(length, width):
    return length * width

def calculate_perimeter(length, width):
    return 2 * (length + width)

# 使用函数
room_length = 5
room_width = 4
area = calculate_area(room_length, room_width)
perimeter = calculate_perimeter(room_length, room_width)

print(f"房间面积:{area}平方米")
print(f"房间周长:{perimeter}米")

面向对象编程呢?这是另一种重要的范式,它主要关注于:

    将数据和操作数据的方法组织到对象中

    使用类来创建对象

    支持封装、继承和多态等概念

示例:

class Room:
    def __init__(self, length, width):
        self.length = length
        self.width = width
    
    def calculate_area(self):
        return self.length * self.width
    
    def calculate_perimeter(self):
        return 2 * (self.length + self.width)

# 使用类
my_room = Room(5, 4)
print(f"房间面积:{my_room.calculate_area()}平方米")
print(f"房间周长:{my_room.calculate_perimeter()}米")

下面将介绍Python面向对象编程知识。

Python是一种面向对象编程(OOP)的语言,类和对象是其核心概念。

类(Class

类 是对象的蓝图或模板,它定义了一组属性和方法,这些属性和方法被具体的对象实例所共享。

基本语法:

class ClassName:
    # 类体
    pass

【注:pass 是一个特殊语句,它主要用作占位符,不会改变程序的执行流程,但pass 是一个语句,是一个语法上的无操作语句,它的出现能避免不写任何语句时的语法错误。】

下面给出定义类的包含比较全面的语法:
class ClassName:
    # 类属性
    class_attribute = value

    # 初始化方法
    def __init__(self, parameter1, parameter2):
        self.instance_attribute1 = parameter1
        self.instance_attribute2 = parameter2

    # 实例方法
    def instance_method(self):
        # 方法体
        pass

    # 类方法
    @classmethod
    def class_method(cls):
        # 方法体
        pass

    # 静态方法
    @staticmethod
    def static_method():
        # 方法体
        pass

类和对象的说明

属性 (Attributes): 对象具有的数据。

方法 (Methods): 对象可以执行的操作。

实例化 (Instantiation): 使用类创建对象的过程。

self: 在方法定义中,self 代表当前对象,用于访问修改对象的属性和方法。

实例属性:定义在 __init__ 方法中的属性,用 self 引用。每个对象都有自己独立的实例属性。

类属性:在类体内直接定义,用 ClassName.attribute 或 self.__class__.attribute 引用。所有对象共享类属性。

实例方法:定义在类内部,以 self 作为第一个参数的方法。用于操作对象实例的属性。

类方法:使用 @classmethod 装饰器定义,以 cls 作为第一个参数的方法。用于操作类属性。

静态方法:使用 @staticmethod 装饰器定义,不需要 self 或 cls 参数。通常与类或实例无关。

必须的部分:

class ClassName: 这是定义类的基本语法,是必须的。

常用但不是必须的部分:

__init__ 方法:虽然不是严格必需的,但在大多数情况下都会定义,用于初始化对象。

实例属性:通常在 __init__ 中定义,但也可以在其他方法中定义。

可选但常见的部分:

类属性:不是必须的,但在需要所有实例共享某些属性时很有用。

实例方法:定义对象的行为,是面向对象编程的核心,但并非每个类都必须有。

类方法和静态方法:这些是更高级的概念,根据具体需求使用。

另外,Python 使用命名约定(如单下划线前缀)来表示私有或保护成员,而不是严格的访问控制。

需要注意,重要的是理解这些组件的作用,并根据具体情况选择使用。过度设计(如在不需要的地方使用类方法或静态方法)可能会使代码不必要地复杂。

Python类中各种成员的用途和注意事项:

☆类属性(Class Attributes)

用途:

    存储所有实例共享的数据

    定义类级别的常量

    跟踪类的全局状态

注意事项:

    可以通过类名或实例访问

    修改时要小心,因为会影响所有实例

    可能被实例属性覆盖

☆实例属性(Instance Attributes)

用途:

    存储每个实例特有的数据

    定义对象的状态

注意事项:

    通常在__init__方法中初始化,使用self定义的变量

    只能通过实例访问

    每个实例可以有不同的值

☆实例方法(Instance Methods)

用途:

    定义对象的行为

    操作实例的状态

注意事项:

    第一个参数总是self,代表实例本身

    可以访问和修改实例属性

    通过实例调用

☆类方法(Class Methods)

用途:

    操作类属性

    实现替代构造器

注意事项:

    使用@classmethod装饰器

    第一个参数通常命名为cls,代表类本身

    可以通过类或实例调用

    不能直接访问实例属性

☆静态方法(Static Methods)

用途:

    实现与类相关但不需要访问类或实例状态的功能

    组织代码结构

注意事项:

    使用@staticmethod装饰器

    不需要特殊的首参数

    可以通过类或实例调用(不建议通过实例调用)

    不能访问类或实例属性

☆魔术方法(Magic Methods),也称为特殊方法

用途:

    定制类的特殊行为,用于实现特定的功能,如对象初始化、字符串表示、运算符重载等。

注意事项:

    以双下划线开始和结束,如__init__、str、__len__等

    在特定情况下自动调用

    可以极大地增强类的功能和灵活性

☆属性装饰器(Property Decorators)

用途:

    将方法调用伪装成属性访问(可以像访问属性一样访问)

    实现计算属性

    控制属性的访问、设置和删除

注意事项:

    使用@property装饰器

    可以定义getter、setter和deleter

    提供了一种优雅的方式来封装数据访问

☆内部类(Nested Classes)

用途:

    将相关类组织在一起

    封装辅助类

注意事项:

    定义在另一个类的内部

    可以访问外部类的属性

    通常用于实现辅助功能或数据结构

☆私有成员(Private Members)

用途:

    隐藏实现细节

    防止直接访问和修改

注意事项:

    以双下划线__开头

    Python通过名称改写机制实现

    可以通过特殊方式访问,不是绝对私有

☆保护成员(Protected Members)

用途:

    表示应该被视为内部使用的成员

    在继承中使用

注意事项:

    以单下划线_开头

    这只是一个约定,并不强制执行,实际可以被外部访问,但不应该

特别提示,实际使用时,合理使用各种成员类型,有些部分不一定出现,选择合适的类型可以使您的代码更加清晰和高效。

Python类的成员类型和概念很多,一次性全部掌握是有难度的。这是很正常的学习过程,可以先集中精力关注您不需要一次掌握所有内容。随着您编写更多的Python代码,这些概念会变得越来越清晰。最常用的部分,如实例属性、实例方法、类方法和静态方法。基础示例:

class Car:
    total_cars = 0  # 类属性

    def __init__(self, make, model):
        self.make = make    # 实例属性
        self.model = model  # 实例属性
        Car.total_cars += 1

    def display_info(self):  # 实例方法
        return f"{self.make} {self.model}"

    @classmethod
    def get_total_cars(cls):  # 类方法
        return cls.total_cars

    @staticmethod
    def honk():  # 静态方法
        return "Beep beep!"

# 使用类
my_car = Car("Toyota", "Corolla")
print(my_car.display_info())  # 输出: Toyota Corolla
print(Car.get_total_cars())   # 输出: 1
print(Car.honk())             # 输出: Beep beep!

这个例子涵盖了基本的类属性、实例属性、实例方法、类方法和静态方法。您可以从这里开始,逐步理解每个概念的作用和使用场景。

Python 中类的方法确实与普通函数比较

在 Python 中,类的方法确实与普通函数在很多方面都是类似的。两张比较如下:

相似之处:

a) 定义方式:

类方法和普通函数都使用 def 关键字定义。

b) 参数传递:

两者都可以接受位置参数、关键字参数、默认参数、*args 和 **kwargs。

c) 返回值:

两者都可以有返回值,使用 return 语句。

d) 文档字符串:

两者都可以使用文档字符串(docstrings)来描述其功能。

e) 装饰器:

两者都可以使用装饰器来修改或增强功能。

主要区别:

a) self 参数:

类方法的第一个参数通常是 self,代表类的实例。普通函数没有这个要求。

b) 访问范围:

类方法可以访问类的属性和其他方法,而普通函数不能直接访问类的内部结构。

c) 调用方式:

类方法通常通过类的实例调用,而普通函数直接调用。

d) 特殊方法:

类可以有特殊方法(如 __init__, __str__ 等),这在普通函数中不存在。

让我们通过一个例子来说明这些相似点和区别:

# 普通函数
def regular_function(x, y, *args, **kwargs):
    """这是一个普通函数的文档字符串"""
    print(f"Regular function: x={x}, y={y}, args={args}, kwargs={kwargs}")

# 类定义
class ExampleClass:
    def __init__(self, name):
        self.name = name

    def class_method(self, x, y, *args, **kwargs):
        """这是一个类方法的文档字符串"""
        print(f"{self.name}: x={x}, y={y}, args={args}, kwargs={kwargs}")

    @staticmethod
    def static_method(x, y):
        """这是一个静态方法"""
        print(f"Static method: x={x}, y={y}")

# 使用普通函数
regular_function(1, 2, 3, 4, a=5, b=6) # 输出:Regular function: x=1, y=2, args=(3, 4), kwargs={'a': 5, 'b': 6}

# 使用类方法
obj = ExampleClass("MyObject")
obj.class_method(1, 2, 3, 4, a=5, b=6) # 输出:MyObject: x=1, y=2, args=(3, 4), kwargs={'a': 5, 'b': 6}

# 使用静态方法
ExampleClass.static_method(1, 2) # 输出:Static method: x=1, y=2

这个例子展示了普通函数和类方法在定义和使用上的相似性,同时也突出了它们的一些区别,特别是 self 参数的使用和调用方式的不同。

总的来说,Python 的设计使得类方法在使用上感觉非常像普通函数,这是 Python 简洁和一致性设计哲学的体现。这种相似性使得从函数式编程转向面向对象编程变得相对容易。

下面介绍封装(Encapsulation)、继承(Inheritance)和多态(Polymorphism)等内容,很重要,但涉及内容广泛,在此仅作简要介绍,作为初学者可以先作为了解内容。

封装(Encapsulation

封装是将数据(属性)和行为(方法)隐藏在类内部,只通过公开的方法访问。

私有属性和方法:通过在属性或方法名前加两个下划线 __ 实现。示例:

class Person:
    def __init__(self, name, age):
        self.__name = name  # 私有属性
        self.__age = age

    def get_name(self):
        return self.__name

    def get_age(self):
        return self.__age

person = Person("Alice", 30)
print(person.get_name())  # 输出: Alice
print(person.get_age())  # 输出: 30
# print(person.__name)  # 会报错,无法直接访问私有属性

在 Python 中,高级封装可以属性装饰器(@property)和property()函数。

Python中的property:@property装饰器和 property() 函数,它们都是用来创建托管属性(managed properties)的机制,允许你对属性的获取、设置和删除操作进行精细控制。这两种方法本质上是实现相同功能(功能等价)的不同语法。这是一种更现代、更简洁的语法,通常在新代码中更常用。property()函数这是较早的语法,但仍然完全有效和有用。@property装饰器实际上是property()函数的语法糖。

选择哪种主要取决于个人偏好和具体的使用场景。

Python使用装饰器(@property)来实现getter和setter的功能。例如:

class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property
    def radius(self):
        """Getter for radius"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """Setter for radius"""
        if value <= 0:
            raise ValueError("半径必须为正数")
        self._radius = value

    @property
    def area(self):
        """Getter for area"""
        return 3.14 * self._radius ** 2

circle = Circle(5)
print(circle.radius)  # 输出: 5
circle.radius = 10    # 使用setter
print(circle.radius)  # 输出: 10
print(circle.area)    # 输出: 约 314.0

# circle.radius = -1  # 会抛出 ValueError: 半径必须为正数

说明(解释):

a. @property装饰器:

    将方法转换为只读属性

    通常用作getter

b. @[属性名].setter装饰器:

    定义属性的setter方法

    允许设置属性值时进行验证或处理

c. 只读属性:

    只定义@property而不定义setter,创建只读属性

property()函数

property() 函数是 Python 内置函数,用于创建和返回 property 对象。它提供了另一种方式来定义属性,而不是使用装饰器语法。

property() 函数的基本语法是:

property(fget=None, fset=None, fdel=None, doc=None)

其中:

    fget:获取属性值的函数(getter)

    fset:设置属性值的函数(setter)

    fdel:删除属性的函数(可选)

    doc:属性的文档字符串(可选)

例如(一个完整的、可运行的使用property() 函数示例):

class Circle:
    def __init__(self, radius):
        self._radius = radius

    def get_radius(self):
        print("Getting radius")
        return self._radius

    def set_radius(self, value):
        print("Setting radius")
        if value <= 0:
            raise ValueError("半径必须为正数")
        self._radius = value

    def del_radius(self):
        print("Deleting radius")
        del self._radius

    radius = property(get_radius, set_radius, del_radius, "圆的半径属性")

# 使用这个类
circle = Circle(5)

print(circle.radius)  # 获取半径
circle.radius = 10    # 设置半径
print(circle.radius)  # 再次获取半径
del circle.radius     # 删除半径

# 查看属性的文档
print(Circle.radius.__doc__)

# 尝试设置无效值
try:
    circle.radius = -1
except ValueError as e:
    print(f"错误: {e}")

说明(解释):

我们定义了 get_radius、set_radius 和 del_radius 方法。

使用 property() 函数创建了 radius 属性,将这些方法关联起来。

当我们访问、修改或删除 radius 属性时,相应的方法被调用。

我们还可以访问属性的文档字符串。

当尝试设置无效值时,会引发 ValueError。

使用 property() 函数的优点是它提供了一种更灵活的方式来定义属性,特别是在需要动态创建属性或在运行时修改属性行为时。然而,对于大多数简单的情况,使用 @property 装饰器语法通常更为简洁和常见。

运行这个程序的输出是:

Getting radius
5
Setting radius
Getting radius
10
Deleting radius
圆的半径属性
Setting radius
错误: 半径必须为正数

继承(Inheritance

继承是面向对象编程中的一个重要概念,它允许一个类(子类)继承另一个类(父类)的属性和方法。

定义子类的语法:

class SubClass(ParentClass):
    # 子类定义
 

示例:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        raise NotImplementedError("Subclass must implement this method")

class Cat(Animal):
    def speak(self):
        return f"{self.name} says meow"

class Dog(Animal):
    def speak(self):
        return f"{self.name} says woof"

cat = Cat("Whiskers")
dog = Dog("Buddy")

print(cat.speak())  # 输出: Whiskers says meow
print(dog.speak())  # 输出: Buddy says woof

多重继承(Multiple Inheritance)

Python 支持多重继承,一个子类可以继承多个父类。

语法:

class SubClass(ParentClass1, ParentClass2):
    # 子类定义

示例:

class Swimmable:
    def swim(self):
        return "I can swim"

class Flyable:
    def fly(self):
        return "I can fly"

class Duck(Swimmable, Flyable):
    pass

duck = Duck()
print(duck.swim())  # 输出: I can swim
print(duck.fly())  # 输出: I can fly

多态(Polymorphism

在 Python 中,多态(Polymorphism)是指不同的对象对同一操作的不同响应方式。这意味着,您可以用相同的方式处理不同类型的对象,而不需要了解它们具体的类型。多态通常通过继承与方法重写(override)来实现。例如:

class Shape:
    def area(self):
        pass

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius
    
    def area(self):
        return 3.14 * self.radius ** 2

def print_area(shape):
    print(f"The area is: {shape.area()}")

# 创建不同的形状
rect = Rectangle(5, 4)
circ = Circle(3)

# 用相同的函数处理不同的对象
print_area(rect)  # 输出: The area is: 20
print_area(circ)  # 输出: The area is: 28.26

说明,在这个例子中:

Shape 是一个基类,定义了 area 方法。

Rectangle 和 Circle 继承自 Shape,并重写了 area 方法。

print_area 函数接受一个 Shape 对象,并调用其 area 方法。

我们可以传入 Rectangle 或 Circle 的实例,print_area 函数会正确调用相应的 area 方法。

这个例子展示了如何通过继承和方法重写来实现多态,也展示了如何用相同的方式(调用 print_area 函数)处理不同类型的对象。

方法重写(Method Overriding)

子类可以重写父类的方法,提供自己的实现。

示例:

class Bird:
    def speak(self):
        return "Bird sound"

class Parrot(Bird):
    def speak(self):
        return "Parrot says squawk"

bird = Bird()
parrot = Parrot()

print(bird.speak())  # 输出: Bird sound
print(parrot.speak())  # 输出: Parrot says squawk

最后总结一下Python中的self的作用。

self小结:

Python中的self是一个在面向对象编程中非常重要的概念。self 是一个约定俗成的名称,通常用于代表一个类的实例。它作为实例方法的第一个参数来访问对象的属性和方法。 self 的作用:

1)用于访问和修改实例变量(也称为实例的属性)。

2)用于调用其他实例方法。

示例:

class Person:
    def __init__(self, name, age):
        self.name = name  # 使用 self 设置实例变量
        self.age = age

    def introduce(self):
        print(f"我是 {self.name},今年 {self.age} 岁")  # 使用 self 访问实例变量

    def have_birthday(self):
        self.age += 1  # 使用 self 修改实例变量
        self.introduce()  # 使用 self 调用其他实例方法

# 创建实例
person = Person("Alice", 30)
person.introduce()  # 输出:我是 Alice,今年 30 岁
person.have_birthday()  # 输出:我是 Alice,今年 31 岁

关于self重要说明

self 必须作为第一个参数传递给实例方法,但在调用时不需要传递,Python 会自动处理。

self不是Python的关键字,而是个常用约定,但你可以使用其他名称,但是不建议这样做,以保持代码的可读性和一致性。

在__init__中,self指向新创建的实例。(__init__是一个特殊方法,用于初始化新创建的对象。)

访问实例变量时总是需要使用self前缀。

实例方法的定义需要包含self,在类方法 (使用@classmethod装饰器) 和静态方法 (使用@staticmethod装饰器) 中,self 不再使用,类方法使用cls作为第一个参数;静态方法不使用特殊的第一个参数。

在子类中,self仍然指向当前实例,即使方法是从父类继承的。

附录

Python面向对象程序设计 https://blog.csdn.net/cnds123/article/details/108354860

Python中的property介绍 https://blog.csdn.net/cnds123/article/details/129420059

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学习&实践爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值