面向对象高级编程

1、单下划线:开始的成员变量叫 保护变量(protected)  只有类对象和子类对象自己能访问到这些变量

双下划线:开始的是 私有成员(private) 只有类对象自己能访问,连子类对象也不能访问

注:以单下划线开头(_foo)的代表不能直接访问的类属性,需通过类提供的接口进行访问,不能用“from xxx import *”而导入;以双下划线开头的(__foo)代表类的私有成员;以双下划线开头和结尾的(__foo__)代表python里特殊方法专用的标识,如 __init__()代表类的构造函数。

2、__slots__

正常情况下,定义一个class,创建一个class的实例后,可以给该实例绑定任何属性和方法,这就是动态语言的灵活性

class Student(object):

  pass

然后,尝试给实例绑定一个属性:

s=Student()

s.name='zhu'

print s.name    zhu

尝试给实例绑定一个方法:

def set_age(self,age):

  self.age=age

from types import MethodType

s.set_age=MethodType(set_age,s,Student)  给实例绑定一个方法

s.set_age(25)

s.age  打印出25

但是给一个实例绑定的方法,对另一个实例是不起作用的,为了给所有实例绑定方法,可以给类class绑定方法:

def set_score(self,score):

  self.score=score

Student.set_score=MethodType(set_score,None,Student)  给类绑定一个方法

所以class绑定方法后,所有实例都可以调用

s.set_score(100)  则s.score=100

s2=set_score(99)  则s2.score=99

 

思考:上面例子中,完全可以把set_score方法直接定义在class中,单动态绑定允许我们在程序运行的过程中动态给class加上功能;这在静态语言中很难实现

如果想要限制class的属性,只允许Student实例添加name和age属性???

为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制class能添加的属性

注:__slots__定义的属性仅对当前类起作用,对继承的子类时不起作用的;除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__

class Student(object):

  __slots__=('name','age')  用tuple定义允许绑定属性名称

s=Student()

s.age=25

s.name='zhu'

s.score=99  报AttributeError错误

 

3、@property:python内置的,负责把一个方法变成属性调用

在绑定属性时,我们直接把属性暴露出去,虽然写起来简单,但是没有检查参数,导致成绩随便改

s=Student()

s.score=999

这显然不和逻辑,为了限制score的范围,通过set_score()方法设置成绩,set_score()来获取成绩,这样在set_score()方法中就可以检查参数了:

使用@property

@property广泛用在类的定义中,可以让调用者写出减短的代码,同时保证对参数进行必要的检查,这样程序在运行时就减少了出错的可能性

 

4、多重继承;;Mixin的目的是给一个类增加多个功能;由于Python允许使用多重继承,因此,Mixin就是一种常见的设计

 

5、定制类:python的class中还有许多这样有特殊用途的函数,可以帮助我们定制类

  ①__str__

class Student(object):
...     def __init__(self, name):
...         self.name = name
...     def __str__(self):
...         return 'Student object (name: %s)' % self.name
print Student('Michael')
Student object (name: Michael)

 若没有__str__()函数则打印结果是:<__main__.Student object at 0x109afb190>

若直接敲变量s还是>>>s=Student(‘Micheal’)

         >>>s  则<__main__.Student object at 0x109afb190>,这是因为直接显示变量调用的不是__str__(),而是__repr__()

两者区别:__str__() :返回用户看到的字符串

     __repr__() :返回程序开发者看到的字符串,就是为调试用的

def __str__(self):
...      return 'Student object (name: %s)' % self.name
__repr__=__str__

这样直接单调用实例s时,>>>s  则Micheal

  ②__iter__

如果一个类想被用于for ... in循环,类似list或tuple那样,就必须实现一个__iter__()方法,该方法返回一个迭代对象,然后,Python的for循环就会不断调用该迭代对象的next()方法拿到循环的下一个值,直到遇到StopIteration错误时退出循环。

以斐波那契数列为例,写一个Fib类,可以作用于for循环:

class Fib(object):
    def __init__(self):
        self.a, self.b = 0, 1   # 初始化两个计数器a,b

    def __iter__(self):
        return self   # 实例本身就是迭代对象,故返回自己

    def next(self):
        self.a, self.b = self.b, self.a + self.b   # 计算下一个值
        if self.a > 100000:   # 退出循环的条件
            raise StopIteration();
        return self.a   # 返回下一个值

现在,试试把Fib实例作用于for循环:

>>> for n in Fib():
...     print n
...
1
1
2
3
posted @ 2016-05-27 15:02  潇竹  阅读(198)  评论(0编辑  收藏  举报