欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

[原创首发】用 Ash 学习 Python - 类和示例

最编程 2024-05-26 17:22:53
...

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

声明:版权归本人所有,违者必究。 
转载请注明来源 https://juejin.cn/post/7112658873902694413

面向对象的核心是类与实例,类可以看做是实例的模板,是对现实世界的抽象;实例则是根据类创造出来的具体对象。如,人是抽象的概念,可以人为人是一个“类”,人有姓名、身份证号、身高、种族、肤色等属性,但当我们说“人”的时候,并不清楚具体指的是哪个人;当我们给人指定姓名、身份证号等属性时,就完成了对“人”这个类的实例化,我们可以知道张三是谁,知道他的身高是多少,知道他的种族和肤色的具体“值”,因此,可以认为张三是“人”这个类的一个“实例”。

1.1.1. 定义类

类是面向对象的基本要素,封装了一类对象的状态和方法,在语法上,类由两部分组成:类的声明和类体,语法格式如下:

class   <类名>:    

     <类体的内容>

l 第1行是类的声明,class是关键词,用来定义类,其后紧跟的是类名称,通过空格分隔。类名可以为任意符合规范的名称,一般首字母大写,使用驼峰命名法,以区分与方法、属性的区别。类名后用“:”表示后续为类内容部分。

l 第2行是类体的内容,用来封装一类事物的相同属性和功能。类体由属性和方法组成。类体内容可有多行组成,每行内容缩进两个空格或一个制表符。

 

我们定义了“Dog”类和“Animal”两个类,用来表示“狗”和“动物”两种类型的对象。“Dog”和“Animal”分别是类名,可以是任意按照标识符规范定义出来的名称,类名一般是名词,首字母常大写;类体内可定义成员变量或成员方法,此处暂以pass来代替具体内容。

【例1-1】 定义“猫”、“狗”类的代码示例如下:

12345 class  Dog:  pass   class Animal:        pass  

类属性****

属性的定义与前文中介绍的变量定义类似,属性用来表示类的内部状态,在类中定义属性的语法格式如下:

c lass ********<类名>:    

<属性名>  =  <默认值>  

l 第1行是类的声明,与前文一致。

l 第2行是属性的定义,此处属性的定义必须指定默认值。类的属性可以根据需要定义多个,属性的定义不区分先后顺序,但必须在使用之前定义好。在类中定义的属性,为其实例提供模板,实例自动具备类中定义的属性默认值。属性名一般遵循变量命名规则,多个单词中间通过单个“_”连接。

 

以“Animal”为例,我们给其定义名字、年龄、颜色等属性。name表示动物的名字,age表示动物的年龄,color表示动物的颜色。因name和color都是字符串类型,所以默认值为空字符串;age为数字类型,因此默认值为0。

【例1-2】 定义“Animal”类的属性:

1234 class Animal:   # 定义Animal类name = ''   # 动物的名字   age = 0   # 动物的年龄 color =''   # 动物的颜色

类方法****

方法用于定义类的行为能力,方法的定义与前文的函数定义类似,区别之处在于:类中定义的方法 ,第一个参数必须是实例本身,一般使用self,类似其他语言中的this对象;函数可以直接通过函数名称调用, 类中的方法必须与对象结合使用,通过对象来调用。在类中定义方法的语法格式如下:

class <类名>:  

def  <方法名> (self [, 参数1, 参数2...] ):  

<方法体>  

l 第1行是类的声明,与前文一致。

l 第2行是方法的定义,方法名可以是任意符合规范的方法至少需要一个参数,第一个参数指向当前实例;此处的self不是固定的关键词,可以是任意自定义的名称,但一般约定俗成的使用self;方法名如果有多个关键词,一般通过单个“_”连接;方法的参数遵循变量命名规则。

l 第3行为方法体,类似前面章节中介绍的函数体。如需在方法内调用当前对象的属性或方法,可以通过“self.属性名”、“self.方法名”的方式调用。

 

给动物定义两个方法,分别是说话、吃东西。speak方法只有一个self作为参数,内部通过self对象调用当前对象的name和age属性。eat方法有多个参数,方法体中直接通过参数名称调用参数。

【例1-3】 定义Animal类:

12345678910 class Animal:   # 定义Animal类name = ''   # 动物的名字   age = 0   # 动物的年龄 color =''   # 动物的颜色      def speak(self):   # 只有一个参数的方法print("我是{},今年{}岁了".format(self.name,self.age))      def eat(self, food_number, food_name):   # 有多个参数print("我是{},今天吃了{}个{}".format(self,self.name, food_number, food_name)) 

修饰符****

属性和方法是有访问限制的,与其他语言类似,如java的属性,通过private、protected、public等修饰符来定义属性的访问限制,private的属性仅可作用于类的内部,只有自己可以访问;protected的属性,可以被模块内部或子类访问;public为公开的属性,可以在任意位置使用。而Python语言中并没有private、protected、public等修饰符,而是通过“”来修饰。未加“”表示公开的属性,可以被外部使用;一个“”表示受保护的属性,不完全对外公开,仅能在类的内部、模块内或子类中使用;两个“”表示私有的属性,仅能在类的内部访问,否则会报错。

1.1.2. 类的实例化

通过类创建实例的过程就是实例化,实例创建完成后,就通过实例对象引用其属性和方法,以完成对象与对象之间通信的过程。在其他语言中一般通过new关键词来创建实例,Python没有此关键词,而是通过“类名+()”的方式创建实例。语法如下:

<对象名> = <类名>( [参数1, 参数2...] )  

l 类名后面紧跟初始化实例所需的参数

l 参数可以无空,也可以有多个,这是根据类中的构造方法决定的

l 在创建实例时,实际会调用类的构造方法。

 

类实例化时,会调用类的构造方法的构造。构造方法是一个特殊的方法,与普通方法类似,它的名字是固定的“init”,一个类只能有一个构造方法。构造方法定义如下:

class <类名>:  

def init(self [, 参数1, 参数2...] ):  

<方法体>  

l 方法名必须是固定的“init”(init前后均为两个“_”)

l 参数列表与实例化时的参数一一对应

l 该方法不是必须的方法,如果类中没有该方法,则默认会有一个无参构造方法,且方法体为空

 

以上文的Animal类为例,如需在创建对象时做一些事情,可在Animal类中添加构造方法,构造方法接收四个参数,分别是动物的名字、年龄、颜色。

【例1-1】 给Animal类添加构造方法:

12345678910111213141516 class Animal:       def init(self, name, age, color):       # 定义构造方法self.name = name  self.age = age  self.color = color  if age > 10:  self.label = 'old animal'  else:  self.label = 'young animal'    def speak(self):   # 动物说话print("我是{},今年{}岁了".format(self.name,self.age))     def eat(self, food_number, food_name):       # 动物吃食物print("我是{},今天吃了{}个{}".format(self,self.name, food_number, food_name)) 

 

 

正因Animal类中定义的构造方法有多个参数,因此在创建对象实例时,也需要有对应的参数。当需要使用创建好的对象时,通过“对象名.属性名”的方式引用对象中的属性。在Python中,对象的本质是内存中的一个数据块,每个数据块对应一个“地址”,当需要这块数据时,根据“地址”便可找到此数据。Python的变量名存储的是这个地址,通过“地址”指向数据块的位置,这种获取数据的方式称为“引用”,类似其他语言的“指针”的说法。

【例1-2】 实例化Animal类:

12 dog = Animal('小狗黑豆', 3, 'white')  print(dog.name)  # 打印结果为“小狗黑豆”

类属性与对象属性****

或许你会发现一个问题,在上文给类定义属性时定义了name,age,color三个属性,而在实例化的例子中,将这三个属性去掉了,改为了在__init__方法中通过“self.属性名”的方式隐式的给对象声明了四个属性。这里是有区别的,在类中定义的属性称为类属性,在方法(包括构造方法和普通方法)中通过“self.属性名”隐式定义的属性成为对象属性。对象可以通过通过“类名.类属性名”访问类属性,在类中可以通过“对象名.对象属性”来访问对象属性。

【例1-3】 类属性与对象属性:

12345678910111213 class Demo:  remark = 'Class Property'  def modify(self):  self.remark = 'Object Property Modified'  # 在对象中修改对象属性  Demo.remark = 'Class Property Modified'    # 在对象中修改类属性   if name == "main":object1 = Demo()  print(object1.remark)            # 修改前访问对象1的属性  print(Demo.remark)               # 修改前访问类属性  object1.modify()   # 通过实例化的对象名调用其方法print(object1.remark)            # 修改后访问对象1的属性  print(Demo.remark)               # 修改后访问类属性 

执行结果如下:

Class Property**

Class Property**

Object Property Modified**

Class Property Modified**

由以上执行结果可以看出:

在类中定义的属性,可以通过“类名.属性名”访问,也可以通过“self.属性名”来访问。但通过self引用的只能作用在对象的范围内,修改之后不会影响类属性的值。通过“self.属性名”第一次获取到的值,是从类属性“拷贝”过来的,类属性相当于模板,通过该类创建的对象,自动将类属性作为初始值。

类的内置方法****

上文在对类实例化时,提到的__init__方法为类的内置方法,开发者通过重写该方法,可定义类的构造行为。除此方法之外,类还有其他的内置方法,所有的内置方法前后都有两个“_”,每个内置方法都有其特殊意义:

init : 构造函数,在生成对象时调用

del : 析构函数,释放对象时使用

repr : 将对象转换成字符串

setitem : 按照索引赋值

getitem: 按照索引获取值

len: 获得长度

cmp: 比较运算

call: 函数调用

add: 加运算

sub: 减运算

mul: 乘运算

truediv: 除运算

mod: 求余运算

pow: 乘方