Python的面向对象
1. 进入Python的面向对象
python 作为一个弱类型的动态语言,其面向对象的方式与Java、C++这种强类型的语言相比还是有很大的不同的。其中Java、C++如何此处不作赘述。
首先,先预设这么一个类:
# code-01
class Person(object):
def __init__(self, name):
self.name = name
def setName(self, name):
self.name = name
def getName(self):
return self.name
像这样定义属性:
# code-02
def __init__(self, name):
self.name = name # self.name 代表的就是定义的属性(先声明再定义?还是直接定义?由你决定!)
像这样定义函数:
# code-03
def setName(self, name): # 这里的setName()、getName()函数都可以通过实例来调用,self代表的是实例本身,
# 其他函数的参数问题不在本文讨论之列,另外:注释不要像我这么写
self.name = name
def getName(self):
return self.name
2. 访问控制
python 的访问控制干脆直接,属性权限从属性的名字上即可得到。
此处按照常规的访问权限解释:
-
public
如 code-01 的代码所示:
# code-04 def __init__(self, name = '') self.name = name这里的
self.name就是 public 的,我们可以通过下面这种方式访问这个属性:# code-05 if __name__ == '__main__': p = Person("Marry") print(p.name) # 这里会输出: Marry同样的,这里的
setName()和getName()也是 public 的,我们也可以通过下面这种方式来访问:# code-06 if __name__ == '__main__': p = Person("Marry") print(p.getName()) # 这里会输出: Marry -
private
这里我们把上面 code-01 的代码修改
__init__(self,name)函数,如下所示:# code-07 class Person(object): def __init__(self, name = "",marry = False): self.name = name self.__marry = marry并添加如下代码,其他部分不变。
# code-08 class Person(object): def __isMarry(self): return self.__marry像
__isMarry(self)这样的函数就是private函数,self.__marry这样的属性(变量)就是private属性。那么,如果再直接访问它的话,就会报错:
# code-09 if __name__ == '__main__': p = Person("Marry") print(p.getName()) # 这里会输出: Marry print(p.__isMarry()) # 这里会报错 Traceback (most recent call last): File "/media/somote/新加卷/pytest/ootest.py", line 16, in <module> print(p.__isMarry()) AttributeError: 'Person' object has no attribute '__isMarry' -
protected
事实上,python 并不提供这个权限,所以在此不作描述。
3. 内置装饰器
@property
先说一下property()函数,这里有必要提一下类的三个内置函数:setattr、getattr(以及getattribute)、delattr,关于关于这三个函数该如何使用,请自行搜索
property()的作用就在于把setattr、getattr、delattr三个函数给统一起来,如下所示:
# code-10
class Girl (Person):
"""
我们新增一个 Girl 类,继承自 Person,同时我们为它新增一些身材属性 bust、waist、hip
"""
def __init__(self, name):
super(Girl, self).__init__(name)
self.bust = 80
self.waist = 80
self.hip = 80
# 这里的 figure 参数实际上就是*args(tuple类型)
def setfigure(self, figure):
self.bust, self.waist, self.hip = figure
def getfigure(self):
return self.bust, self.waist, self.hip
def delfigure(self):
del self.bust
del self.waist
del self.hip
# 这里是重点
figure = property(getfigure, setfigure, delfigure)
运行:
# code-11
if __name__ == '__main__':
g = Girl("Jane")
print(g.name)
g.setfigure((50,60,90)) # 通过函数来设置
print(g.getfigure())# 50,60,90
'''
通过figure属性,绑定到其property()函数的 setter、getter、deller函数上,注意:这里必须把参数给齐,否则会报错
'''
g.figure = 60,90,90
print(g.figure) # 60,90,90
print(g.bust) # 60
print(g.waist) # 90
print(g.hip) # 90
我们也可以通过@property来设置属性:
# code-12
class Girl (Person):
"""
我们新增一个 Girl 类,继承自 Person,同时我们为它新增一些身材属性 bust、waist、hip
"""
def __init__(self, name):
super(Girl, self).__init__(name)
self.bust = 80
self.waist = 80
self.hip = 80
# 这里预先把 figure() 装饰為 figure属性,所以可以在下面设置 setter、deleter,注意: getter 由这里的figure()代替了
@property
def figure(self):
print("get value")
return self.bust, self.waist, self.hip
@figure.setter
def figure(self, figure):
print("set value")
self.bust, self.waist, self.hip = figure
@figure.deleter
def figure(self):
del self.bust
del self.waist
del self.hip
运行:
# code-13
if __name__ == '__main__':
g = Girl("Jane")
print(g.name) # Jane
g.figure = 60,90,90 # set value
print(g.figure) # get value
# 60,90,90
print(g.bust) # 60
print(g.waist) # 90
print(g.hip) # 90
通过property()或@property这种方式,可以控制某些属性的读写权限
@staticmethod
顾名思义,staticmethod就是静态方法的意思,那么首先先来了解一下静态属性,在code-12的代码里,我们作如下修改:
# code-14
class Girl (Person):
girlsnum = 0
# primary code here
运行:
# code-15
if __name__ == '__main__':
g = Girl("Jane")
print(g.girlsnum) # 1
g1 = Girl("Marry")
print(g.girlsnum) # 2
g2 = Girl("Lucy")
print(g1.girlsnum) # 3
print(Girl.girlsnum) # 3
可以看出,girlsnum这个属性就是一个静态的类属性,那么staticmethod呢?
我们在code-12的基础上再次添加一些内容:
# code-16
class Girl (Person):
# primary code here
@staticmethod
def info(name="", figure=()):
return "Name : " + name + " \tFigure : " + str(figure)
然后运行:
# code-17
if __name__ == '__main__':
g = Girl("Jane")
print(Girl.info("Jane", g.figure)) # Name : Jane Figure : (80, 80, 80)
或许,你灵机一动把info(name="", figure=())改为info(self,name="", figure=()) ,那么去看看会发生什么吧![1]
@classmethod
其实@classmethod和@staticmethod很难说到底有什么不同,水平有限,其具体用途留待探讨,此处只作简要说明。我们在code-12的基础上作如下修改:
# code-18
class Girl (Person):
# primary code here
@classmethod
def build(clazz):
print("ClassMethod")
运行:
# code-19
if __name__ == '__main__':
g = Girl("Jane")
Girl.build() # ClassMethod
注意:
@classmethod所装饰的函数,最少需要一个参数,并且这个参数就是当前类本身- 就调用而言,instancemethod_要宽泛于_staticmethod_和_classmethod(实例可以调用静态方法或者类方法,反之不可)
4. 某些属性
_dict_
__dict__主要保存的是实例的属性键值对,我们对code-12的代码作如下修改并运行:
# code-20
if __name__ == '__main__':
g = Girl("Jane")
print(g.__dict__) # {'hip': 80, 'name': 'Jane', 'bust': 80, 'waist': 80}
注意:@property所装饰的figure并没有作为属性被打印出来
_slots_
我们对code-12的代码作如下修改:
# code-07
class Girl (Person):
__slots__ = ("bust", "waist", "hip")
# primary code here
此时,Girl类应当只有三个属性:bust、waist、hip了,但是事实并非如此,我们运行如下代码:
# code-21
if __name__ == '__main__':
g = Girl("Jane")
g.age = 25
发现仍能通过,并且通过dir(g)可以查看到age属性,为什么呢?
原因在于:Girl的基类Person并没有用__slots__来限制属性,也就是说__slots__的作用范围仅仅包括当前类,所以:
# code-22
class Person(object):
__slots__ = ("name")
# primary code here
此时,再次运行code-21就会发现解释器会报错
这里的
self会被当作普通参数处理 ↩︎

浙公网安备 33010602011771号