类
我们知道,类是所有属性和方法的集合体,它包含了所有函数和数据,是一个抽象的概念。要想具体化,就需要创建一个类的实例,称类的实例对象。
实例对象中拥有属性和方法,它可以表示任何事物的属性和动作,实例对象就是一个大的集合体。如果想要表示最具体的个体,就需要将实例对象实例化,称实例化对象。
比如,学生表示的是一群爱好学习的人,这是一个大的集合体,表示了所有学生,他们具有学生共同拥有的特征,这是一个类。
一个集合体不足以表示学生的特征,因为每个人都是不同的,他们拥有各自的特点,所以需要将其实例化,具体到个人,这就是实例化对象。
类的命名
遵守变量命名的规范
大驼峰命名(由一个或多个单词构成,首个字母大写,其它单词小写相连)
尽量避开与系统命名相似的命名(不要命名与关键字、保留字相同的名)
声明类
使用class关键字声明
类由属性和方法构成,其它不允许出现
成员属性定义可以直接使用变量赋值,如果不确定,可以使用None
类的实例化
```
变量 = 类名() # 实例化对象
# 相当于“类名(变量)”,变量相当于调用实例对象时传入的参数
```
访问对象成员(调用属性和方法)
使用点号“.”操作符
```
obj.属性名
obj.方法名()
```
可以通过默认内置变量检查类和对象的所有成员,得到成员在内存中的地址
对象所有成员检查
```
obj._dict_ # dict前后各有下划线
```
类所有的成员
```
class_name._dict_
```
类的举例
# 定义一个类,用来描述学习Python的学生
# Pythonstuednt表示类的实例
class Pythonstudent ():
# 用None表示暂时不确定
name = None
age = 20
course = "Python"
# self默认参数,替代实例化对象
def doHomework (self):
print("我在做作业!")
return None
# 实例化对象
student2 = Pythonstudent()
# 类的实例调用属性和方法
print(Pythonstudent.name)
print(Pythonstudent.age)
# 实例化对象调用属性和方法
print(student2.name)
print(student2.age)
# 相当于Pythonstudent.doHomework(student2)
student2.doHomework()
以下结果如下:
None
20
None
20
我在做作业
其中,通过class关键字创建的是实例对象,它包含属性和方法,没有其它。既然是对象,那么Pythonstudent仅仅是一个指向对象的引用,它可以通过赋值运算符将这个引用赋值给其它变量。
“student2=Pythonstudent()”这一步称为类的实例化,就是将类的具体表现具体化,student1为实例对对象。
实例化对象的过程
首先创建一个空对象并赋值给student2
其次,类中的魔法属性 _new_ 会将空对象 student2 实例化
然后实例对象Pythonstudent中的魔法属性 _init_ 会格式化student2,即将实例对象Pythonstudent中的所有属性和方法格式化给student2,使它共享Pythonstudent的所有属性和方法
也就是说,在不修改student2的属性和方法的情况下,student2和Pythonstudent共享有同样的属性和方法,即实例对象Pythonstudent中的属性和函数。
换句话说,在不对实例化对象的属性重新赋值的情况下,student2和Pythonstudent这两个引用指向的都是同一个对象空间,即存放Pythonstudent中属性和函数的空间。
可以通过id()函数来查看实例对象和实例化对象所指空间是否相同
通过id()查看存入空间:
# 查看Pythonstudent的存入空间
print("Pythonstudent中name的存放空间:", id(Pythonstudent.name))
# 查看student2中name的存入空间
print("student2中name的存放空间:", id(student2.name))
结果如下:
Pythonstudent中name的存放空间: 8791484820704
student2中name的存放空间: 8791484820704
可见,实例对象和实例化对象共享相同的属性和方法。在不对实例化对象的属性赋值的前提下,student2和Pythonstudent指向同一个对象。
但此时如果对student2的属性重新赋值,那么Pythonstudent和student2的属性所指空间不相同,如:
# 此时对实例化对象的属性重新赋值,两个对象所指空间就不再相同
student2.name = "Jon"
# 查看实例对象中name的存入空间
print("Pythonstudent中name的存放空间:", id(Pythonstudent.name))
# 查看student2中name的存入空间
print("student2中name的存放空间:", id(student2.name))
结果如下:
Pythonstudent中name的存放空间: 8791484820704
student2中name的存放空间: 39637152
当然,我们也可以为实例化对象student2添加一个新的属性:
# 添加体重这个属性
student2.weight = 60
# 打印体重
print(sutdent2.weight)
print(Pythonstudent._dict_)
print(a._dict_)
结果如下:
60
这个weight属性Pythonstudent是没有的,是实例化对象student2独有的。
对于“student2 = Pythonstudent()”的解释:
student2=Pythonstudet()相当于Pythonstudet(student2),student2相当于调用实例对象时传入的参数,即 student2 ==>self
对于函数方法中的“self”的解释:
self是函数默认的参数。方法中都默认有这样一个参数,且在参数的第一个位置,它用来替换实例化对象。实例化对象调用方法时,self用来替换实例化对象。
self的值为 当前类.new(cls)。如果 Pythonstudet 是通过 class 创建的,而不是继承其他类的,那么 self == object.new(cls),也就是 实例化对象 student2 的值。那么 student2就相当于 self,被传递到函数方法中。
```
student2.doHomework()
# 可以理解为:
Pythonstudent.doHomework(student2)
```
其中,当代入到doHomework这个函数时,self自动替换成student2,然后可以执行一系列操作,比如下面的例子:
class A ():
name = "Tom"
age = 25
lover = "Python"
def doLover (self):
print("我叫{},今年{},喜欢{}".format(self.name, self.age, self.lover))
return None
# 实例化对象
a = A()
# 调用属性
print(a.name)
print(a.age)
print(a.lover)
# 调用方法,相当于A.doLover(a)
print(a.doLover())
结果为:
Tom
25
Python
我叫Tom,今年25,喜欢Python
其中,self.name替换成了a.name,self.age替换成了a.age,self.lover替换成了a.lover。
类和对象的成员分析
这里的类指的是基类(object)的实例对象,即通过 class 创建的对象。对象指的是实例化的对象。
类 的 实例对象 和 实例化对象 都可以存储成员,成员可以归实例对象所有,也可以归实例化对象所有
类 存储成员时使用的是与 类 关联的一个对象,对象存储成员也与这个对象关联,两个共同享有这个对象
实例化对象中的成员与实例对象中成员为同一个(id()相同,前提条件是实例化对象中的成员没有重新赋值、修改过。一旦修改,那么就不是同一个了,即id()不同。
独享存储成员是存储在 当前实例化对象 中
除了有与实例对象共享的属性和方法外,实例化对象也可以有自己的独有的属性和方法
通过对实例化对象添加新的属性,这个属性是 实例对象(实例化对象的所属的类) 没有的。
创建对象的时候,类中的成员不会放到对象中,只是一个空的对象,没有成员。对象可以“借用”类的成员
在 对实例化对象 的成员重新赋值,或者为它新添加成员时,成员会放到实例化对象中,不会放到实例对象中,这是实例化对象独有的。
如果对 实例对象 重新赋值,或者新添加成员,那么 实例化对象 也拥有这个成员。
关于self的理解
在 类(实例对象) 的方法函数中,self就是第一个参数,且在第一参数的位置上。当实例化对象调用这个方法时,self会自动替换成 实例化对象 并代入到方法中执行一系列操作。
在类的方法中,如果有self这个参数,说明该方法是非绑定的,可以通过实例化对象访问;如果没有self参数,那么这个函数就是绑定的,它只能通过类(实例对象本身)来访问,即实例对象访问。
比如,我们为上面的实例对象A新添加一个方法:
```
def say ():
print("这是一个绑定的方法!")
# 然后通过类来访问即A.say()
print(A.say()) #可以得到结果“这是一个绑定的方法!”
# 如果通过实例对化对象来访问即a.say()
print(a.say()) # 发生错误
# 当然,此时为say()添加self参数
def say (self):
print("这是一个非绑定的方法!")
# 那么就可以通过实例化对象来访问
print(a.say()) # 这是一个非绑定的方法!
```
可见,self用来表示实例化对象的,在调用类的方法时,self自动替换为实例化对象进行操作。
如果想要访问类中的属性,可以使用class.属性名来访问
现在,我们将实例对象A这个例子做稍微的修改:
class A ():
name = "Tom"
age = 25
lover = "Python"
def doLover (self):
self.name = "Bob"
self.age = "22"
print("我叫{},今年{},喜欢{}".format(self.name, self.age, self.lover))
return None
def say ():
print("这是绑定方法!")
return
# 实例化对象
a = A()
# 调用属性
print(a.name)
print(a.age)
print(a.lover)
# 调用方法,相当于A.doLover(a)
print(a.doLover())
print(A.say())
结果如下:
Tom
25
Python
我叫Bob,今年22,喜欢Python
None
这是绑定方法!
None
可见,self替换成了实例化对象a,“a.doLover”相当于“A.doLover(a)”,在函数体内相当于“A.dolover(a)”
如果此时我们想通过“a.doLover()”来访问 类(实例对象A)中的属性,可以使用 _class_.属性名 来访问:
def doLover (self):
self.name = "Bob"
self.age = "22"
print("我叫{},今年{},喜欢{}".format(self.name, __class__.age, self.lover))
return None
结果发生改变:
我叫Bob,今年25,喜欢Python
其中,"_class_.age"访问到的是类A中的age属性,没有访问self.age(实例化对象的属性)。
如果我们再这样调用:
a = A()
# a作为参数传入函数,__class__.age成类的属性
A.doLover(a)
# A传为参数传入函数,self替换A,__class__.age变成了self.age
A.doLover(A)
结果如下:
我叫Bob,今年25,喜欢Python
我叫Bob,今年22,喜欢Python
特别需要注意“_class_.age”的变化,可见self不仅替换实例化对象,也可以替换实参。
通过以上例子,我们可以得知:
self替换的是实参,不仅仅是实例化对象。只是因为“a.doLover()”相当于“A.doLover(a)”,所以刚好对象a成了实参,self替换了实例化对象a。
类的方法和普通函数的区别:
类的方法有一个默认的参数self,它用来替换传入方法的实参。一般用来表示实例化对象。
类和对象的区别:
类是抽象的,它包含所有属性和方法,或者包含所有数据信息。
对象是类的实例化,或者说是类的具体表现。
本质上来说,类和对象没有太大的区别,如鱼和金木鱼的区别。对象是类的实例化、具体化。