💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
[TOC] <br> ### 类与实例的定义 >[info] 我们描述人类,动物时,很显然他们是不同的类,具有不同的特性,我们将具有相同特性的一类事务划到一个`类`型中。 而张三、李四,王五是人类中的一个具体的实例对象,他们具有人类的所有特性,但是他们又是不同的`实例`,例如他们的能力,外貌等各不相同。 类(Class)是面向对象程序设计(OOP,Object-Oriented Programming)实现信息封装的基础。**类是一种用户定义类型,也称类类型**。每个类包含数据说明和一组操作数据或传递消息的函数。类的实例称为对象。 类的构成包括**数据成员**和**成员函数**,数据成员对应类的属性,成员函数则用于操作类的各项属性,是一个类具有的特有的操作。 ### python中的类与实例 类的定义: ```python class Person(object): """ 定义一个人类 人类具有属性:性别 人类具有行为能力:说话 """ sex = "boy" # 类属性 def __init__(self, name): """ 构造方法,在创建类实例时,初始化作用""" self.name = name # 实例属性 def say_hello(self, language): # 实例方法 """ 自定义方法""" result = {"name": self.name, "sex": self.sex, "language": language} return result ``` 类的使用: ```python # 创建实例对象(一只具体的人),传入构造方法中规定的参数,初始化这个人的name属性值为sandy p1 = Person("sandy") print("p1:", p1) # 输出对象 print(p1.say_hello("普通话")) # 实例对象用'.'来调用类中的普通自定义方法 print("p1.sex:", p1.sex) # 实例对象用'.'来调用类中的普通属性 ``` 运行结果: ```cmd p1: <__main__.Person object at 0x0000000000BED240> {'name': 'sandy', 'language': '普通话', 'sex': 'boy'} p1.sex: boy ``` ***代码解释:*** 这个实例,是最常用的一种类结构了。 1. 在python中,通过**关键字`class` 来声明类**,class后面跟着类名,这里定义了类"Person",类名后面的括号里面跟着该类的父类,这里的“object”是所有类的基类,这是一种新式类的写法,经典类中可以没有。建议都使用形式类吧,经典类就不提了。 2. 类中的方法,与之前学习的函数是否感觉特别相似?但是在类中,它叫方法,它的第一个参数固定是`self`,它表示**实例对象自身**,通过self.XXX 可以调用实例对象所拥有的属性和方法。 3. **实例,是通过类来创造的**。实例被创建后,就拥有了操作类属性和类方法的功能。 将类实例化,在java中需要`new`出来,而在python中,`类名([初始化参数])`就可以实例出一个对象了。创建实例时,首先就调用类中的构造方法\__init__,在\__init__中初始化一些需要外部传入的参数值给类属性。 ### 属性 #### 类属性 是在声明类后,就存在与内存中,能够通过类来直接访问,如Person.sex #### 实例属性 则只有在实例化后才会存在,如果直接通过类访问,如Person.name 则会报错:AttributeError: type object 'Person' has no attribute 'name' #### 私有属性 在python中,有一种私有属性,命名时,以两个下划线开头,如下: ```python class Person(object): """ 定义一个人类 人类具有属性:性别 人类具有行为能力:说话 """ sex = "boy" # 类属性 def __init__(self, name): """ 构造方法,在创建类实例时,初始化作用""" self.name = name self.__age = 100 # 设置私有属性 def say_hello(self, language): # 自定义类方法 """ 自定义方法""" result = {"name": self.name, "sex": self.sex, "language": language} return result def get_age(self): return self.__age ``` 编译的时候,私有属性__age自动加上类名,变成`_Person__membername`,这种技术叫变量名压缩(mangling),以达到外部不能调用的目的 **创建实例p1** ```cmd p1 = Person('Sandy') ``` **调用私有属性__age:** 如果直接通过实例调用__age,如 p1.__age,则会报错:AttributeError: 'Person' object has no attribute '__age' 但是可以通过以下两种方式访问到__age,如 p1.get_age() p1._Person__age 对于私有属性,我们一般都会通过第一种封装函数来访问。 ### 方法 1. 方法是类内部定义的函数(意味着方法是类属性而不是实例属性) 2. ***方法只有在所属的类拥有实例时,才能被调用***,当存在一个实例时,方法才被认为是绑定到那个实例了 3. 任何一个方法定义中的第一个参数都是变量`self`,它表示调用此方法的实例对象。对于已绑定的方法调用来说,self是自动传递给这个方法的,在调用的时候就不需要传入这个参数了。 #### 静态方法@staticmethod与类方法@classmethod >由前面的介绍可知,类中的方法,第一个参数都是self. 类中定义的方法,需要实例化后才能调用。 能否实现在方法中,不需要传入self,不需要实例化,直接通过类就能调用? 在python中,可以通过声明`静态方法`和`类方法`来实现。 **静态方法**:在类方法中,存在与类相关,但是又不需要改变类和实例状态的方法,这类方法可以声明为静态方法,静态方法不需要访问类里的任何参数。所带的参数都是从外部传入的。使用函数修饰符 @staticmethod 将方法声明为静态方法。 **类方法**: python中使用函数修饰符@classmethod 将方法声明为类方法,可以被类直接调用。 类方法第一个参数必须是类属性,一般用cls,因此我们可以在方法里面调用类的属性、方法 ```python class Person(object): """ 定义一个人类 人类具有属性:性别 人类具有行为能力:说话 """ sex = "boy" # 类属性 def __init__(self, name): """ 构造方法,在创建类实例时,初始化作用""" self.name = name def say_hello(self, language): # 类方法 """ 自定义方法""" result = {"name": self.name, "sex": self.sex, "language": language} return result @staticmethod def sing(song): print("sing:", song) @classmethod def run(cls, distance): print("run:", distance,"sex:",cls.sex) ``` 调用方式: ```python Person.sing("HIJKLMN...") # 类直接调用静态方法 Person.run("400") # 类直接调用类方法 Sandy=Person('Sandy') Sandy.sing("ABCDEFG...") # 通过实例调用静态方法 Sandy.run("8000") # 通过实例调用类方法 ``` 运行结果: ```cmd sing: HIJKLMN... run: 400 sex: boy sing: ABCDEFG... run: 8000 sex: boy ``` #### 属性方法 @property @property`把一个函数变成一个静态属性,直接调用函数名字`,不需要加括号,就能获取到函数返回值。一般用在不注重过程,只要结果的情况! ```python class Person(object): """ 定义一个人类 """ sex = "boy" # 类属性 def __init__(self, name): """ 构造方法,在创建类实例时,初始化作用""" self.name = name self.__age = 100 @property def age(self): return self.__age Sandy = Person('Sandy') print(Sandy.age) #不需要括号,看起来完全是一个属性,这就是属性方法 ``` 运行结果: ```cmd 100 ``` ### 类中内置的几个特殊方法 #### \__new__,\__init__,\__del__,\__str__ 通过实例,了解他们的调用时机 ```python class Person(object): """ 定义一个人类 """ def __init__(self,name): self.name=name print("__init__ function call") def __new__(cls, *args, **kwargs): print("__new__ function call") return super(Person, cls).__new__(cls) def __del__(self): print("__del__ function call") def __str__(self): print("__str__ function call") return self.name print("*"*30) Sandy = Person('Sandy') print("*"*30) print(Sandy) print("*"*30) del Sandy ``` 运行结果如: ```cmd ****************************** __new__ function call __init__ function call ****************************** __str__ function call Sandy ****************************** __del__ function call ``` \__new__() 是在新式类中新出现的方法,它作用在构造方法创建实例之前 \__init__() 构造方法,它作用于创建实例之时 \__str__() 作用于输出实例对象时 \__del__() 作用于销毁实例对象时 ### 类的继承 在python中,object是新式类最顶级的类,是所有类的基类。 在前面的举例中,Person是人`类`,那么,“中国人”,“美国人”,“法国人”等也是`人类`中划分更细的一个群体,也可以定义成一个类,并且这些类具有`人类`的一切特征,但是又有属于自己特有的特征。 我们定义“中国人”,“美国人”类时,直接**继承**人类,即可实现在“中国人”和“美国人”这些`子类`中,无需重复编写相同的特性与属性,可以直接使用`父类`Person中定义的属性和方法。 #### 成员属性和方法的继承 ```python class Person(object): """ 定义一个人类""" sex = "Boy" def say_hello(self, language): # 类方法 """ 自定义方法""" print("Lanuage:", language) class Chiness(Person): """ 定义中国人 类""" nature = "Love Peace!" p1 = Chiness() print(p1.sex) # 从子类中,可以调用父类的成员数据 p1.say_hello("普通话") # 从子类中,可以调用父类的方法 ``` 运行结果: ```cmd Boy Lanuage: 普通话 ``` #### 子类对父类方法的重写 子类的的方法如果和父类的方法重名,子类会覆盖掉父类。 ```python class Person(object): """ 定义一个人类""" sex = "Boy" def say_hello(self, language): # 类方法 """ 自定义方法""" print("Lanuage:", language) class Chiness(Person): """ 定义中国人 类""" nature = "Love Peace!" def say_hello(self,language): print("您好,我是中国人,我的母语是",language) p1 = Chiness() p1.say_hello("普通话") # 从子类中,调用父类的方法 ``` 在Chiness类中,具有与父类方法名相同的say_hello,当Chiness的实例对象调用say_hello时,就会使用Chiness中的say_hello。 运行结果: ```cmd 您好,我是中国人,我的母语是 普通话 ``` #### 构造方法的继承与重写 一般来说,子类的构造方法都是先继承,然后扩展。其中, **新式类**的构造方法继承写法如:***`supper(子类,self).__init__(参数1,参数2...)`*** **经典类**的构造方法继承写法如:*父类名称.\__init__(self,参数1,参数2,...)* ```python class Person(object): """ 定义一个人类""" sex = "Boy" def __init__(self, name): self.name = name def say_hello(self): # 类方法 """ 自定义方法""" print("name:", self.name) class Chiness(Person): """ 定义中国人 类""" def __init__(self, name, nature): super(Chiness, self).__init__(name) # 先继承父类的构造方法 self.nature = nature # 扩展子类的构造方法 def say_hello(self): print("您好,我是中国人,我的名字是【{name}】,我的天性是【{nature}】".format(name=self.name, nature=self.nature)) p1 = Chiness("张三", "爱好和平") p1.say_hello() ``` 运行结果: ```cmd 您好,我是中国人,我的名字是【张三】,我的天性是【爱好和平】 ``` ### 多态 >子类的的方法如果和父类的方法重名,子类会覆盖掉父类。因为这个特性,就获得了一个继承的好处”多态”。 ```python class Person(object): """ 定义一个人类""" def __init__(self, name): self.name = name def say_hello(self): # 类方法 """ 自定义方法""" print("name:", self.name) class Chiness(Person): """ 定义中国人 类""" def __init__(self, name, nature): super(Chiness, self).__init__(name) # 先继承父类的构造方法 self.nature = nature # 扩展子类的构造方法 def say_hello(self): print("您好,我是中国人,我的名字是【{name}】,我的天性是【{nature}】".format(name=self.name, nature=self.nature)) class America(Person): """ 定义一个美国人 类""" def __init__(self, name, nature): super(America, self).__init__(name) # 先继承父类的构造方法 self.nature = nature # 扩展子类的构造方法 def say_hello(self): print("Hello,I am America,My name is 【{name}】,my nature is 【{nature}】".format(name=self.name, nature=self.nature)) def say_hello(people): people.say_hello() p1 = Chiness("张三", "爱好和平") p2 = America("Perter","fighting") # 同一个方法,传入不同的人,会说出不同的问候,这便是一种多态... say_hello(p1) say_hello(p2) ``` 运行结果: ```cmd 您好,我是中国人,我的名字是【张三】,我的天性是【爱好和平】 Hello,I am America,My name is 【Perter】,my nature is 【fighting】 ``` <hr style="margin-top:100px"> :-: ![](https://box.kancloud.cn/2ff0bc02ec938fef8b6dd7b7f16ee11d_258x258.jpg) ***微信扫一扫,关注“python测试开发圈”,了解更多测试教程!***