目录
前言
面向对象是一种程序设计思想,面向过程也是一种程序设计hi思想,这是处理问题的思考角度不一样。
面向过程的思维就是需要注重的是这个事情的步骤和顺序,比较直接高效。
面向对象的思维就是要注重事情的参与者,需求什么对象以及每个对象都需要做哪些事情。将其拆解为一个个模块和对象。这样的设计思想会更容易维护和扩展。
-
类和实例
-
类:用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法
-
实例(对象):根据类映射出的一个个具体的对象
-
类方法:整个类共有的功能
-
类属性:整个类共有的属性
-
实例方法:属于每个对象的功能
-
实例属性:属于每个对象的属性
-
# -*- coding: utf-8 -*-
class Student:
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
def eat(self):
print(f"{self.name}吃饭了")
li_hua = Student("梨花", 180, 80)
li_hua.eat()
__init__方法:实例初始化的方法,创建实例后自动调用,第一个参数为self为创建实例的本身。
学过c++的同学应该知道c++的类中有构造函数,python的__init__方法和构造函数的作用一样。
-
实例的属性和类的属性
在类的函数当中定义的变量都是对象的成员变量,如果要定义类的属性和类方法(使用 @classmethod
装饰器定义的方法)就要使用下面的方法
# -*- coding: utf-8 -*-
class Student:
stunum = 1 # 像这样将变量定义在函数外面就是类的属性
# 类的属性整个类共享
# 定义类的方法
@classmethod
def addstu(cls):
cls.stunum += 1
print("学生+1")
def __init__(self, name, height, weight):
self.name = name
self.height = height
self.weight = weight
def eat(self):
print(f"{self.name}吃饭了")
li_hua = Student("梨花", 180, 80)
li_hua.eat()
-
访问限制
- 单下划线
_
开头:使用单下划线开头命名的属性或方法,表示这是一个受保护的成员,建议外部代码不要直接访问它们,但仍然可以通过对象名访问。这种命名约定是一种约定俗成的做法,并不是真正的强制性限制。
class MyClass: def __init__(self): self._protected_variable = 10 # 受保护的属性 def _protected_method(self): print("This is a protected method.") # 受保护的方法
- 双下划线
__
开头:使用双下划线开头命名的属性或方法,表示这是一个私有成员,外部代码不能直接访问它们,而且子类也不能继承它们。Python 会对这些名称进行名称修饰(name mangling),以防止子类意外重写父类的私有成员。
- 单下划线
class MyClass:
def __init__(self):
self.__private_variable = 20 # 私有属性
def __private_method(self):
print("This is a private method.") # 私有方法
实际上,Python 并不会严格执行私有变量的访问限制,它只是将变量名称进行了名称修饰(name mangling),以防止外部代码意外修改私有变量。可以通过特殊的名称访问方式来访问私有变量,但不建议这样做,因为这会破坏封装性。
获取私有属性
如果想要让外部代码获取私有属性,可以定义方法
class MyClass:
def __init__(self):
self.__private_variable = 30 # 私有属性
def get_private_variable(self): # 定义获取私有属性的方法
return self.__private_variable
obj = MyClass()
print(obj.get_private_variable()) # 通过方法获取私有属性的值
也可以利用装饰器@property
class MyClass:
def __init__(self):
self.__private_variable = 30 # 私有属性
@property
def private_variable(self): # 使用@property装饰器定义私有属性的getter方法
return self.__private_variable
obj = MyClass()
print(obj.private_variable) # 通过属性的getter方法获取私有属性的值
这两种方式都允许外部代码访问私有属性,但是使用 @property
装饰器可以使代码更加清晰和优雅,因为它将属性的访问看作是属性的读取操作,而不是方法的调用。
修改私有属性
如果要修改私有属性,可以定义方法
class MyClass:
def __init__(self):
self.__private_variable = 30 # 私有属性
def set_private_variable(self, value): # 定义设置私有属性的方法
self.__private_variable = value
obj = MyClass()
print(obj.__dict__) # 输出对象的属性字典,确认私有属性存在
obj.set_private_variable(50) # 通过方法设置私有属性的值
print(obj.__dict__) # 输出修改后的属性字典,确认私有属性已修改
也可以用装饰器@xxx.setter
class MyClass:
def __init__(self):
self.__private_variable = 30 # 私有属性
@property
def private_variable(self): # 使用 @property 装饰器定义私有属性的 getter 方法
return self.__private_variable
@private_variable.setter
def private_variable(self, value): # 使用 @xxx.setter 装饰器定义私有属性的 setter 方法
self.__private_variable = value
obj = MyClass()
print(obj.__dict__) # 输出对象的属性字典,确认私有属性存在
obj.private_variable = 50 # 通过属性的 setter 方法设置私有属性的值
print(obj.__dict__) # 输出修改后的属性字典,确认私有属性已修改
需要注意的是:@xxx.setter
必须要配合只读装饰器@property
使用才能使用
-
类的内置属性
-
__dict__
:返回类的属性(字典类型,类的数据结构组成) -
__doc__
:类的文档字符串 -
__name__
:类名 -
__module__
:类定义所在的模块 -
__bases__
:类的所有父类析构元素 -
__mro__
:显示继承顺序
-
继承
面向对象编程的好处之一就是代码重用,如果子类的属性和方法含有父类的所有属性方法。就可以通过继承来实现代码重用。
通过继承创建的新类就是子类或派生类,被继承的类就是基类。
注意: python类的私有的属性、方法 ,不会被子类继承,也不能访问。
class Animal:
def __init__(self, name):
self.__name = name # 私有属性
def make_sound(self):
print("Animal makes a sound")
def __sleep(self): # 私有方法
print("Animal is sleeping")
class Dog(Animal):
def bark(self):
print("Woof! Woof!")
# 创建 Animal 对象
animal = Animal("Generic Animal")
# 创建 Dog 对象
dog = Dog("Fido")
# 调用基类的公共方法
animal.make_sound()
# 调用子类的公共方法
dog.make_sound()
dog.bark()
# 访问私有属性和方法
# 以下代码会导致 AttributeError
# print(dog.__name)
# dog.__sleep()
父类的方法不能满足需求时,可以在子类中重写方法
调用父类的方法
保留父类的属性并新增属性(初始化方法),或保留父类的某个方法的功能并增强的方法。
-
super(子类,self).方法名(参数)
-
super().方法名(参数)
-
父类名.方法名(self,参数)
class Animal:
def __init__(self, name):
self.name = name
def make_sound(self):
print("Animal makes a sound")
class Dog(Animal):
def __init__(self, name, breed): # 子类的初始化方法
super().__init__(name) # 调用父类的初始化方法,保留父类的属性
self.breed = breed # 新增属性
def make_sound(self):
super().make_sound() # 调用父类的方法
print("Dog barks")
# 创建 Dog 对象
dog = Dog("Fido", "Golden Retriever")
# 调用子类的方法,会保留父类的功能并增强
dog.make_sound()
多继承
使用方法:在子类的继承括号中用逗号分隔多个类
多个父类中有相同的方法名,并且子类没有该方法时,从左往右查找父类中的方法
class Parent1:
def common_method(self):
print("This is from Parent1")
class Parent2:
def common_method(self):
print("This is from Parent2")
class Subclass(Parent1, Parent2):
pass
# 创建子类对象
subclass = Subclass()
# 调用子类继承的方法
subclass.common_method()