Python中的类与对象
参考文章:7篇文章搞懂Python的类与对象
上面看着是一篇博文,其实是七篇博文,每篇都不长,我觉得对类与对象写得还蛮清楚的,我在此系统整理一下。因为是基于自己的理解进行的排版,所以如果有理解有偏颇的地方,欢迎讨论。
一、关于类与对象的理解
类:可以把“类”当成是制造产品的图纸,或者是一个模具,里面有一些设定好的东西。在进行产品生产时就依照产品图纸与模具进行生产。
对象:依照图纸与模具生产的产品。产品之间大同小异。也称对象是类的实例(instance),可以理解为是概念产品的实例化。
再从一些比较专业的角度谈甚么是对象:
- 对象是内存中专门用来存储数据的一块区域。
- 对象中可以存放各种数据(比如:数字、布尔值、代码)
- 对象由三部分组成:
1.对象的标识(id)
2.对象的类型(type)
3.对象的值(value)
常规开发中,我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名。
二、简单案例
类的基本结构
class 类名([父类]): 代码块
1. 定义一个最简单基础的类
class MyClass(): pass print(MyClass)
这个类里面甚么都没有,所以也就不会输出甚么有用信息。
2. 定义好类之后就可以创建对象
mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例 print(mc)
mc就是我们用Myclass这个模具创造出来的一个实际产品(对象)。因为这个模具里面啥都没有,所以这个产品实际上也是啥都没有。
听起来有点玄学,那么我们来创建一个有东西的类试一下。不过在创建有东西的类之前,我们需要知道两个东西——变量与函数。
三、变量与方法
在类的代码块中,我们可以定义变量和函数。
定义变量
变量会成为该类实例的公共属性,所有的该类实例都可以通过以下形式访问: 对象.属性名
class Person : name = 'swk' #再创建对象p1与p2,此时p1与p2中的值一模一样 p1 = Person() p2 = Person() print(p2.name)#访问的是‘swk’ print(p2.name)#访问的是‘swk’
此时name为公共属性,所有实例都可以访问。比如 p2.name 访问的就是swk这样一个名字。( p1.name 访问的也是这一个名字)
定义方法
在类中也可以定义函数,类中的定义的函数,我们称为该类实例的公共方法。所有的该类实例都可以通过以下形式访问: 对象.方法名()
class Person : name = 'swk' #如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参。所以要在方法say_hello()中定义一个参数,在括号里面定义一个占位用的a也行。 def say_hello(self) : print('你好!') #再创建对象p1与p2,此时p1与p2中的值一模一样 p1 = Person() p2 = Person() #print(p2.name) #调用方法:对象.方法名 p1.say_hello() # p1调用方法say_hello()
总结:p1与p2是制造出来的两个产品,依照“Person”这个类制造出来的,两个此时是一模一样的东西。
四、个性化定制
这是我自己瞎取的名。
不过我们已经了解到一个类,可以制造出很多相同的对象。但是我们开始思考一个问题,就是我利用类创造出的对象,他就必须得是一模一样吗?当然不是啦小笨蛋,每一个对象也可以建立一个自己的独有属性。
class Person: def say_hello(self): print("你好") p1 = Person() p2 = Person() # p1.say_hello() p1.name = "孙悟空" print(p1.name)
可以看见name这个属性在Person的类里面并没有,是之后我们自己给p1这个对象创建的,是p1特有的,如果输出 print(p2.name) 是会报错的,因为对象p2中没有这个name属性。
当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,如果有,则直接返回当前的对象的属性值;如果没有,则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,如果没有则报错!
关于放在类里与个性化定制一点提醒:
如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中;
如果这个属性(方法)是某个实例独有,则应该保存到实例对象中。
五、类的特殊方法init
在介绍init之前,我们先来看之前提到的,在设定方法时必须设定的那一个参数。
关于在方法中必须设定的参数:方法每次被调用时,解析器都会自动传递第一个实参,其实第一个参数,就是调用方法的对象本身。示例代码和注释如下:
class Person : name = 'swk' def say_hello(self) : # 如果是p1调的,则第一个参数就是p1对象 # 如果是p2调的,则第一个参数就是p2对象 # 一般我们都会将这个参数命名为self ''' say_hello()这个方法,可以显示如下格式的数据: 你好!我是 xxx 注意:在方法中不能直接访问类中的属性,此处只写name是会报错的,所以要通过`self.name`的形式: ''' print('你好!我是 %s' %self.name) # 创建Person的实例 p1 = Person() p2 = Person() # 修改p1的name属性 p1.name = '猪八戒' p2.name = '沙和尚' p1.say_hello() # '你好!我是 猪八戒' p2.say_hello() # '你好!我是 沙和尚'
上面的例子表明,对于类一开始所具有的属性,在建立对象后,我们可以通过 对象.属性 方法调用进行修改。
不过在一开始,我们也可以不在类中设立属性,仅仅设立方法。此时方法中使用的属性,需要在创建对象后再利用 对象.属性 对属性赋值。
class Person: def say_hello(self): print("你好,我是%s" % self.name) p1 = Person() p2 = Person() # p1.say_hello() p1.name = "孙悟空" p1.say_hello()
此时如果输出 p2.say_hello() 是会报错的。
但是对于Person类来讲,name是必须的。由于每一个对象的name属性基本上都不同。
我们采取的解决方法是在建立对象后,手动将name属性添加到对象中,这种方法很容易出错,可能会忘记赋值,致使有些对象没有name属性,产生错误。
更好的解决方法:在设置对象的时候就必须建立name属性,如果不设置,则无法建立对象。并且属性的创建应该是自动完成的,不是在创建对象之后手动完成。
在类中可以定义一些特殊方法(魔术方法),特殊方法都是以__
开头,__
结尾的方法,特殊方法不需要我们自己调用。不要尝试去调用特殊方法,特殊方法将会在特殊的时刻自动调用。
init就是Python的一种特殊方法,会在对象创建之后立刻执行,可以用来向新创建的对象中初始化属性。
调用类创建对象时,类后面的所有参数都会自动一次传递到init()中。
class Person : def __init__(self,name): # 通过self向新建的对象中初始化属性 self.name = name def say_hello(self): print('大家好,我是%s'%self.name) p1 = Person('孙悟空') p2 = Person('猪八戒') p3 = Person('沙和尚') p4 = Person('唐僧') p4.say_hello()
此时就完成了强制赋值,因为如果不给传递name的话就会报错
总结一下,类的基本结构:
class 类名([父类]) : 公共的属性... # 对象的初始化方法 def __init__(self,...): ... # 其他的方法 def method_1(self,...): ... def method_2(self,...): ... ...
在原博文的第七篇博文中有一个小狗的例子,感兴趣的可以试一下。