概述
之前的博客里,不管是数据结构与算法,还是深度学习框架,到处都是面向对象编程。很多资料里都说面向对象是比较抽象的东西,但是我总觉得吧,这东西理解起来很容易,就是讲出来比较抽象。很多时候不必去深究面向对象的概念,我们可以从代码的角度去理解它。万事万物都是对象,都会属于某个类。类是抽象的,而对象是具体的。
变量与对象
a = 123
dir(a)
首先我们定义一个整型变量,使用dir()函数来查看它的属性,对a来说,下面的这些函数其实都是它的属性,这也就说明了Python中,整型变量也是有属性的,它也是个类。篇幅有限,我截取了一部分的属性。
再来看,int是否也是对象呢?
这里我也是只截取了一部分属性,可见int本身就是一个对象。当我们定义一个整型变量时,也就是继承了int的属性。对变量a来说,它是一个对象,int是这个变量的类。
这样我们可以像查看对象的属性一样来查看a这个变量的内容。
当然,不仅是整型变量。列表也是这样。
列表与对象
这里我就直接给出demo代码,感兴趣的可以试一试。
我们可以对比一下常规操作和使用类的方法操作的结果,其实是一样的。
list = [1,2,3]
dir(list)
list.append(4)
list.__getitem__(2)
上面废话这么多,就是想说明一点:Python中万物皆是对象。
面向对象
其实我们不需要看很多废话,记住面向对象的四个特性就可以了:封装,抽象,继承,多态。如果你是好好学过中学语文的话,是可以大概理解这四个词的,在实际操作过程中,你就会发现这四个词用得恰到好处。
我们首先创建一个类并将它实例化:
class People:
pass
peo1 = People()
peo2 = People()
peo1,peo2
这里返回的信息是两个对象现在的存储位置。我们将一个类写成上面这种形式,给具体的对象调用,这种写法就是封装。这里pass里没有上面内容,但它可以有很多内容,这么多内容合在一起给了People这个类。
我们可以添加属性信息,这里需要用到__init__()方法。
class People:
def __init__(self,num,name,age):
self.num = num
self.name = name
self.age = age
peo1 = People('001', '张三' ,18)
peo2 = People('002', '李四' ,20)
print('{}的年龄是{}'.format(peo1.name,peo1.age))
print('{}的年龄是{}'.format(peo2.name,peo2.age))
这里注意一点是属性中的第一个参数要是self,实例化后,我们可以直接传入对象特有的参数构成对象的属性。最后我们打印的时候,需要写一个方法来打印,其实我们可以直接将它变成类中的方法,然后实例化后就直接有这样的方法。当实例很多的时候,会极大减少代码量。
class People:
def __init__(self,num,name,age):
self.num = num
self.name = name
self.age = age
def inform(self):
return '{}的年龄是{}'.format(self.name,self.age)
peo1 = People('001', '张三' ,18)
peo2 = People('002', '李四' ,20)
print(peo1.inform())
print(peo2.inform())
这样也是可以输出同样的效果。所以我们在类中定义的方法,将类实例化后,实例也是可以直接使用该方法的。
类方法与静态方法
类方法
上面所说的类里的方法都是实例方法(instance method),它们都适用于对象,下面我们说一下类方法(class method)和静态方法(static method)。
类方法适用于该类,也就是说对这个类的所有实例的作用都是一样的。类方法有两个特点:
- 第一行要有装饰器 @classmethod
- 函数的第一个参数必须是cls
比如说我们根据上面的代码添加一个功能。假设按照年龄发放餐补,补助金额是年龄的1.5倍,代码可以是这样的:
class People:
buzhu_rate = 1.5
def __init__(self,num,name,age):
self.num = num
self.name = name
self.age = age
def inform(self):
return '{}的年龄是{}'.format(self.name,self.age)
@classmethod
def canbu(cls,buzhu_rate ):
cls.buzhu_rate = buzhu_rate
peo1 = People('001', '张三' ,18)
peo2 = People('002', '李四' ,20)
print(People.buzhu_rate)
print(peo1.buzhu_rate)
print(peo2.buzhu_rate)
我们首先查看buzhu_rate这个变量,类中定义了后,用两个实例来看buzhu_rate,这明显是没有变化的,都是1.5。
然后我们改变类中的这个值,再次查看结果:
class People:
buzhu_rate = 1.5
def __init__(self,num,name,age):
self.num = num
self.name = name
self.age = age
def inform(self):
return '{}的年龄是{}'.format(self.name,self.age)
@classmethod
def canbu(cls,buzhu_rate ):
cls.buzhu_rate = buzhu_rate
peo1 = People('001', '张三' ,18)
peo2 = People('002', '李四' ,20)
People.canbu(1.6)
print(People.buzhu_rate)
print(peo1.buzhu_rate)
print(peo2.buzhu_rate)
通过类来调用类方法并且改变参数,这样做后实例中的类方法也改变了。
现在我们用实例的类方法来改变参数,看看结果如何:
class People:
buzhu_rate = 1.5
def __init__(self,num,name,age):
self.num = num
self.name = name
self.age = age
def inform(self):
return '{}的年龄是{}'.format(self.name,self.age)
@classmethod
def canbu(cls,buzhu_rate ):
cls.buzhu_rate = buzhu_rate
peo1 = People('001', '张三' ,18)
peo2 = People('002', '李四' ,20)
peo1.canbu(1.6)
print(People.buzhu_rate)
print(peo1.buzhu_rate)
print(peo2.buzhu_rate)
结果全是1.6,所以我们通过实例中的类方法改变参数也是可以达到同样的效果。所以总结看来,类方法是所有对象和类都能调用,而且产生的效果一样。
静态方法
一个类中会有一些函数,它们不会随对象和类的属性改变,这种函数就叫做静态方法。
静态方法中的两个特点:
- 需要装饰器@staticmethod
- 函数中参数不能有cls和self
具体怎么实现这里不多赘述了。