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()的作用就在于把setattrgetattrdelattr三个函数给统一起来,如下所示:

# 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

注意:

  1. @classmethod所装饰的函数,最少需要一个参数,并且这个参数就是当前类本身
  2. 就调用而言,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类应当只有三个属性:bustwaisthip了,但是事实并非如此,我们运行如下代码:

# 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就会发现解释器会报错


  1. 这里的self会被当作普通参数处理 ↩︎

posted @ 2017-05-06 14:00  bbbbest  阅读(255)  评论(0)    收藏  举报