1 了解面向对象
- Python 就是一个面向对象的编程语言
- 对象就是内存中用来存储指定数据的一块区间
- 对象的结构:每个对象当中都保存了3种数据:
1、id(标识):id是由我们的解析器生成的,在Cython中,id就是对象的内存地址。
2、type(类型):用来标识当前对象所属的类型,类型就决定了对象有什么功能。
3、value(值):就是对象中存储的具体数据。 - 概念:
(1)类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
(2)方法:类中定义的函数。
(3)类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
(4)数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
(5)方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
(6)局部变量:定义在方法中的变量,只作用于当前实例的类。
(7)实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
(8)继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。
(9)实例化:创建一个类的实例,类的具体对象。
(10)对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
2 类
2.1 类的引入
- Python中的类提供了面向对象编程的所有基本功能:类的继承机制允许多个基类,派生类可以覆盖基类中的任何方法,方法中可以调用基类中的同名方法。
- 对象可以包含任意数量和类型的数据。
- 类(class):简单理解相当于一个图纸,在程序中我们需要根据类来创建对象
- 学习的都是Python的内置对象,如int() str() list() tuple() set() dict()
- 类是type类型的对象,定义类实际上就是定义了一个type类型对象
- 可以通过类来创建一些自定义的对象
- 使用class 关键字来定义类,语法:
class 类名([父类]):
代码块
这里类名后面括号里的参数(即父类)可以省略,如果有父类传递过来,那就是继承
- 类名一般采用驼峰命名法
- 现在通过MyClass 创建的对象都是空对象
- 可以向对象中添加变量,对象中添加变量我们称之为属性
语法: 对象.属性名=属性值 - 可以用isinstance()函数来检查一个对象是否是另一个类的实例,返回值是True或False
class MyClass():
pass
print(id(MyClass),type(MyClass)) # 35759912 <class 'type'>
mc=MyClass() # mc是通过类 MyClass来创建的,mc就是MyClass的实例
print(mc,type(mc)) # <__main__.MyClass object at 0x00000000028C2780> <class '__main__.MyClass'>
r= isinstance(mc,MyClass)
print(r) # True
mc.name='hello'
print(mc.name) # hello
2.2 类的定义
- 类的定义:类和对象都是现实生活中的抽象
- 实际上,所有的事物有两部分组成:
1.数据(属性)
2.行为(方法) - 在类中的代码块,我们可以定义变量和函数
- 类对象创建后,类命名空间中所有的命名都是有效属性名。
- 在类中定义的变量和函数将会成为所有实例的公共属性和公共方法,任何该类的实例都可以访问。
- 方法调用和函数调用的区别:
1.如果是函数调用,有几个形参,就传递几个实参;
2.如果是方法调用,默认要指定一个形参,所以方法中至少要有一个形参
class Person():
a=123
b=456
def speak(self):
print('hahah')
# 创建Person的实例
p1=Person()
# 调用类的属性,语法:对象.属性名
print(p1.a,p1.b) # 123 456
# 调用类的方法,语法:对象.方法名()
p1.speak() # hahah
2.3 属性和方法的查找流程
- 当我们调用一个对象的属性时,解析器会先在当前的对象中寻找是否有该属性(方法):
(1)如果有,则直接返回当前的对象的属性值(方法返回值);
(2)如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值(方法返回值),如果没有就报错。
class Text():
c='haha'
def spe(self):
print('123')
p2=Text()
p2.c='wowo'
print(p2.c) # 结果为 wowo,而不是 haha
- 类对象和实例对象中都可以保存属性(方法),具体要保持到哪里,看实际需求:
(1)如果这个属性(方法)是所以的实例共享的,则应该将其保存到类对象中;
(2)如果这个属性(方法)是某个实例独有的,则应该保存到实例对象中,别的实例访问不到;
(3)一般情况下,属性保存到实例对象中,而方法需要保存到类对象中。
2.4 方法的默认形参 self
- self在定义时需要定义,但是在调用时会自动传入。
- self的名字并不是规定死的,但是最好还是按照约定和规范用 self
- self总是指调用时的类的实例。
- 注意:
(1)类方法必须包含参数 self, 且为第一个参数
(2)在定义类的方法时,不能直接调用方法外的变量,这是和函数嵌套不同的地方。 - 如果要调用,可以使用 self.属性名 的方式
class StrPrint():
str='hello'
def pri(self):
print(self.str)
a=StrPrint()
b=StrPrint()
a.str='hey'
b.str='你好'
# 哪个实例调用,self就是哪个实例的对象
a.pri() # 输出 hey
b.pri() # 输出 你好
# self 代表的是类的实例,代表当前对象的地址
print(a.pri) # 输出 <bound method StrPrint.pri of <__main__.StrPrint object at 0x00000000026D2668>>
2.5 特殊方法
- 在类中可以定义一些特殊的方法,形如__mmm__,注意前后都是双下划线,比如初始化方法:init(self),该方法在类实例化时会自动调用。
- 这些特殊方法不需要我们自己调用,创建实例时就已经调用,有多少个实例就会被调用多少次。
- 类中的代码执行顺序(例如):先执行类里面的代码块,再执行__init__部分的代码块。
- 当一个类创建了多个实例时,类里面的代码只执行一次,而特殊方法则会根据实例的个数执行多次。
class StrPrint():
print('hello')
def __init__(self):