面向对象编程(OOP)是Python编程的核心范式,而属性和方法是构建类的两大基石。本文将全面讲解Python中属性和方法的各类特性和使用技巧,帮助你掌握面向对象编程的精髓。
类属性属于类本身,被所有实例共享
class Dog:
# 类属性
species = "Canis familiaris"
count = 0 # 用于统计实例数量
def __init__(self, name):
self.name = name # 实例属性
Dog.count += 1
每个实例独有的属性,通常在__init__
中初始化
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
self.grade = self.calculate_grade()
def calculate_grade(self):
return 'A' if self.score >= 90 else 'B'
print(Dog.species) # 通过类访问类属性
buddy = Dog("Buddy")
print(buddy.name) # 通过实例访问实例属性
print(buddy.species) # 通过实例访问类属性(会向上查找)
实例方法就是函数,至少有一个指向实例对象的形参self
最常用的方法类型,第一个参数为self
class Circle:
def __init__(self, radius):
self.radius = radius
# 实例方法
def area(self):
return 3.14 * self.radius ** 2
使用@classmethod
装饰器,第一个参数为cls
(
说明
类方法需要使用@classmethod装饰器定义
类方法至少有一个形参用于绑定类,约定为 cls
类和该类的实例都可以调用类方法
类方法不能访问此类创建的对象的实例属性
)
class Pizza:
def __init__(self, ingredients):
self.ingredients = ingredients
@classmethod
def margherita(cls):
return cls(["mozzarella", "tomatoes"])
@classmethod
def prosciutto(cls):
return cls(["mozzarella", "tomatoes", "ham"])
使用@staticmethod
装饰器,没有默认参数
(
静态方法定义在类的内部,作用域是类内部
说明
使用@staticmethod装饰器定义
不需要self和cls参数
通过类或类实例调用
可以访问类属性,不能访问实例属性
)
class MathUtils:
@staticmethod
def add(a, b):
return a + b
@staticmethod
def multiply(a, b):
return a * b
以单下划线开头,提示"不要直接访问"
class BankAccount:
def __init__(self, balance):
self._balance = balance # 提示这是受保护的
以双下划线开头,Python会进行名称改写(Name Mangling)
作用:通过改变属性名称来实现一定程度的"私有化"。
改写后的名称格式为:
_类名__原属性名
class Secret:
def __init__(self):
self.__secret_code = "12345" # 实际变为_Secret__secret_code
属性装饰器(@property
)是Python中一种强大的特性,它允许你将方法"伪装"成属性来访问,从而实现对属性的更精细控制。
使用@property
控制属性访问
class Temperature:
def __init__(self, celsius):
self._celsius = celsius
@property
def celsius(self):
return self._celsius
@celsius.setter
def celsius(self, value):
if value < -273.15:
raise ValueError("温度不能低于绝对零度")
self._celsius = value
@property
def fahrenheit(self):
return self._celsius * 9/5 + 32
魔术方法是一种特殊的方法,用双下划线包裹,例如__init__
,__str__
,__add__
等。这些方法允许您自定义类的行为,以便与内置Python功能(如+运算符、迭代、字符串表示等)交互。
__init__(self, ...)
: 初始化对象,通常用于设置对象的属性。
__str__(self)
: 定义对象的字符串表示形式,可通过str(object)
或print(object)
调用。例如,您可以返回一个字符串,描述对象的属性。
__repr__(self)
: 定义对象的“官方”字符串表示形式,通常用于调试。可通过repr(object)
调用。
__len__(self)
: 定义对象的长度,可通过len(object)
调用。通常在自定义容器类中使用。
__getitem__(self, key)
: 定义对象的索引操作,使对象可被像列表或字典一样索引。例如,object[key]
。
__setitem__(self, key, value)
: 定义对象的赋值操作,使对象可像列表或字典一样赋值。例如,object[key] = value
。
__delitem__(self, key)
: 定义对象的删除操作,使对象可像列表或字典一样删除元素。例如,del object[key]
。
__iter__(self)
: 定义迭代器,使对象可迭代,可用于for
循环。
__next__(self)
: 定义迭代器的下一个元素,通常与__iter__
一起使用。
__add__(self, other)
: 定义对象相加的行为,使对象可以使用+
运算符相加。例如,object1 + object2
。
__sub__(self, other)
: 定义对象相减的行为,使对象可以使用-
运算符相减。
__eq__(self, other)
: 定义对象相等性的行为,使对象可以使用==
运算符比较。
__lt__(self, other)
: 定义对象小于其他对象的行为,使对象可以使用<
运算符比较。
__gt__(self, other)
: 定义对象大于其他对象的行为,使对象可以使用>
运算符比较。
__call__(self, other)
是一个特殊的方法(也称为“魔法方法”),它允许一个对象像函数一样被调用。
__str__ 和 __repr__ 方法用于定义对象的字符串表示形式。 __str__ 方法的作用是返回对象的可读性良好的字符串表示,通常用于用户友好的输出,比如当使用 print() 函数打印对象时会调用 __str__ 方法。而 __repr__ 方法的作用是返回对象的“官方”字符串表示,理想情况下,该字符串可以用来重新创建对象,方便调试和记录日志等场景。例如在交互式环境中直接输入对象时会调用 __repr__ 方法。
class Book:
def __init__(self, title, author):
self.title = title
self.author = author
def __str__(self):
return f"《{self.title}》 - {self.author}"
def __repr__(self):
return f"Book('{self.title}', '{self.author}')"
运算符重载允许我们定义自定义类的实例在使用运算符(如 + 、 * 等)时的行为。比如在下述 Vector 类中, __add__ 方法定义了向量相加的操作,当使用 + 运算符对两个 Vector 实例进行操作时,会调用 __add__ 方法; __mul__ 方法定义了向量与标量相乘的操作,使用 * 运算符时会调用 __mul__ 方法。这样就可以让自定义的 Vector 类像内置的数值类型一样进行运算。
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
__len__ 方法返回容器中元素的数量,当使用 len() 函数获取容器对象的长度时会调用该方法。 __getitem__ 方法允许通过索引(如 [index] )来访问容器中的元素,当使用类似 inventory[i] 的方式访问 Inventory 类的实例时会调用该方法。 __contains__ 方法用于判断容器中是否包含某个元素,当使用 in 关键字检查元素是否在容器中时会调用该方法。通过这些方法,自定义的 Inventory 类就可以像内置的容器类型(如列表、元组等)一样使用。
class Inventory:
def __init__(self):
self.items = []
def __len__(self):
return len(self.items)
def __getitem__(self, index):
return self.items[index]
def __contains__(self, item):
return item in self.items
__dict__
属性查看对象的所有属性
class Person:
def __init__(self, name):
self.name = name
p = Person("Alice")
print(p.__dict__) # {'name': 'Alice'}
class Dynamic:
pass
obj = Dynamic()
obj.new_attr = "动态添加的属性"
__slots__
优化限制实例能拥有的属性,节省内存
class Point:
__slots__ = ['x', 'y']
def __init__(self, x, y):
self.x = x
self.y = y
遵循命名约定:
公共属性:normal
保护属性:_protected
私有属性:__private
合理使用属性装饰器:
需要计算或验证时使用@property
保持简单属性直接访问
方法选择原则:
需要访问实例:实例方法
需要访问类但不依赖实例:类方法
既不访问类也不访问实例:静态方法
文档字符串:
为所有公共方法和属性添加docstring
class Calculator:
"""一个简单的计算器类"""
def add(self, a, b):
"""返回两个数字的和
Args:
a: 第一个数字
b: 第二个数字
Returns:
两数之和
"""
return a + b
Python中的属性和方法构成了面向对象编程的基础:
属性:
类属性 vs 实例属性
属性访问控制
动态属性管理
方法:
实例方法、类方法、静态方法
特殊方法(魔术方法)实现运算符重载
方法装饰器的使用
掌握这些概念后,你将能够:
设计更合理的类结构
实现更优雅的对象接口
编写更易维护的面向对象代码
充分利用Python的动态特性
面向对象编程是一个需要不断实践的领域,建议从简单的类开始,逐步尝试更复杂的设计模式,最终你将能够构建出强大而灵活的Python应用程序。