对象(Object)
什么是对象?
对象是内存中专门用来存储数据的一块区域。对象中可以存放各种数据,比如数字、布尔值、代码。对象由三部分组成:
- 对象的标识(id)
- 对象的类型(type)
- 对象的值(value)
面向对象(OOP)
Python是一门面向对象的编程语言。所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的。
面向过程的编程语言
面向过程指将我们的程序的逻辑分解为一个一个的步骤,通过对每个步骤的抽象,来完成程序。例如,孩子上学的过程可以拆分为多个步骤:
- 妈妈起床
- 妈妈上厕所
- 妈妈洗漱
- 妈妈做早饭
- 妈妈叫孩子起床
- 孩子上厕所
- 孩子要洗漱
- 孩子吃饭
- 孩子背着书包上学校
面向过程的编程思想将一个功能分解为一个一个小的步骤,通过完成一个一个小的步骤来完成一个程序。这种编程方式比较简单,符合人类的思维。但是它的可复用性低,并且难于维护。
面向对象的编程语言
面向对象的编程语言关注的是对象,而不关注过程。对于面向对象的语言来说,一切都是对象。例如,孩他妈起床叫孩子上学。
面向对象的编程思想将所有的功能统一保存到对应的对象中,要使用某个功能,直接找到对应的对象即可。这种方式编写的代码容易阅读、易于维护,也容易复用。但是这种方式编写起来稍微麻烦一点,不太符合常规的思维。
综上所述,面向对象的编程思想主要包括两步:
- 找对象
- 搞对象
类(class)
在Python中,我们可以使用内置对象 (如int, float, str等) 来创建对象。但是,不能满足所有的需求,因此我们经常需要自定义一些对象。简单地说,类就相当于一个图纸。我们在程序中需要根据类来创建对象。也有人称对象是类的实例(instance)。如果多个对象是通过一个类创建的,我们称这些对象是一类对象,就像 int()、float()、bool()、str()、list()、dict() 之类的对象一样。在定义自己的类时,需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名。
#定义一个简单的类 class MyClass(): pass mc = MyClass()
使用类创建对象的流程
使用类来创建对象,就像调用一个函数一样。它的流程如下:
1.创建一个变量
2.在内存中创建一个新对象
3.将对象的id赋值给变量
类的定义
实际上,类和对象都是对现实生活中的事物或程序中的内容的抽象。在类的代码块中,我们可以定义变量和函数。变量会成为该类实例的公共属性,所有该类实例都可以通过 对象.属性名 的形式访问。函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法。在定义方法时,至少要定义一个形参。方法调用时,解析器会先在当前对象中寻找是否含有该属性或方法,如果没有,则去当前对象的类对象中去寻找。如果类对象中依然没有,则报错。
#定义一个简单的人类 class Person : name = 'swk' # 公共属性,所有实例都可以访问 def say_hello(self) : print('你好!我是 %s' %self.name) p1 = Person() p2 = Person() p1.name = '猪八戒' p1.say_hello() # '你好!我是 猪八戒' p2.say_hello() # '你好!我是 swk'
代码演示
#定义一个简单的类 class MyClass(): pass #使用MyClass创建一个对象 mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例 mc_2 = MyClass() mc_3 = MyClass() mc_4 = MyClass() # isinstance()用来检查一个对象是否是一个类的实例 result = isinstance(mc_2,MyClass) #现在我们通过MyClass这个类创建的对象都是一个空对象 #也就是对象中实际上什么都没有,就相当于是一个空的盒子 #可以向对象中添加变量,对象中的变量称为属性 #语法:对象.属性名 = 属性值 mc.name = '孙悟空' mc_2.name = '猪八戒' print(mc_2.name) #定义一个简单的人类 class Person : name = 'swk' # 公共属性,所有实例都可以访问 def say_hello(self) : print('你好!我是 %s' %self.name) p1 = Person() p2 = Person() p1.name = '猪八戒' p1.say_hello() # '你好!我是 猪八戒' p2.say_hello() # '你好!我是 swk'
初始化方法和实例属性
在类中,我们可以定义一个特殊的方法,称为初始化方法(init),它会在创建一个对象时自动调用。初始化方法可以接受参数,并将这些参数赋值给对象的属性。通过这种方式,我们可以为每个对象设置不同的初始值。
class Person: def __init__(self, name, age): self.name = name self.age = age def say_hello(self): print(f"你好!我是{self.name},今年{self.age}岁。")
在上面的代码中,我们定义了一个Person
类,它有两个实例属性:name
和age
。初始化方法接受两个参数,并将它们分别赋值给对象的属性。通过创建对象并调用say_hello
方法,我们可以访问和修改这些属性。
类属性和类方法
除了实例属性和实例方法,类还可以有类属性和类方法。
类属性是属于类本身的属性,而不是属于实例的属性。所有该类的实例都可以访问和修改类属性。
class Person: count = 0 # 类属性 def __init__(self, name): self.name = name Person.count += 1 # 每创建一个实例,count加1 @classmethod def get_count(cls): return cls.count # 使用cls访问类属性
在上面的代码中,我们定义了一个count
类属性,它记录了创建的实例个数。每当创建一个实例时,通过初始化方法将类属性count
加1。通过类方法get_count()
,我们可以获取到目前创建的实例个数。
继承和多态
Python中的类还支持继承,一个类可以从另一个类继承属性和方法。子类可以重写父类的方法,实现多态的效果。
class Animal: def __init__(self, name): self.name = name def speak(self): pass class Dog(Animal): def speak(self): print(f"{self.name}汪汪叫") class Cat(Animal): def speak(self): print(f"{self.name}喵喵叫")
在上面的代码中,我们定义了一个Animal
类,它有一个speak
方法。然后,我们定义了Dog
和Cat
两个子类分别继承Animal
类。子类可以重写父类的方法,这就是多态的一种体现。通过创建Dog
和Cat
对象,我们可以调用它们各自的speak
方法。
魔术方法
除了初始化方法(init)之外,Python中还有许多特殊方法,也被称为魔术方法(magic methods)。这些特殊方法以双下划线开头和结尾,它们在特定的时刻自动调用。
class Person: def __init__(self, name): self.name = name def __str__(self): return f"Person对象:{self.name}" def __eq__(self, other): return self.name == other.name
在上面的代码中,我们定义了两个魔术方法:__str__
和__eq__
。
__str__
方法用于定义对象的字符串表示。当调用print
函数或使用str()
函数时,会自动调用该方法并返回一个字符串表示。__eq__
方法用于定义对象的相等性。它接受另一个对象作为参数,并根据自定义的逻辑判断两个对象是否相等。
通过实现这些魔术方法,我们可以更好地控制对象的行为,并使其更符合我们的预期。
小结
在本章中,我们介绍了Python类的基本概念和用法。从初始化方法到实例属性、类属性、类方法、继承和多态,我们一步步深入了解了类的各种特性和用法。同时,我们还了解了魔术方法的作用和用法,可以通过实现这些方法来定制类的行为。
类的封装性
在面向对象的编程中,封装是一种重要的概念。它指的是将数据和方法组合成一个单一的实体,并对外部隐藏具体的实现细节。
Python中的类提供了封装的机制。我们可以使用访问修饰符来控制属性和方法的可访问性。
- 公有访问修饰符:没有使用任何修饰符,所有属性和方法默认为公有。公有属性和方法可以在类内部和外部访问。
- 私有访问修饰符:使用双下划线(__)作为前缀来定义私有属性和方法。私有属性和方法只能在类内部访问,无法在类外部直接访问。
class Person: def __init__(self, name): self.__name = name # 私有属性 def __say_hello(self): # 私有方法 print(f"你好!我是{self.__name}。") def greet(self): self.__say_hello()
在上面的代码中,name
和say_hello
都是私有成员。使用双下划线作为前缀可以定义私有属性和方法。在类的内部,我们可以直接访问这些私有成员。而在类的外部,无法直接访问私有成员,但可以通过公有方法间接访问。
属性的访问器和设置器
除了直接访问属性,我们还可以使用属性访问器(getter)和属性设置器(setter)来控制对属性的访问和修改。
class Person: def __init__(self, name): self.__name = name @property def name(self): # 属性访问器 return self.__name @name.setter def name(self, value): # 属性设置器 if isinstance(value, str): self.__name = value else: raise ValueError("姓名必须是字符串类型")
在上面的代码中,我们使用@property
装饰器定义了一个属性访问器,名为name()
。通过访问obj.name
,我们可以获取私有属性__name
的值。然后,我们使用@name.setter
装饰器定义了一个属性设置器,名也为name()
。通过赋值obj.name = value
,我们可以修改私有属性__name
的值。
这样做的好处是,在外部使用对象属性时,我们可以像访问普通属性一样,而无需直接访问私有属性。
小结
在本文中,我们介绍了Python类的封装性和属性访问控制。通过使用访问修饰符、私有属性和方法,我们可以隐藏类的具体实现细节,并提供公有接口供外部使用。我们还学习了如何使用属性访问器和设置器来控制对属性的访问和修改。
总结
本文介绍了面向对象编程中的一些重要概念和技术,包括对象、类、继承、多态、魔术方法等。通过使用类和对象,我们可以将数据和方法组合成一个单一的实体,实现代码的封装和复用。
在面向过程的编程语言中,主要关注程序的过程和函数。而在面向对象的编程语言中,我们将程序分解成一个个的对象,每个对象都有自己的数据和方法。这种方式更加灵活和易于理解。
类是对象的模板,通过定义类可以创建出多个实例对象。类由属性和方法组成,属性存储对象的数据,方法定义对象的行为。
初始化方法和实例属性用于在创建对象时初始化对象的状态。类属性是所有实例共享的属性,类方法是作用于整个类而非单个实例的方法。
继承和多态是面向对象编程中的两个重要概念。通过继承,我们可以创建新的类并从现有的类继承属性和方法。多态允许不同的对象对相同的方法进行不同的实现,提高了代码的灵活性和可扩展性。
魔术方法是Python中特殊命名的方法,用于实现特定的功能或行为,如初始化、比较、运算符重载等。
此外,本文还介绍了类的封装性和属性的访问控制。通过使用访问修饰符、私有属性和方法,可以隐藏类的具体实现细节,并提供公有接口供外部使用。属性访问器和设置器可以控制对属性的访问和修改,增加了代码的安全性和可维护性。
总而言之,面向对象编程是一种强大的编程范式,通过将程序分解成对象的方式,可以实现代码的模块化、复用和灵活性。掌握类的定义、继承、多态、魔术方法等概念和技术,能够编写出更加结构化和可扩展的代码。