一、面向对象编程
1.1 面向过程与面向对象
面向过程:更加注重通过函数来组织代码,适合任务明确、结构简单的程序。
面向对象:则注重通过对象和类来组织代码,适合复杂且需要长期维护和扩展的大型项目。
面向过程和面向对象都是一种编程方式,只不过再设计上有区别。
三大基本特性:
封装:将数据和操作数据的代码组合在一起,并限制对外部的访问。
继承:一个类可以继承另一个类的属性和方法,避免重复代码。
多态:同一个方法可以作用于不同类型的对象,实现灵活的功能扩展。
1.2 类 和 对象
1.2.1 类的定义
类是用来创建对象的模板。类定义了对象的属性和方法。类本身并不代表一个具体的实体,而是对一类事物的抽象描述。
1.2.2 实例化对象
实例化对象是通过类创建对象的过程。每个通过类创建的对象都被称为该类的实例。实例是类的具体表现,每个实例可以有不同的属性值。
举例说明:
我们可以将学生看作一个类,在这个类中定义了学生的属性和行为,比如学号、姓名等属性,以及写作业、玩耍等行为。
那么,当我们要描述具体一个学生时,就需要创建一个该类的对象,并根据需要设置其相应的属性值或对其进行行为操作。
另外,我们可以根据同一个类创建多个不同的对象,每个对象的属性值和行为可能都不同。例如大学生肯定不止一个学生。
class Stu(object):
id = '1001' # 类属性
name = '张三' # 类属性
def __init__(self):
pass # 构造函数,这里没有任何操作
def fun1(self):
pass # 实例方法,这里没有任何操作
# 创建两个对象 s1 和 s2
s1 = Stu()
s2 = Stu()
# 打印对象的 name 属性
print(s1.name) # 输出:张三
print(s2.name) # 输出:张三
1.2.3 访问属性/方法
# 访问属性
对象名.属性
# 访问方法
对象名.方法名()
1.2.4 对象与类的关系
对象拥有类的所有属性和方法
对象的属性和方法可以单独添加、删除、修改
对象与对象之间的属性和方法不可共享
对象不能独自创建,必须依托于类,类可以实例化N个对象
举例说明1:
class Stu(object):
id = '1001' # 类属性
name = '张三' # 类属性
def fun1(self):
pass # 方法,暂时没有实现
# 实例化对象
s1 = Stu()
s2 = Stu()
# 对象的属性可以单独修改、添加、删除
s1.name = '李四' # 修改实例属性 'name'
s1.age = 18 # 添加实例属性 'age'
del s1.age # 删除实例属性 'age'
print(s1.name) # 输出:李四
print(s2.name) # 输出:张三
类定义了共享的属性和行为,而对象则可以根据需要修改自己的属性。每个对象都有自己独立的实例属性,但它们共享类属性,除非这些类属性被对象单独修改。
举例说明2:
from types import MethodType
class Stu(object):
id = '1001'
name = '张三'
def fun1(self):
print(f"{self.name}会吃饭")
def fun2(self):
print(f"{self.name}会学习")
# 实例化对象
s1 = Stu()
s2 = Stu()
# 修改实例的属性
s1.name = '刘德华'
s2.name = '蔡徐坤'
# 调用类中定义的方法
s1.fun1() # 输出:刘德华会吃饭
s2.fun1() # 输出:蔡徐坤会吃饭
# 定义新的方法
def sing(self):
print(f"{self.name}会唱歌")
def dance(self):
print(f"{self.name}会跳舞")
# 使用 MethodType 动态绑定方法到对象
s1.sing = MethodType(sing, s1)
s2.dance = MethodType(dance, s2)
# 调用动态绑定的方法
s1.sing() # 输出:刘德华会唱歌
s2.dance() # 输出:蔡徐坤会跳舞
类提供了共享的行为和属性,而对象则可以继承这些行为,并且可以在运行时对自身的属性和方法进行扩展或修改。
二、魔方方法——构造函数 与 析构函数
1.1 __init__构造函数
构造函数是用来初始化对象的特殊方法。在 Python 中,构造函数的名称是 __init__
,它会在创建对象时被自动调用,用来初始化对象的属性。
__init__ 方法在每次创建新对象时都会被调用。
self 代表当前对象本身,可以用它来初始化实例属性
class Dog:
# 构造函数
def __init__(self, name, age):
self.name = name # 初始化实例属性 name
self.age = age # 初始化实例属性 age
def introduce(self):
print(f"我的名字是 {self.name}, 我 {self.age} 岁。")
# 创建对象时,构造函数会被自动调用
dog1 = Dog("A", 3)
dog2 = Dog("B", 5)
dog1.introduce() # 输出:我的名字是 A, 我 3 岁。
dog2.introduce() # 输出:我的名字是 B, 我 5 岁。
1.2 __del__ 析构函数
删除对象时执行一些操作,自动执行。
class Dog:
# 构造函数
def __init__(self, name, age):
self.name = name
self.age = age
# 析构函数
def __del__(self):
print(f"狗 {self.name} 已销毁")
# 创建对象
dog1 = Dog("A", 3)
# 删除对象
del dog1 # 调用析构函数,输出:狗 A 已销毁
1.3 __str__ 打印方法:输出执行信息,自动执行。
class Dog:
def __init__(self, name, age):
self.name = name
self.age = age
# 自定义 __str__ 方法
def __str__(self):
return f"这是一只名叫 {self.name} 的狗,它 {self.age} 岁。"
# 创建一个 Dog 对象
dog = Dog("Buddy", 3)
# 使用 print() 打印对象,会自动调用 __str__ 方法
print(dog) # 输出:这是一只名叫 Buddy 的狗,它 3 岁。
三、类属性/方法 与 实例对象属性/方法 与 静态方法
1.1 类属性和实例属性
1.1.1 类属性
类属性是属于整个类的属性,而不是某个具体的实例。它被类的所有实例共享。
类属性通过类名访问,也可以通过实例访问,但修改类属性时会影响所有实例。
如果你改变了类属性的值,它会影响到所有实例。
1.1.2 实例属性
实例属性是绑定到每个实例的属性,每个实例都有自己的属性值。
每次创建一个实例时,都会调用 __init__ 方法来初始化实例属性。
实例属性只能通过实例来访问和修改,不能通过类来访问。
举例说明:
class Car(object):
# 类属性
wheels = 4
def __init__(self, name, color):
# 实例属性
self.name = name
self.color = color
# 创建两个实例
car1 = Car("奥迪", "黑色")
car2 = Car("宝马", "白色")
# 访问类属性
print(Car.wheels) # 输出: 4
# 访问实例属性
print(car1.name) # 输出: 奥迪
print(car2.color) # 输出: 白色
# 修改类属性
Car.wheels = 6
print(car1.wheels) # 输出: 6
print(car2.wheels) # 输出: 6
1.2 类方法和实例方法
1.2.1 类方法
使用@classmethod进行修饰,第一个参数传入cls参数,表示类本身,用于访问类本身的属性
类方法内,只能调用类属性和类方法
可以通过类名调用、对象名调用
class Car(object):
wheels = 4 # 类属性
def __init__(self, name, color):
self.name = name
self.color = color
# 类方法
@classmethod
def change_wheels(cls, num):
cls.wheels = num
print(f"所有车的轮子数都改为 {cls.wheels}")
# 调用类方法
Car.change_wheels(6) # 输出: 所有车的轮子数都改为 6
Car.change_wheels(6) # 输出: 所有车的轮子数都改为 6
1.2.2 实例方法
第一个参数传入self参数,没有实例化前不能调用;实例化后,也多用对象调用而不是类调用
class Car(object):
def __init__(self, name, color):
self.name = name
self.color = color
# 实例方法
def drive(self):
print(f"{self.name}正在开动,颜色是{self.color}")
# 创建 Car 类的实例
car = Car("奥迪", "黑色")
Car.drive(car) # 输出: 奥迪正在开动,颜色是黑色
car.drive() # 输出: 奥迪正在开动,颜色是黑色
1.3 静态方法
静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等
使用 @staticmethod 装饰器来定义静态方法。
class Student(object):
"""
定义了一个学生类
"""
grade = 'py24101'
def __init__(self, name, age):
self.name = name
self.age = age
@staticmethod
def sta_fun(x):
print(f"{x}静态方法一般实现与类和对象无关联的操作,例如:游戏说明书等")
s1 = Student('张三', 18)
# 如何调用静态方法
Student.sta_fun(1)
s1.sta_fun(1)
四、类的封装【私有属性与方法】
封装是类的三大特性之一。
封装指的是隐藏对象中一些不希望让外部所访问的属性或方法。
python中封装其实是通过设置访问权限来体现的,私有属性和私有方法是控制访问权限的组成部分。
1.1 私有属性和私有方法
私有属性和方法是以双下划线(__
)开头的,它们只能在类的内部访问,外部无法直接访问或修改。这种封装机制确保了类的内部实现细节不会被外部直接修改,增强了数据的安全性。
class Bank(object):
"""
定义了一个银行卡类
属性:
name: 客户的名字
__pwd: 客户的密码(私有属性,不希望外部直接访问)
"""
def __init__(self, name, pwd):
"""
构造函数,初始化 Bank 对象的属性
参数:
name (str): 客户的名字
pwd (str): 客户的密码
"""
self.name = name # 客户的名字,是一个公有属性
self.__pwd = pwd # 客户的密码,是一个私有属性(前缀加双下划线)
def __info(self):
"""
一个私有方法,用于显示银行卡信息,包括名字和密码
注意:这个方法是私有的,外部不能直接调用
"""
print(f"名字{self.name}, 密码{self.__pwd}")
def get_info(self):
"""
公有方法,提供对外接口来获取银行卡信息
通过此方法间接调用 __info 方法
"""
self.__info() # 调用私有方法 __info 来显示信息
# 下面是创建 Bank 类对象并使用方法的示例:
b1 = Bank('李四', '123456') # 创建 Bank 类的实例,传入名字和密码
# Bank.__info() # 会报错,因为 __info 是私有方法,不能在类外直接访问
# b1.__info() # 会报错,因为 __info 是私有方法,不能在实例外直接访问
# 通过公有方法 get_info 来间接访问和显示信息
b1.get_info() # 输出: 名字李四, 密码123456
1.2 属性装饰器
属性装饰器是实现把方法转为属性的装饰器。
作用:
把方法转为属性,便于操作属性
实现对属性的更改(验证)、查看、删除
举例说明:
class Student(object):
def __init__(self, name):
self.__name = name # 私有属性,存储学生的名字
@property
def name(self):
"""
getter 方法,获取学生的名字
通过 @property 装饰器将这个方法变为一个属性,可以像访问属性一样获取名字
"""
return self.__name
@name.setter
def name(self, new_name):
"""
setter 方法,设置学生的名字
通过 @name.setter 装饰器提供修改名字的功能
"""
if not isinstance(new_name, str): # 判断传入的名字是否是字符串
print('名字必须是一个字符串') # 如果不是字符串,打印错误提示
else:
self.__name = new_name # 如果是字符串,更新学生名字
@name.deleter
def name(self):
"""
deleter 方法,删除学生的名字
通过 @name.deleter 装饰器提供删除名字的功能
"""
print("已删除名字") # 删除名字时打印提示
del self.__name # 删除 __name 属性
# 实例化一个 Student 对象
s1 = Student('张三')
# 打印学生的名字
print(s1.name) # 输出: 张三
# 尝试将名字设置为一个非字符串类型(数字)
s1.name = 111 # 输出: 名字必须是一个字符串
# 正常修改名字为 '李四'
s1.name = '李四'
print(s1.name) # 输出: 李四
# 删除名字
del s1.name # 输出: 已删除名字
五、类的继承
面向对象的编程带来的主要好处之一就是代码的重用,实现这种重用的方法之一就是通过继承机制。
1.1 类的继承的基本概念
父类(基类):被继承的类,包含一些共有的属性和方法。
子类(派生类、超类):继承父类的类,可以复用父类的属性和方法,并可以增加或修改一些新的属性和方法。
举例说明1:
class Parent(object):
"""
定义父类
"""
par_attr = 100
def __init__(self):
print("初始化父类")
def par_fun1(self):
print("父类方法1")
def par_fun2(self):
print("父类方法2")
class Child(Parent):
"""
定义子类
"""
child_attr = 666
def __init__(self):
print("初始化子类")
def child_fun1(self):
print("子类方法1")
# 创建一个 Child 类的实例 c1
c1 = Child() # 输出:初始化子类
# 输出:初始化父类 (自动调用父类的 __init__ 方法)
# 访问并打印子类的属性 child_attr
print(c1.child_attr) # 输出:666
# 调用并执行子类的方法 child_fun1
c1.child_fun1() # 输出:子类方法1
# 访问并打印父类的属性 par_attr
print(c1.par_attr) # 输出:100
# 调用并执行父类的方法 par_fun1
c1.par_fun1() # 输出:父类方法1
# 调用并执行父类的方法 par_fun2
c1.par_fun2() # 输出:父类方法2
1.2 多继承语法
如果在继承的元组()里面有一个以上的类,就称之为多继承。
class A:
pass
class B:
pass
class C:
pass
class D(A, B, C):
pass
d1 = D()
print(D.mro())
# python中提供了一个函数mro()用于查看继承的顺序。
1.3 继承重写父类方法
如果你的父类方法不能满足你得要求,你可以在子类中重写父类的方法。
# 定义父类 Animal
class Animal:
def speak(self):
print("Animal makes a sound") # 父类方法,所有动物都会发出这种声音
# 定义子类 Dog 继承 Animal
class Dog(Animal):
def speak(self):
print("狗 汪汪") # 重写父类方法,狗发出 "汪汪" 声音
# 定义子类 Cat 继承 Animal
class Cat(Animal):
def speak(self):
print("猫 喵喵") # 重写父类方法,猫发出 "喵喵" 声音
# 创建 Dog 和 Cat 类的实例
dog = Dog()
cat = Cat()
# 调用它们的 speak 方法
dog.speak() # 输出: Dog barks
cat.speak() # 输出: Cat meows
1.4 python继承特点
在子类中如果需要父类的构造方法,需要显式调用父类的构造方法,或者不重写父类的构造方法。__init__()
在子类中调用父类的方法,需要显式调用,且第一个参数self不能省略。
六、类的多态
python中的多态也可以通过方法重写进行。
同一个方法,不同对象显式的结果不同。
# 定义父类 Animal
class Animal:
def speak(self):
print("Animal makes a sound") # 父类方法,所有动物都会发出这种声音
# 定义子类 Dog 继承 Animal
class Dog(Animal):
def speak(self):
print("狗 汪汪") # 重写父类方法,狗发出 "汪汪" 声音
# 定义子类 Cat 继承 Animal
class Cat(Animal):
def speak(self):
print("猫 喵喵") # 重写父类方法,猫发出 "喵喵" 声音
# 创建 Dog 和 Cat 类的实例
dog = Dog()
cat = Cat()
# 调用它们的 speak 方法
dog.speak() # 输出: Dog barks
cat.speak() # 输出: Cat meows
结尾:
面向对象编程是现代编程的核心思想之一,无论是小型项目还是大型系统,理解并应用 OOP 都是开发者的必备技能。希望本文能够帮助你加深对 OOP 的理解,提升你的编程水平。
如果你对 Python 面向对象编程有任何问题或想法,欢迎在评论区交流讨论。愿你在编程的道路上越走越远,继续探索更多的技术与工具!
标签:__,name,Python,self,面向对象,理解,print,def,属性 From: https://blog.csdn.net/qq_65009672/article/details/143749704