赞
踩
1.理解面向过程编程和面向对象编程思想
2.明确类和对象的关系,会独立设计和使用类
3.会使用类创建对象,并添加属性
4.掌握类的属性和方法
5.掌握构造方法和析构方法的使用
重点
1.self的使用
2.构造方法和析构方法
3.类属性和实例属性
4.方法的重载
面向过程:先分析解决问题的步骤,使用函数把这些步骤以此实现,使用的时候需要逐个调用函数 。
面向对象:把解决问题的事物分为多个对象 ,对象具备解决问题过程中的行为。
我认为面向过程,就好像自己亲力亲为做一件事,先做什么再做什么。
面向对象就好像自己培养有能力的人来为你做这件事。
1:面向对象编程有两个非常重要的概念:类和对象。
2:对象是面向对象编程的核心。
3:具有相似特征和行为的事物的集合统称为类
4:对象是根据类创建的,一个类可以对应多个对象。
理解起来类就像是一个模具,而对象就是依据类这个模具生产出来的东西。
对象的定义 某种事物的抽象(功能)
抽象原则包括数据抽象和过程抽象两个方面
1:数据抽象-定义对象属性;
2:过程抽象-定义对象操作。
封装 | 把客观事物抽象并封装成对象 |
继承 | 允许使用现有类的功能,并在无需重新改写原来的类的情况下,对这些功能进行扩展 |
多态 | 对象可以表示多个类型的能力 |
类的名称 | 类名,首字母必须大写,比如Person |
类的属性 | 一组数据,比如性别 |
类的方法 | 允许进行操作的方法,比如说话 |
使用class关键字来声明一个类,基本格式如下
- class 类名:
-
- 类的属性
-
- 类的方法
根据类创建对象的语法格式如下:
对象名 = 类名()
要想给对象添加属性,可以通过如下方式:
对象名.新的属性名 = 值
代码演示
- class Person1:#定义类Person1
- pass#为空语句占位
- p1=Person1()
- print(Person1,type(Person1),id(Person1))
- print(p1,type(p1),id(p1))
-
- <class '__main__.Person1'> <class 'type'> 2085640536560
- <__main__.Person1 object at 0x000001E59A917AA0> <class '__main__.Person1'> 2085652363936
这段代码定义了一个名为 Person1
的类,然后创建了一个该类的实例 p1
。
print(Person1, type(Person1), id(Person1))
:
Person1
的值是 <class '__main__.Person1'>
,表示 Person1
是一个类对象。type(Person1)
返回的是 <class 'type'>
,表示 Person1
的类型是类对象的类型,即 type 类型。id(Person1)
返回的是 2085640536560
,这是 Person1
的内存地址,用于标识 Person1
在内存中的位置。print(p1, type(p1), id(p1))
:
p1
的值是 <__main__.Person1 object at 0x000001E59A917AA0>
,表示 p1
是一个 Person1 类的对象,并给出了该对象的内存地址。type(p1)
返回的是 <class '__main__.Person1'>
,表示 p1
的类型是 Person1 类的实例。id(p1)
返回的是 2085652363936
,这是 p1
的内存地址,用于标识 p1
在内存中的位置。总体来说,这段代码显示了类对象 Person1
和类实例对象 p1
的信息,包括它们的类型和内存地址。
id()
内存地址是计算机在内存中存储变量数据的位置。在 Python 中,id()
函数返回的是对象的内存地址,它是唯一的,用于标识一个对象。
通过“实例.属性”添加的属性都是实例属性
通过self.变量名定义的属性。
定义类,定义成员变量。
- def __init__(self):
- #实例属性
- self.age = 1
在 Python 中,实例属性是与特定类的每个实例相关联的属性。self
参数在类的方法中用于引用这些实例属性。当你创建类的实例时,每个实例都会有自己的一组属性,而这些属性的值可能因实例而异。为了使每个实例都能访问和修改其自己的属性,Python 使用 self
参数来引用实例本身。
在类的方法中,通过 self
参数可以访问实例的属性和方法。当你调用一个实例方法时,Python 会自动将调用该方法的实例传递给 self
参数,使得方法内部能够访问实例的属性。这种机制使得类的方法能够操作特定实例的数据,而不是类本身的数据。
例如,在下面的代码中,self.name
和 self.age
分别表示 Person
类的实例的姓名和年龄属性:
- class Person:
- def __init__(self, name, age):
- self.name = name
- self.age = age
-
- def print_info(self):
- print("Name:", self.name)
- print("Age:", self.age)
-
- # 创建一个 Person 实例
- person1 = Person("Alice", 30)
-
- # 调用实例方法
- person1.print_info()
在 __init__()
方法中,self.name
和 self.age
将姓名和年龄属性绑定到创建的实例上。在 print_info()
方法中,通过 self.name
和 self.age
可以访问实例的姓名和年龄属性,并将它们打印出来。
- class Person2: #定义类Person2
- def __init__(self, name,age): #__init__方法
- self.name = name #初始化self.name,即成员变量name(域)
- self.age = age #初始化self.age,即成员变量age(域)
- def say_hi(self): #定义类Person2的函数say_hi()
- print('您好, 我叫', self.name) #在实例方法中通过self.name读取成员变量name(域)
- #测试代码
- p1 = Person2('张三',25) #创建对象
- p1. say_hi () #调用对象的方法
- print(p1.age) #通过p1.age(obj1.变量名)读取成员变量age(域)
在面向对象编程中,定义类是指创建一个类,这个类描述了一个抽象的概念或实体,其中包含了一组属性和方法。类是对象的模板,它定义了对象应该具有的特征和行为。
定义成员变量则是在类中定义变量,这些变量被称为类的成员变量或实例变量。成员变量存储在对象中,并且每个对象都有自己的一组成员变量的副本。成员变量用于描述对象的状态或特征。
下面是一个简单的例子,演示了如何在 Python 中定义一个类和成员变量:
- class Person:
- def __init__(self, name, age):
- self.name = name # 定义一个成员变量 name
- self.age = age # 定义一个成员变量 age
-
- # 创建一个 Person 实例
- person1 = Person("Alice", 30)
-
- # 访问成员变量并打印
- print("Name:", person1.name)
- print("Age:", person1.age)
在上面的例子中,Person
类具有两个成员变量 name
和 age
,它们分别表示人的姓名和年龄。在 __init__()
方法中,通过 self.name
和 self.age
将传递给构造函数的参数值赋给这两个成员变量。然后,创建一个 Person
类的实例 person1
,并通过 person1.name
和 person1.age
访问和打印这两个成员变量的值。
成员变量与类的属性是相关的概念,它们通常在面向对象编程中用来描述对象的特征或状态。
在 Python 中,成员变量通常被称为实例变量,因为它们是与特定类的每个实例相关联的变量。而类的属性则是指属于类本身的变量,它们可以在类的所有实例之间共享。
在一个类中定义的变量可以是类的属性,也可以是实例的成员变量。当变量被定义为类的属性时,它属于类本身,可以通过类名直接访问。而当变量被定义为实例的成员变量时,它属于类的每个实例,必须通过实例对象来访问。
下面是一个示例,演示了类的属性和实例的成员变量的区别:
- class MyClass:
- class_attr = "I am a class attribute" # 类的属性
-
- def __init__(self, instance_attr):
- self.instance_attr = instance_attr # 实例的成员变量
-
- # 访问类的属性
- print(MyClass.class_attr)
-
- # 创建实例并访问实例的成员变量
- instance1 = MyClass("Instance attribute 1")
- print(instance1.instance_attr)
-
- instance2 = MyClass("Instance attribute 2")
- print(instance2.instance_attr)
在上面的示例中,class_attr
是类的属性,可以通过类名直接访问;而 instance_attr
是实例的成员变量,必须通过实例对象来访问。
类属性是类所拥有的属性,它需要在类中进行显示地定义(位于类内部,方法的外面),它被所有类的实例对象所共有,在内存中只存在一个副本
类属性示例代码:
- class Cat(object):
- #类属性
- num = 0
类属性:类本身的变量
代码演示
- class Person3:
- count = 0 #定义属性count,表示计数
- name = "Person" #定义属性name,表示名称
- #测试代码
- Person3.count += 1 #通过类名访问,将计数加1
- print(Person3.count) #类名访问,读取并显示类属性
- print(Person3.name) #类名访问,读取并显示类属性
- p1 = Person3() #创建实例对象1
- p2 = Person3() #创建实例对象2
- print((p1.name, p2.name)) #通过实例对象访问,读取成员变量的值
- Person3.name = "雇员" #通过类名访问,设置类属性值
- print((p1.name, p2.name)) #读取成员变量的值
- p1.name = "员工" #通过实例对象访问,设置实例对象成员变量的值
- print((p1.name, p2.name)) #读取成员变量的值
-
- 运行结果
- 1
- Person
- ('Person', 'Person')
- ('雇员', '雇员')
- ('员工', '雇员')
内存中只存在一个副本
"只存在一个副本"意味着类属性在内存中只有一份拷贝,不论有多少个类的实例对象被创建,它们都共享相同的类属性。当类属性被修改时,所有实例对象所看到的该属性的值都会随之改变,因为它们都指向相同的内存地址。
这种共享特性使得类属性非常适合用于描述类的特征或状态,例如描述某个类的所有实例对象所共有的特性。
代码演示
- class MyClass:
- class_attr = "I am a student"
-
- # 创建实例对象
- obj1 = MyClass()
- obj2 = MyClass()
-
- # 访问类属性
- print(obj1.class_attr) # 输出:"I am a student"
- print(obj2.class_attr) # 输出:"I am a student"
-
- # 修改类属性
- MyClass.class_attr = "I am a teacher"
-
- # 打印修改后的类属性
- print(obj1.class_attr) # 输出:"I am a teacher"
- print(obj2.class_attr) # 输出:"I am a teacher"
__
开头,例如 __private_attr
。_
开头,例如 public_attr
或 _protected_attr
。- class MyClass:
- def __init__(self):
- self.public_attr = "I am a student" # 公有属性
- self.__private_attr = "I am a teacher" # 私有属性
-
- def get_private_attr(self):
- return self.__private_attr # 在类的内部访问私有属性
-
- # 创建实例对象
- obj = MyClass()
-
- # 访问公有属性
- print(obj.public_attr) # 输出:"I am a student"
-
- # 访问私有属性(会导致错误)
- #print(obj.__private_attr) # 会抛出 AttributeError: 'MyClass' object has no attribute '__private_attr'
-
- # 通过方法访问私有属性
- print(obj.get_private_attr()) # 输出:"I am a teacher"
- class MyClass:
- def __init__(self):
- self.__private_attr = "I am a teacher" # 私有属性
-
- def get_private_attr(self):
- return self.__private_attr # 通过方法获取私有属性的值
-
- def set_private_attr(self, value):
- self.__private_attr = value # 通过方法设置私有属性的值
-
- # 创建实例对象
- obj = MyClass()
-
- # 通过方法获取私有属性的值
- print(obj.get_private_attr()) # 输出:"I am a teacher"
-
- # 通过方法设置私有属性的值
- obj.set_private_attr("New value")
- print(obj.get_private_attr()) # 输出:"New value"
在上面的示例中,get_private_attr()
方法用于获取私有属性 __private_attr
的值,而 set_private_attr(value)
方法用于设置私有属性的值。通过这种方式,可以在类的外部间接地访问和修改私有属性,而不直接暴露私有属性本身
实例属性与私有属性的关系
实例属性和私有属性是两个不同的概念,它们之间并不完全相同。
实例属性是属于类的实例的属性,它们存储在实例的命名空间中,并且可以通过实例访问和修改。实例属性通常在类的 __init__
方法中初始化,但也可以在任何地方动态添加。
私有属性是一种访问限制,用于防止直接访问和修改类的属性。在Python中,可以通过在属性名前添加双下划线 __
来定义私有属性。私有属性只能在类的内部访问,无法在类的外部直接访问。
尽管实例属性通常不会被定义为私有属性,但你可以在实例属性前添加双下划线来模拟私有属性的效果。然而,这种做法并不是Python推荐的做法,因为Python并没有严格的私有属性机制,双下划线只是一种名称修饰约定,而不是真正意义上的私有属性。
总的来说,实例属性是类实例的属性,而私有属性是一种访问限制。尽管可以将实例属性定义为私有属性,但这并不是实例属性的本质,而是一种访问控制的手段。
常用的属性装饰器包括 @property
、@<property_name>.setter
、@<property_name>.deleter
等。这些装饰器可以帮助我们实现属性的封装、计算属性、属性值的验证等功能。
封装属性访问:属性装饰器可以将类的方法转换为属性,从而隐藏属性的具体实现细节,使得属性的访问更加简洁和直观。通过使用 @property
装饰器,可以将方法转换为只读属性,而使用 @<property_name>.setter
装饰器则可以定义属性的设置方法。
计算属性:属性装饰器还可以用于计算属性的值。通过定义只读属性的方法,可以在访问属性时动态计算其值,而无需存储额外的数据。这种方式可以节省内存空间,并且可以确保属性的值始终是最新的。
属性值验证:属性装饰器还可以用于对属性值进行验证。通过在属性的设置方法中添加验证逻辑,可以确保属性的值符合预期的范围或格式,从而提高代码的健壮性和可靠性。如果属性值不满足验证条件,可以引发异常或采取其他适当的处理方式。
属性删除:除了获取和设置属性值外,属性装饰器还可以用于定义属性的删除方法。通过使用 @<property_name>.deleter
装饰器,可以定义在删除属性时执行的操作,例如释放资源或执行清理操作。
增强属性的功能:属性装饰器还可以用于增强属性的功能。例如,可以在属性的设置方法中添加日志记录、缓存更新等额外的逻辑,从而使属性具有更多的功能和用途。
自定义属性是指在类中定义的用于描述类实例特征或状态的变量。在Python中,可以通过在类的方法中直接操作类的实例变量来定义自定义属性。
代码解释
- class Person:
- def __init__(self,name,age):
- self.name = name
- self.age = age
- def introduce(self):
- print(f"大家好,我叫{self.name},今年{self.age}岁。")
-
- person=Person("张三",25)
- print(person.name)
- print(person.age)
- person.introduce()
- 张三
- 25
- 大家好,我叫张三,今年25岁。
实例属性与自定义属性的关系
实例属性和自定义属性是相关但不完全相同的概念,它们之间有一定的关系,但并不等价。
实例属性是指属于类的实例的属性,它们存储在实例的命名空间中,并且每个实例都有自己的一组实例属性。实例属性通常在类的 __init__
方法中初始化,并且可以在任何地方通过实例访问和修改。
自定义属性是指在类中显式定义的属性,它们可以是实例属性,也可以是类属性。自定义属性通常用于描述类的特征或状态,例如一个人的姓名、年龄等。自定义属性的定义通常在类的定义中进行,并且可以通过类的实例访问和修改。
因此,实例属性是自定义属性的一种,而自定义属性不仅限于实例属性,还可以是类属性。类属性是属于类本身的属性,在类的所有实例之间共享。与实例属性不同,类属性的值在所有实例之间是共享的,可以通过类名或实例访问和修改。
总的来说,实例属性是类实例特有的属性,而自定义属性是在类中显式定义的属性,可以是实例属性也可以是类属性。实例属性是自定义属性的一种形式,而自定义属性则是描述类的特征和状态的一种机制。
实例方法是面向对象编程中的一种方法,它与特定类的实例相关联,并且可以访问该类的实例变量和其他实例方法。
声明方式
- def 方法名(self,[形参列表]):
- 函数体
调用格式
对象.方法名([实参列表])
假设我们有一个名为Car
的类,它表示汽车,其中包含实例变量color
和speed
,以及两个实例方法accelerate()
和brake()
。实例方法通过在方法定义中使用self
参数来访问实例变量。
- class Car:
- def __init__(self, color, speed):
- self.color = color
- self.speed = speed
-
- def accelerate(self, increase):
- self.speed += increase
-
- def brake(self, decrease):
- self.speed -= decrease
-
- # 创建一个名为my_car的Car实例
- my_car = Car("red", 0)
-
- # 使用实例方法加速
- my_car.accelerate(10)
- print("当前速度:", my_car.speed) # 输出: 当前速度: 10
-
- # 使用实例方法减速
- my_car.brake(5)
- print("当前速度:", my_car.speed) # 输出: 当前速度: 5
在上面的示例中,accelerate()
和brake()
方法都是实例方法,它们可以访问Car
类的实例变量speed
,并根据传入的参数增加或减少速度。
总结一下,实例方法是与特定类的实例相关联的方法,它们可以访问并操作该类的实例变量。
声明属于与类的对象实例无关的方法
静态方法不对特定实例进行操作,在静态方法中访问对象实例会导致错误
静态方法通过装饰器@staticmethod来定义
- @staticmethod
- def 静态方法名([形参列表]):
- 函数体
静态方法一般通过类名来访问,也可以通过对象实例来调用
类名.静态方法名([实参列表])
静态方法是不依赖于类的实例而存在的方法,它们与特定类相关联,但在调用时不传递类实例。静态方法通常与类的某些功能相关联,但不需要访问类的实例变量。
假设我们有一个名为MathUtils
的类,其中包含一个静态方法add()
,用于执行简单的加法操作。这个方法不依赖于MathUtils
类的任何实例。
- class MathUtils:
- @staticmethod
- def add(x, y):
- return x + y
-
- # 调用静态方法,不需要创建MathUtils类的实例
- result = MathUtils.add(3, 5)
- print("加法结果:", result) # 输出: 加法结果: 8
在上面的示例中,add()
方法是一个静态方法,它不需要通过实例来调用,而是直接通过类名MathUtils
调用。静态方法通常用于执行与类相关的一些通用功能,而不需要访问类的实例变量。
总结一下,静态方法是与类相关联的方法,但在调用时不需要传递类的实例,它们通常用于执行一些与类相关的通用功能。
允许声明属于类本身的方法,即类方法
类方法不对特定实例进行操作,在类方法中访问对象实例属性会导致错误
类方法通过装饰器@classmethod来定义,第一个形式参数必须为类对象本身,
- @classmethod
- def 类方法(cls,[形参列表]):
- 函数体
类方法一般通过类名来访问,也可通过对象实例来调用
类名.类方法名([实参列表])
类方法是与类本身相关联的方法,而不是与类的实例相关联的方法。类方法可以访问类变量,但不能直接访问实例变量。它们通常用于执行与类相关的操作,而不需要访问或修改特定实例的状态。
假设我们有一个名为Employee
的类,其中包含一个类方法get_company_name()
,用于返回公司的名称。这个方法不依赖于Employee
类的任何实例,但它可以访问类变量company_name
。
- class Employee:
- company_name = "ABC Corp" # 类变量
-
- @classmethod
- def get_company_name(cls):
- return cls.company_name
-
- # 调用类方法,不需要创建Employee类的实例
- company = Employee.get_company_name()
- print("公司名称:", company) # 输出: 公司名称: ABC Corp
在上面的示例中,get_company_name()
方法是一个类方法,它通过@classmethod
装饰器来声明。在方法内部,通过cls
参数可以访问类变量company_name
。
总结一下,类方法是与类本身相关联的方法,它们可以访问类变量,但不需要类的实例。通常用于执行与类相关的操作,而不需要访问特定实例的状态。
__init__方法即构造函数(构造方法),用于执行类的实例的初始化工作。创建完对象后调用,初始化当前对象的实例,无返回值,这个方法的第一个参数通常是self
,它表示正在创建的实例对象本身,然后可以接受其他参数用于初始化实例的各个属性。
Python示例来说明构造方法
- class Car:
- def __init__(self, color, brand):
- self.color = color
- self.brand = brand
-
- # 创建一个名为my_car的Car对象,并传入颜色和品牌信息
- my_car = Car("red", "Toyota")
-
- # 打印对象的属性
- print("颜色:", my_car.color) # 输出: 颜色: red
- print("品牌:", my_car.brand) # 输出: 品牌: Toyota
__new__方法是一个类方法,创建对象时调用,返回当前对象的一个实例,一般无需重载该方法
它是在 __init__
方法之前调用的。与 __init__
方法不同,__new__
方法是一个类方法,而不是实例方法,并且必须返回一个新创建的实例。通常情况下,你不需要自己定义 __new__
方法,因为 Python 提供的默认实现通常就足够了。
__new__
方法通常在以下情况下被用到:
自定义对象的创建过程:当你需要控制对象的创建过程时,可以重写 __new__
方法。例如,你可能想要在创建对象之前执行某些额外的逻辑,或者根据不同的条件返回不同的实例。
不可变类型的实现:对于不可变类型(例如 int、str、tuple 等),__new__
方法可以用来创建新的实例。这些类型的实例在创建后不可更改,因此需要在 __new__
方法中进行适当的处理。
- class MySingleton:
- _instance = None
-
- def __new__(cls, *args, **kwargs):
- if cls._instance is None:
- cls._instance = super().__new__(cls, *args, **kwargs)
- return cls._instance
-
- # 创建两个 MySingleton 的实例
- singleton1 = MySingleton()
- singleton2 = MySingleton()
-
- print(singleton1 is singleton2) # 输出: True,因为它们是同一个实例
在上面的示例中,MySingleton
类使用 __new__
方法来实现单例模式。__new__
方法检查类变量 _instance
是否为 None,如果是,则创建一个新的实例,并将其赋值给 _instance
,否则返回已存在的实例。
总之,__new__
方法是在 Python 中用于创建对象实例的特殊方法,它允许你在对象创建过程中进行一些额外的控制或逻辑处理。
析构方法(Destructor Method)是一个在对象被销毁(即被垃圾收集器回收)时自动调用的特殊方法。在 Python 中,析构方法由 __del__
方法实现。与 __init__
方法和 __new__
方法类似,__del__
方法也是一个特殊方法,用于在对象即将被销毁时执行清理工作。
当对象不再被引用,且没有任何变量指向它时,Python 的垃圾收集器会自动回收该对象的内存空间。在这个回收过程中,如果对象定义了 __del__
方法,那么该方法会被调用,允许对象执行一些清理工作,例如关闭文件、释放资源等。
虽然 __del__
方法提供了执行清理工作的机会,但是在实际编程中,你可能不需要经常使用它,因为 Python 的垃圾收集器通常会很好地管理对象的生命周期。此外,由于垃圾收集器的工作机制可能会导致 __del__
方法的调用时间不确定,因此不应该依赖于 __del__
方法来释放关键资源。
- class MyClass:
- def __init__(self, name):
- self.name = name
-
- def __del__(self):
- print(f"对象 {self.name} 被销毁了")
-
- # 创建一个对象实例
- obj = MyClass("example")
-
- # 手动删除对象的引用
- del obj
-
- # Python 的垃圾收集器会自动回收对象,触发析构方法的调用
__
来定义私有方法,例如def __private_method(self):
。__
开头,那么它就是一个公有方法。- class MyClass:
- def __init__(self, name):
- self.name = name
-
- def __private_method(self):
- print("这是一个私有方法")
-
- def public_method(self):
- print("这是一个公有方法")
- self.__private_method() # 在公有方法中调用私有方法
-
- # 创建一个对象实例
- obj = MyClass("example")
-
- # 调用公有方法
- obj.public_method()
-
- # 尝试调用私有方法,会引发错误
- # obj.__private_method() # 这行代码会引发 AttributeError
-
- # 通过内部调用公有方法来间接调用私有方法
- # obj._MyClass__private_method() # 这行代码会成功执行,但不建议这样做
在上面的示例中,__private_method()
是一个私有方法,只能在类的内部调用,而public_method()
是一个公有方法,可以被外部调用
方法重载(Method Overloading)是指在同一个类中,可以定义多个方法具有相同的名称但参数列表不同的情况。在Python中,方法重载并不是一种直接支持的特性,因为Python不支持方法的参数签名或类型检查。但是,可以通过一些技巧来实现类似的功能。
在Python中,方法重载通常通过使用默认参数值、可变参数或关键字参数来实现
__str__ 方法是另一个特殊方法,在 Python 中用于定义对象的字符串表示形式。当你尝试打印对象时,Python 解释器会自动调用该对象的 __str__ 方法,以获取其字符串表示形式。
- class Teacher(SchoolMember):
- # 其他方法...
-
- def __str__(self):
- return f"Teacher: {self.name}, ID: {self.id}, Department: {self.department}"
-
- class Student(SchoolMember):
- # 其他方法...
-
- def __str__(self):
- return f"Student: {self.name}, ID: {self.id}, Grade: {self.grade}"
这样,当我们打印 Teacher 或 Student 对象时,就会使用定义的 __str__ 方法来显示对象的信息。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。