Python - 访问修饰符

你好,有抱负的Python程序员们!今天,我们将开始一段激动人心的旅程,深入了解Python中的访问修饰符。如果你是编程新手,不用担心;我会一步一步引导你理解这个概念,沿途会有大量的例子和解释。那么,让我们开始吧!

Python - Access Modifiers

Python中的访问修饰符

在面向对象编程中,访问修饰符用于控制类成员(属性和方法)的可见性和可访问性。虽然许多编程语言有严格的访问修饰符,如public、private和protected,但Python采用了一种更为宽松的方法。它遵循一种常被称为“我们这里都是成年人”的哲学。

在Python中,我们有三种访问修饰符:

  1. 公共
  2. 受保护
  3. 私有

让我们通过例子来探讨每一个。

公共成员

在Python中,所有成员默认都是公共的。这意味着它们可以从类的外部访问。以下是一个例子:

class Student:
def __init__(self, name, age):
self.name = name  # 公共属性
self.age = age    # 公共属性

def display_info(self):  # 公共方法
print(f"Name: {self.name}, Age: {self.age}")

# 创建Student的一个实例
student1 = Student("Alice", 20)

# 访问公共成员
print(student1.name)  # 输出:Alice
student1.display_info()  # 输出:Name: Alice, Age: 20

在这个例子中,nameagedisplay_info()都是公共成员。我们可以直接从类的外部访问它们。

受保护成员

受保护成员通过在成员名称前加上一个下划线(_)来表示。它们并不是真正的私有,仍然可以从外部访问,但按照约定,应将其视为仅内部使用。

class Employee:
def __init__(self, name, salary):
self._name = name      # 受保护属性
self._salary = salary  # 受保护属性

def _display_salary(self):  # 受保护方法
print(f"{self._name}'s salary is ${self._salary}")

# 创建Employee的一个实例
emp1 = Employee("Bob", 50000)

# 访问受保护成员(注意:这是可能的,但不推荐)
print(emp1._name)  # 输出:Bob
emp1._display_salary()  # 输出:Bob's salary is $50000

虽然我们可以访问_name_salary_display_salary(),但通常不推荐在类或其子类的外部这样做。

私有成员

私有成员通过在名称前加上双下划线(__)来表示。Python会对这些成员进行名称重整,使它们更难(但不是不可能)从外部访问。

class BankAccount:
def __init__(self, account_number, balance):
self.__account_number = account_number  # 私有属性
self.__balance = balance                # 私有属性

def __display_balance(self):  # 私有方法
print(f"Balance: ${self.__balance}")

def public_display(self):
self.__display_balance()

# 创建BankAccount的一个实例
account1 = BankAccount("123456", 1000)

# 尝试访问私有成员
# print(account1.__account_number)  # 这将引发一个AttributeError
# account1.__display_balance()      # 这也将引发一个AttributeError

# 通过公共方法访问私有方法
account1.public_display()  # 输出:Balance: $1000

在这个例子中,__account_number__balance__display_balance()是私有成员。尝试直接从外部访问它们将引发一个AttributeError。

名称重整

还记得我提到过Python中的私有成员并不是真正的私有吗?这是因为一个称为名称重整的机制。当你使用双下划线创建一个私有成员时,Python会内部改变它的名称,使其更难被意外访问。

以下是如何工作的:

class NameManglingDemo:
def __init__(self):
self.__private_var = "I'm private!"

demo = NameManglingDemo()
print(dir(demo))
# 输出:[... '_NameManglingDemo__private_var', ...]

# 使用重整后的名称访问私有变量
print(demo._NameManglingDemo__private_var)  # 输出:I'm private!

正如你所看到的,Python将__private_var重命名为_NameManglingDemo__private_var。这就是名称重整的作用!

Python属性对象

Python中的property()函数是一个内置函数,用于创建并返回一个属性对象。它是一种向类属性添加getter、setter和deleter方法的方式。

以下是一个例子:

class Temperature:
def __init__(self, celsius):
self._celsius = celsius

def get_fahrenheit(self):
return (self._celsius * 9/5) + 32

def set_fahrenheit(self, fahrenheit):
self._celsius = (fahrenheit - 32) * 5/9

fahrenheit = property(get_fahrenheit, set_fahrenheit)

# 使用属性
temp = Temperature(25)
print(temp.fahrenheit)  # 输出:77.0

temp.fahrenheit = 86
print(temp._celsius)  # 输出:30.0

在这个例子中,fahrenheit是一个属性,它允许我们获取和设置华氏温度,而内部则以摄氏度存储。

Getter和Setter方法

Getter和Setter方法是用于获取和设置类属性值的方 法。它们提供了一种在保持封装的同时访问和修改私有属性的方法。

以下是一个使用@property装饰器的例子,这是实现getter和setter的更Pythonic方式:

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

@property
def name(self):
return self._name

@name.setter
def name(self, value):
if not isinstance(value, str):
raise ValueError("Name must be a string")
self._name = value

@property
def age(self):
return self._age

@age.setter
def age(self, value):
if not isinstance(value, int) or value < 0:
raise ValueError("Age must be a positive integer")
self._age = value

# 使用getter和setter
person = Person("Charlie", 30)
print(person.name)  # 输出:Charlie

person.name = "David"
print(person.name)  # 输出:David

try:
person.age = -5
except ValueError as e:
print(e)  # 输出:Age must be a positive integer

在这个例子中,我们为nameage创建了getter和setter方法。setter方法包括验证,以确保设置的值满足某些条件。

以下是我们讨论的方法的总结表:

方法 描述 例子
公共 任何地方都可访问 self.name
受保护 类内部和子类中可访问(按约定) self._name
私有 名称重整以限制访问 self.__name
属性 创建一个属性对象 property(get_method, set_method)
Getter 获取属性值的方法 @property
Setter 设置属性值的方法 @attribute.setter

这就是全部内容!我们涵盖了Python中的访问修饰符、名称重整、属性对象以及getter和setter方法。请记住,Python对访问控制的方法更多是基于约定和信任,而不是严格的规定。在你继续Python之旅时,你会发现这种灵活性使得代码保持清晰可读,同时仍然提供实现封装的方法。

继续练习,保持好奇,祝编程愉快!

Credits: Image by storyset