python数据类型-7-自定义类型-class-面向对象编程
一.说明
在python数据类型系列文章中已经介绍了 基础数据类型,容器类型 列表,元组,字典,集合等,今天我们一起来对自定义类型class类进行梳理,介绍class 其实就是要介绍python面向对象编程(OOP)
二.什么是面向对象
面向对象是一种思维方式,它认为万事万物皆对象,程序是由多个对象协作共同完成功能的,所以以后我们要从面向 过程转向面向对象。以面向对象的方式考虑程序的构建。面向对象的核心是:类和对象
类:类是抽象的,我们可以理解为 抽象的生产汽车工厂,比如汽车类 需要传入品牌 颜色 等 ;
对象:对象是类的实例,比如给汽车类传入初始化参数 比如 品牌 :宝马 ,颜色:金色,就给我们返回一个类的实例 金色的宝马
二.class(类)
1.定义
1.在 Python 中,类通过
class
关键字定义;2.类的构成包含类的名称 类的属性 类的方法;
3.类名一般使用大驼峰命名 MyCar
4.类体必须进行缩进
5.在Python3中类默认继承object,所以class MyCar(object): 可以简写为class MyCar:
2.特性
1.封装:将数据(属性)和行为(方法)结合在一起,提供对外部的接口;
2.继承:允许一个类继承另一个类的属性和方法,增强代码重用性;
3.多态:允许不同类的实例以相同的方式调用方法,简化代码结构;
4.更好的组织性:通过将相关的属性和方法组织在类中,代码结构更加清晰;
5.提高可维护性:修改一个类的实现通常不会影响到使用该类的代码,降低了对其他部分代码的影响;
6.适应变化:可以轻松添加新功能,例如通过继承和多态,不需要改变现有代码的情况下扩展系统;
3.创建类
-
创建对象的格式为:对象名 = 类名()
class MyCar: ''' 这是python中一个类的定义 ''' __slots__ = ('name','color') def __init__(self,name,color): self.name = name self.color = color def run(self): print(f'{self.name}:在跑') _bm = MyCar('宝马','金色') _bm.run()
-
构造方法
__init__
构造方法用于初始化对象的属性,它在创建对象时自动调用。
当然也可以不定义,系统会生成一个无参构造方法
class 类名: def __init__(self): pass
那么我们对构造方法需要通过以下维度来学习。
-
语法:def init(self):
-
目的:构造方法用于初始化对象,可以在构造方法中添加成员属性
-
调用:构造函数由系统在实例化对象时自动调用,不要自己调用
-
参数:第一个参数必须是self,其它参数根据需要自己定义
-
返回值:不返回值,或者说返回None,不应该返回任何其他值
-
是否需要自己定义构造方法:没有定义构造方法,系统会生成一个无参构造方法
-
一个类只能有一个构造方法:如果定义多个,后面的会覆盖前面的
def __init__(self,name,color): self.name = name self.color = color
-
-
析构方法
析构方法在 Python 中是用来清理对象的。当一个对象不再被使用并且被垃圾回收时,析构方法 __del__
会被调用。
语法:def del(self):
调用:对象销毁时由系统自动调用
参数:除了self外,没有其他参数
返回值:不返回值,或者说返回None
class FileHandler:
def __init__(self, filename):
self.filename = filename
self.file = open(self.filename, 'w') # 打开文件进行写入
print(f"File {self.filename} opened.")
def write(self, content):
self.file.write(content) # 向文件写入内容
def __del__(self):
if self.file:
self.file.close() # 关闭文件
print(f"File {self.filename} closed.")
# 使用示例
handler = FileHandler("example.txt")
handler.write("Hello, world!")
# 当 handler 变量超出作用域或被删除时,__del__ 方法会被调用
del handler # 手动删除对象,触发析构方法
-
实例方法 def run(self):
实例方法是与对象相关的方法,第一个参数通常是
self
class Dog: def __init__(self, name, age): self.name = name self.age = age def bark(self): # 实例方法 return f"{self.name} says Woof!" # 创建一个 Dog 实例 my_dog = Dog("Buddy", 3) # 调用实例方法 print(my_dog.bark()) # 输出:Buddy says Woof!
-
声明实例所需要的属性
当一个类需要创建大量实例时,可以通过 slots 声明实例所需要的属性,如果超过了此属性范围进行对象属性 赋值,就会限制,起到保护数据作用。
当不用__slots__声明 可对实例动态添加属性
那么问题来了为什么要用? slots = (‘name’,‘color’) 来限制属性,我们在接触其他语言时也会发现类的属性时被强制限定的,那么为什么要这么做?除了保证实例结构安全还有哪些优点呢?
这样做带来以下优点:
- 更快的属性访问速度
- 通过取消 dict 的使用减少内存消耗
- 保护数据安全性
# __slots__ = ('name','color') class MyCar: def __init__(self,name,color): self.name = name self.color = color def run(self): print(f'{self.name}:在跑') _bm = MyCar('宝马','金色') _bm.max_speed=400 _bm.run() # 宝马:在跑 print(_bm.max_speed) # 400 ########################## class MyCar: ''' 这是python中一个类的定义 ''' __slots__ = ('name','color') def __init__(self,name,color): self.name = name self.color = color def run(self): print(f'{self.name}:在跑') _bm = MyCar('宝马','金色') _bm.max_speed=400 #报错 AttributeError: 'MyCar' object has no attribute 'max_speed'
-
私有属性(Private Attributes)
私有属性是类内部的属性,通常以双下划线 (
__
) 开头,以指示该属性不应从类的外部访问。这是 Python 中一种约定,用于实现封装和数据保护。class Example: def __init__(self, value): self.name = value # 私有属性 def get_private_attribute(self): return self.__private_attribute # 通过方法访问私有属性 def set_private_attribute(self,value): self.__private_attribute = value obj = Example(10) obj.set_private_attribute(600) print(obj.get_private_attribute()) # 输出:10 print(obj.__private_attribute) # 报错: AttributeError: 'Example' object has no attribute '__private_attribute'
-
专有属性(Protected Attributes)
专有属性是用单下划线 (
_
) 开头的属性,通常表示这些属性是受保护的,应该在类及其子类中访问,而不是在外部直接访问。这是 Python 的一种约定,而不是严格的访问控制,但仍然可以访问。class Example: def __init__(self, value): self._protected_attribute = value # 专有属性 def get_protected_attribute(self): return self._protected_attribute # 通过方法访问专有属性 class SubClass(Example): def display(self): print(self._protected_attribute) # 子类可以访问专有属性 obj = SubClass(20) obj.display() # 输出:20 print(obj.get_protected_attribute()) # 输出:20
总结:
1.私有属性(以
__
开头)是用于封装和保护数据的,不能从类外部直接访问。2.专有属性(以
_
开头)是受保护的,应该在类及其子类中使用,外部代码不应直接访问,但仍然可以访问。 -
类方法
@classmethod
类方法是与类本身相关的方法,而不是与特定实例相关。它使用
@classmethod
装饰器。注意:第一个参数通常是
cls
,表示类本身。1.类方法的第一个参数是类对象cls,那么通过cls引用的 必定是类对象的属性和方法;
2.实例方法的第一个参数是实例对象self,那么通过self引用的可能是类属性、也有可 能是实例属性;
3.存在相同名称的类属性和实例属性的情况下,实例属性优先级更高。
class Dog: species = "Canine" # 类属性 def __init__(self, name, age): self.name = name self.age = age @classmethod def get_species(cls): # 类方法 return cls.species # 调用类方法 print(Dog.get_species()) # 输出:Canine
-
静态方法
静态方法是与类本身相关的方法,而不是与类的实例相关。静态方法不需要访问或修改类的属性,因此不需要
self
参数。静态方法使用@staticmethod
装饰器定义。class Math: @staticmethod def add(a, b): # 静态方法 return a + b # 调用静态方法 result = Math.add(5, 10) print(result) # 输出:15
-
一个完整的实例 实现 类的封装 多态 继承
封装确保了对象的内部状态被保护,用户只能通过方法来与之交互。
继承允许子类重用父类的代码,并且强制子类实现某些方法。
多态使得可以通过统一的接口来处理不同类型的对象,增强了代码的灵活性和可扩展性。
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚“鸭子类型”。 所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态 Python “鸭子类型”
class Animal: def __init__(self, name): self.name = name # 封装了动物的名字 def speak(self): raise NotImplementedError("Subclass must implement abstract method") ''' Dog 和 Cat 类都继承自 Animal 类。它们都拥有 Animal 的属性 name,并且可以使用 Animal 的构造函数来初始化这些属性。 ''' class Dog(Animal): def speak(self): #重写父类方法 return "Woof!" # 具体实现 ''' Dog 和 Cat 类实现了 speak 方法,这是 Animal 类中的一个抽象方法(通过抛出 NotImplementedError 实现)。这意味着任何继承自 Animal 的类都必须实现 speak 方法。 ''' class Cat(Animal): def speak(self): #重写父类方法 return "Meow!" # 具体实现 ''' 多态是指不同类的对象可以使用相同的接口调用各自的方法,而具体的实现可以不同。在这段代码中,多态的体现主要在 animal_sound 函数中 ''' def animal_sound(animal): print(f"{animal.name} says: {animal.speak()}") # 使用示例 dog = Dog("Buddy") cat = Cat("Whiskers") ''' 在这两个调用中,dog 和 cat 是 Dog 和 Cat 的实例。尽管它们调用的是同一个 animal_sound 函数,但它们各自的 speak 方法提供了不同的实现,展现了多态的特性。 ''' animal_sound(dog) # 输出:Buddy says: Woof! animal_sound(cat) # 输出:Whiskers says: Meow!
-
将类中的方法转换为属性
@property
装饰器为什么是将方法转换为属性?既然是方法,那么转换为属性时,可以添加一些逻辑,作用如下
-
简化接口:使用
@property
可以让方法以属性的方式访问,使得调用更直观。 -
封装逻辑:可以在获取或设置属性时添加自定义逻辑,而不需要改变外部接口。
-
只读属性:可以通过定义一个只带
@property
的方法来实现只读属性,防止外部代码直接修改属性值。
使用场景:
-
计算属性:有时某个属性的值是基于其他属性计算得出的,使用
@property
可以在访问该属性时动态计算其值。 -
数据验证:在设置属性值时,可以进行验证,确保赋值符合特定规则。
-
只读属性:当需要对属性提供只读访问时,可以使用
@property
而不定义 setter 方法。
class Circle: def __init__(self, radius): self._radius = radius # 使用下划线表示内部属性 @property def radius(self): return self._radius # 只读属性 @radius.setter def radius(self, value): if value < 0: raise ValueError("Radius cannot be negative") self._radius = value # 设置值时进行验证 @property def area(self): return 3.14 * (self._radius ** 2) # 动态计算面积 # 使用示例 circle = Circle(5) print(circle.radius) # 输出:5 print(circle.area) # 输出:78.5 circle.radius = 10 # 修改半径 print(circle.area) # 输出:314.0 # circle.radius = -5 # 会抛出 ValueError: Radius cannot be negative
-
三.总结
Python中数据类型 自定义类型class 在开发中有大量的应用,不管怎样都得掌握他,虽然class中的概念很多,但是我们初学习的时候有个印象就行了,后面实际开发多用,就掌握了;
这里要提一下学习方法:
第一要系统学习,系统学习不是要都掌握 是要有印象;
第二不要急于学习新知识,而是你已经掌握多少知识,有一句谚语!江里的大鲫鱼永远比不上手里的小泥鳅!
第三复习很重要,我在开始学习编程的时候就是拿本子记,不是应为我不会啥云文档 博客 markdown文档语法,而是因为我需要复习,而拿笔记本复习更实在更具体!!永远提醒我 要开始复习了!!云文档能提示我个啥!!
关于class我就写到这,有不足地方,欢迎大家补充,我来更新!
创作不易,喜欢的话点点关注 点点赞,再次_感谢!