python入门(9)面向对象 :封装、继承、多态与垃圾回收

奋斗吧
奋斗吧
擅长邻域:未填写

标签: python入门(9)面向对象 :封装、继承、多态与垃圾回收

2023-05-29 18:23:30 43浏览

Python 中的垃圾回收是通过引用计数和垃圾回收器来自动管理对象的内存。引用计数用于跟踪对象的引用情况,当引用计数为0时,对象将被回收。垃圾回收器处理循环引用和其他特殊情况,确保不会有任何对象被遗漏。开发者无需手动管理内存,可以专注于编写代码逻辑。

1. 封装

在Python中,封装是面向对象编程中的一个重要概念,它允许将数据和方法隐藏在类的内部,只暴露一部分接口供外部访问。通过封装,可以有效地控制数据的访问权限,提高代码的可维护性和安全性。

1.1 修饰符

Python中的封装通过使用访问修饰符来实现,主要有三种访问修饰符:

(1)公有访问修饰符(Public):使用默认的访问权限,没有任何修饰符,所有成员都可以在类的内部和外部访问。示例代码如下:

class MyClass:
    def __init__(self):
        self.public_var = 10

    def public_method(self):
        print("This is a public method.")

obj = MyClass()
print(obj.public_var)  # Output: 10
obj.public_method()    # Output: This is a public method.

(2)私有访问修饰符(Private):使用双下划线__作为前缀,将属性或方法标记为私有的,表示只能在类的内部访问。示例代码如下:

class MyClass:
    def __init__(self):
        self.__private_var = 20

    def __private_method(self):
        print("This is a private method.")

    def public_method(self):
        self.__private_method()

obj = MyClass()
print(obj.__private_var)  # Error: 'MyClass' object has no attribute '__private_var'
obj.__private_method()    # Error: 'MyClass' object has no attribute '__private_method'
obj.public_method()       # Output: This is a private method.

尽管私有属性和方法在类的外部无法直接访问,但可以通过公有方法间接访问私有成员。

(3)保护访问修饰符(Protected):使用单下划线_作为前缀,将属性或方法标记为受保护的,表示只能在类的内部和子类中访问。示例代码如下:

class MyBaseClass:
    def __init__(self):
        self._protected_var = 30

    def _protected_method(self):
        print("This is a protected method.")

class MyDerivedClass(MyBaseClass):
    def access_protected(self):
        print(self._protected_var)
        self._protected_method()

obj = MyDerivedClass()
obj.access_protected()    # Output: 30\nThis is a protected method.

尽管受保护的成员可以在子类中访问,但在类的外部仍然可以直接访问。因此,保护访问修饰符主要起到一种命名约定的作用,表示某个成员是受保护的,不应该在类的外部直接访问。

封装可以帮助我们隐藏实现的细节,提供清晰的接口供外部使用。

1.2 self 参数

在Python中,self 是一个约定俗成的参数名,用于表示对象自身。它是一个指向当前实例的引用,类中的方法通过 self 参数来访问对象的属性和方法。

在类定义中,使用 self 作为第一个参数声明方法时,表示该方法是对象的实例方法,可以通过实例调用。例如,__init__(self) 方法用于初始化对象,在方法内部可以通过 self 访问对象的属性和方法。

示例代码:

class MyClass:
    def __init__(self, x):
        self.x = x

    def print_x(self):
        print(self.x)

obj = MyClass(10)
obj.print_x()  # Output: 10

在调用 obj.print_x() 时,self 参数会自动传递实例对象 obj,使得在 print_x 方法内部可以通过 self.x 访问到对象的属性。

需要注意的是,self 不是Python的关键字,可以使用其他名称代替,但约定俗成的做法是使用 self 来表示对象自身。

2. 继承

在Python中,继承是一种面向对象编程的重要概念,它允许一个类继承另一个类的属性和方法,从而实现代码的重用和扩展。

要定义一个继承关系,可以在定义类时在类名后面加上要继承的父类名,用括号括起来。例如,下面是一个简单的继承示例:

class ParentClass:
    def __init__(self, x):
        self.x = x

    def print_x(self):
        print("ParentClass: ", self.x)


class ChildClass(ParentClass):
    def __init__(self, x, y):
        super().__init__(x)  # 调用父类的初始化方法
        self.y = y

    def print_y(self):
        print("ChildClass: ", self.y)


obj = ChildClass(10, 20)
obj.print_x()  # Output: ParentClass: 10
obj.print_y()  # Output: ChildClass: 20

在上面的示例中,ChildClass 继承了 ParentClass,因此它可以访问和使用 ParentClass 中定义的属性和方法。子类可以添加新的属性和方法,也可以重写父类中的方法。

在子类的初始化方法中,可以使用 super().__init__(args) 来调用父类的初始化方法,并传递相应的参数。这样可以确保子类对象在创建时先调用父类的初始化逻辑,然后再进行自己的初始化操作。

通过继承,子类可以继承父类的属性和方法,并且可以添加、修改或覆盖这些属性和方法,从而实现代码的复用和扩展。继承是面向对象编程中重要的特性之一,可以建立类之间的层次关系,提高代码的可维护性和可扩展性。

关于多重继承

Python 支持多重继承,这意味着一个类可以继承自多个父类。

在定义一个类时,可以在类名后面的括号中指定多个父类,多个父类之间使用逗号进行分隔。例如:

class ParentClass1:
    def method1(self):
        print("ParentClass1: method1")

class ParentClass2:
    def method2(self):
        print("ParentClass2: method2")

class ChildClass(ParentClass1, ParentClass2):
    def method3(self):
        print("ChildClass: method3")

obj = ChildClass()
obj.method1()  # Output: ParentClass1: method1
obj.method2()  # Output: ParentClass2: method2
obj.method3()  # Output: ChildClass: method3

在上述示例中,ChildClass 继承了 ParentClass1ParentClass2 两个父类。因此,它可以访问和使用两个父类中定义的属性和方法。通过多重继承,子类可以从多个父类中继承不同的功能,从而实现更灵活和复杂的代码结构。

需要注意的是,多重继承可能导致类之间的复杂关系,特别是当不同的父类中有相同的方法名时,可能会引起命名冲突。在这种情况下,可以使用方法解析顺序(Method Resolution Order,MRO)来确定调用哪个父类的方法。Python 使用 C3 算法来计算 MRO,确保方法的调用顺序是按照一定规则确定的。

尽管多重继承可以提供更大的灵活性和代码重用性,但在使用时需要注意设计和维护的复杂性。合理使用多重继承可以充分利用面向对象编程的优势,但需要注意避免过度复杂化和混乱的继承结构。

3. 多态

多态是面向对象编程的一个重要概念,它允许不同的对象对相同的消息做出不同的响应。在 Python 中,多态性是通过方法的动态绑定实现的。

当一个对象调用一个方法时,Python 会根据对象的类型确定要调用的方法实现。如果该对象是一个特定类的实例,Python 将搜索该类及其父类中的方法,并调用与该方法名匹配的方法实现。

下面是一个简单的示例,演示多态的概念:

class Animal:
    def sound(self):
        pass

class Cat(Animal):
    def sound(self):
        print("Meow!")

class Dog(Animal):
    def sound(self):
        print("Woof!")

def make_sound(animal):
    animal.sound()

cat = Cat()
dog = Dog()

make_sound(cat)  # Output: Meow!
make_sound(dog)  # Output: Woof!

在上述示例中,我们定义了一个基类 Animal,以及两个子类 CatDog。这两个子类都重写了基类中的 sound 方法,实现了各自的声音输出。

然后,我们定义了一个名为 make_sound 的函数,该函数接受一个 Animal 类型的参数,并调用该参数的 sound 方法。通过传入不同的实例对象,我们可以看到函数根据对象的类型调用不同的 sound 方法,实现了多态性。

多态性能够提高代码的灵活性和可扩展性。通过面向对象的多态性,可以编写通用的代码,适用于不同的对象类型,并根据实际对象的类型来调用正确的方法。这样可以使代码更加模块化和可维护,同时减少了冗余的条件判断语句。

4. 多态与 is instance 关键字

is instance 是 Python 中的一个关键字,用于检查一个对象是否属于指定的类型或其子类。它与多态性密切相关,可以在代码中判断对象的类型,并根据需要执行相应的操作。

is instance 的语法如下:

isinstance(object, classinfo)

其中,object 是要检查的对象,classinfo 是要检查的类型或类型元组。

下面是一个示例,演示 isinstance 的用法和多态的概念:

class Animal:
    def sound(self):
        pass

class Cat(Animal):
    def sound(self):
        print("Meow!")

class Dog(Animal):
    def sound(self):
        print("Woof!")

def make_sound(animal):
    if isinstance(animal, Animal):
        animal.sound()
    else:
        print("Invalid animal!")

cat = Cat()
dog = Dog()

make_sound(cat)  # Output: Meow!
make_sound(dog)  # Output: Woof!
make_sound("Invalid")  # Output: Invalid animal!

在上述示例中,我们使用 is instance 来检查传入 make_sound 函数的参数是否属于 Animal 类或其子类。如果是,我们调用 animal.sound() 来执行相应的动作;否则,我们打印出 "Invalid animal!"。

is instance 的使用可以帮助我们在多态的情境中正确地处理不同类型的对象。它允许我们根据对象的类型执行不同的操作,提高代码的可读性和可维护性。

5. python对象的垃圾回收

在 Python 中,垃圾回收是自动进行的,开发者不需要手动管理内存。Python 通过引用计数和垃圾回收器来处理对象的内存管理。

引用计数: Python 使用引用计数来跟踪对象的引用情况。每当对象被引用时,它的引用计数增加1;当对象不再被引用时,它的引用计数减1。当一个对象的引用计数变为0时,表示没有任何引用指向它,该对象将被垃圾回收器回收并释放内存。

循环引用: 循环引用指的是一组对象之间形成了一个环状的引用关系,导致它们的引用计数都不为0,即使没有外部引用指向它们,它们也无法被垃圾回收。为了解决这个问题,Python 使用了一个垃圾回收器来检测和处理循环引用的情况。

垃圾回收器: Python 中的垃圾回收器是一个独立的线程,它会周期性地扫描所有的对象,并判断它们的引用计数是否为0。对于引用计数为0的对象,垃圾回收器将释放它们所占用的内存空间。除了引用计数,垃圾回收器还会检测和处理循环引用,确保不会有任何对象被遗漏。

需要注意的是,虽然垃圾回收是自动进行的,但它可能会导致一些额外的开销和性能损失。在大多数情况下,Python 的垃圾回收机制是高效且无需干预的。然而,对于一些特殊情况,比如大量创建临时对象或使用循环引用的复杂数据结构,开发者可能需要考虑优化内存管理以提高性能。

总结:Python 中的垃圾回收是通过引用计数和垃圾回收器来自动管理对象的内存。引用计数用于跟踪对象的引用情况,当引用计数为0时,对象将被回收。垃圾回收器处理循环引用和其他特殊情况,确保不会有任何对象被遗漏。开发者无需手动管理内存,可以专注于编写代码逻辑。

6. 类的垃圾回收机制

在 Python 中,垃圾回收是由解释器自动进行的,开发者不需要显式地实现垃圾回收。Python 使用引用计数和垃圾回收器来处理对象的内存管理,这些功能由解释器内部实现并进行管理。

引用计数是 Python 主要的垃圾回收机制。每个对象都有一个引用计数器,当有一个引用指向对象时,引用计数加1;当引用离开作用域或被重新赋值时,引用计数减1。当一个对象的引用计数变为0时,表示没有任何引用指向它,该对象就可以被回收。

除了引用计数,Python 还有一个垃圾回收器(Garbage Collector),它会定期扫描所有的对象,并检查是否有循环引用的情况。如果发现循环引用,垃圾回收器会标记这些对象,并将它们回收。

开发者可以通过 `gc` 模块来控制和调整垃圾回收器的行为,例如手动触发垃圾回收、禁用垃圾回收等。`gc` 模块提供了一些函数和方法,如下所示:

  • `gc.collect()`:手动触发一次垃圾回收。
  • `gc.disable()`:禁用垃圾回收器。
  • `gc.enable()`:启用垃圾回收器。
  • `gc.get_count()`:返回当前垃圾回收的计数器。
  • `gc.get_threshold()`:返回垃圾回收器的阈值。
  • `gc.set_threshold()`:设置垃圾回收器的阈值。

需要注意的是,大多数情况下,Python 的垃圾回收是自动进行的,无需开发者干预。开发者只需关注对象的创建和使用,由解释器自动管理内存和垃圾回收。但在某些特殊情况下,如处理大量临时对象或使用循环引用的复杂数据结构时,了解垃圾回收机制和相应的调优技巧可能会对性能有所帮助。

好博客就要一起分享哦!分享海报

此处可发布评论

评论(0展开评论

暂无评论,快来写一下吧

展开评论

您可能感兴趣的博客

客服QQ 1913284695