23ewrw 发表于 2016-3-17 08:57:50

python面向对象高级编程

python中属性和方法的动态绑定


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Student(object):
    pass

# 实例化一个对象   
s = Student()
# 给这个对象绑定一个属性name
s.name = 'John'

print(s.name)
John

# 定义一个方法
def set_age(self, age):
    self.age = age

# 导入模块   
from types import MethodType

#给s这个对象绑定一个set_age的方法
s.set_age = MethodType(set_age, s)

s.set_age = 30
s.age
25


# 给实例对象绑定的方法只对该实例有效。


# 给所有的实例绑定方法的做法是给类绑定方法
def set_score(self, score):
    self.score = score

Student.set_score = MethodType(set_score, Student)

# 给类绑定方法后,所有实例均可调用





python中的__slots__变量
__slots__变量的作用就是限制该类实例能添加的属性:

1
2
class Student(object):
    __slots__ = ('name', 'age')





在创建Student实例的时候只能动态绑定name和age这两个属性。
__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用。


python的@property装饰器
@property是python内置的装饰器,它的作用就是把一个方法变成属性访问。
1
2
3
4
5
6
7
8
9
10
11
class Student(object):
    @property
    def score(self):
      return self._score
    @score.setter
    def score(self, value):
      if not isinstance(value, int):
            raise ValueError('score must be an integer!')
      if value<0 or value>100:
            raise ValueError('score must between 0 ~ 100!')
      self._score = value





1
2
3
4
s = Student()
s.score = 60 # 实际转化为s.set_score(60)
s.score # 实际转化为s.get_score()
60





只定义getter方法,不定义setter方法就是一个只读属性
1
2
3
4
5
6
7
8
9
10
class Student(object):
    @property
    def birth(self):
      return self._birth
    @birth.setter
    def birth(self, value):
      self._birth = value
    @property
    def age(self):
      return 2015 - self._birth




birth有读写,age是只读

python的多重继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Animal(object):
    pass
class Mammal(Animal):
    pass
class Bird(Animal):
    pass
class Dog(Mammal):
    pass
class Bat(Mammal):
    pass
class Parrot(Bird):
    pass
class Ostrich(Bird):
    pass
class Runnable(object):
    def run(self):
      print("Running...")
class Flyable(object):   
    def fly(self):      
      print("Flying...")




类的多继承

1
2
3
4
class Dog(Mammal, Runnable):
    pass
class Bat(Mammal, Flyable):
    pass





python中的MixIn
MixIn的作用就是为了更好地看出继承关系,目的就是给一个类增加多个功能,这样在设计类的时候,我们有限考虑通过多重继承来组合多个MixIn的功能 ,而不是设计多层次的复杂的继承关系。

python自带库使用MixIn的实例举例:
TCPSserver和UDPServer要同时服务多个用户就必须使用多进程或多线程模型。这两种模型由ForkingMixIn和ThreadingMixIn提供。

多进程的TCP服务:

1
2
class MyTCPServer(TCPServer, ForkingMixIn):
    pass





多线程的UDP服务:

1
2
class MyUDPServer(UDPServer, ThreadingMixIn):
    pass





更先进的协程模型,编写一个CoroutineMixIn:

1
2
class MyTCPServer(TCPServer, CoroutineMixIn):
    pass







python定制类

1
2
3
4
5
class Student(object):   
    def __init__(self, name):
      self.name = name
def __str__(self):      
      return 'Student object (name: %s)' % self.name





1
2
print(Student('Michael'))
Student object (name: Michael)





1
2
3
s = Student('Michael')
s
0x345ldf05d





直接显示变量调用的不是__str__(),而是__repr__()。
__str__()和__repr__()的区别是:__str__()返回用户看到的字符串,__repr__()返回程序开发者看到的字符串__repr__()是为调试服务的。

1
2
3
4
5
6
class Student(object):   
    def __init__(self, name):      
      self.name = name
def __str__(self):
    return 'Student object (name=%s)' % self.name
    __repr__ = __str__





一个类想被用于for循环中,必须实现一个__iter__()方法,返回一个迭代对象,然后for循环就会不断调用该迭代对象的__next__()方法拿到循环的下一个值,直到StopIteration退出循环。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Fib(object):   
    def __init__(self):
      self.a, self.b = 0, 1
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
for n in Fib():
    print(n)
1
1
2
3
5
.
.
.
46368





如果想把一个类表现成list那样取出元素,需要实现__getitem__()方法:

1
2
3
4
5
6
class Fib(object):
    def __getitem__(self, n):
      a, b = 1, 1
      for x in range(n):
            a, b = b, a+b
      return a




如果这个类实现的__getitem__()方法,就可以把这个类当成list来操作,但是需要判断__getitem__()方法传入的参数的类型。 该参数可能是一个int,也可能是一个切片对象slice。 需要对该参数做判断。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Fib(object):
    def __getitem__(self, n):
      if isinstance(n, int):
            a, b = 1, 1
            for x in range(n):
                a, b = b, a+b
            return a
      if isinstance(n, slice):
            start = n.start
            stop = n.stop
            if start is None:
                start = 0
            a, b = 1, 1
            L = []
            for x in range(stop):
                if x >= start:
                  L.append(a)
                a, b = b, a+b
            return L





1
2
3
4
5
f = Fib()
f

f[:10]





对一个__getitem__()方法的参数做判断。并对此进行做其他工作。对step的处理,对负数的处理,等等。

__getattr__():该方法动态返回一个属性。
当调用一个不存在的属性的时候,python会试图调用__getattr__(self, 'score')来尝试获得属性。

__call__()方法直接在实例本身上调用,直接对实例调用。

1
2
3
4
5
6
7
8
9
class Student(object):
    def __init__(self, name):
      self.name = name
    def __call__(self):
      print("My name is %s." % self.name)

s = Student('Michael')
s()
My name is Michael.




__call__()定义参数。

判断一个变量是对象还是函数,更多的时候我们判断一个对象是否能被调用。能被调用的对象就是一个callable对象。


python的枚举类
定义一个枚举类:

1
2
from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))




枚举类的使用:
直接使用Month.Jan来引用一个常量,或者枚举它的所有成员。

1
2
for name, member in Month.__members__.items():
    print(name, '=>', member, ',', member.value)





1
2
3
4
5
6
7
8
9
10
form enum import Enum, unique
@unique
class Weekday(Enum):
    Sun = 0
    Mon = 1
    Tue = 2
    Wed = 3
    Thu = 4
    Fri = 5
    Sat = 6




@unique装饰器保证没有重复值。


python使用元类
type()函数可以查看一个类型或变量的类型,还可以创建出新的类型。

通过type()函数创建一个class对象需传入3 个参数:

[*]class的名称。

[*]继承的父类集合,注意python的多继承。

[*]class的方法名称与函数绑定,



1
2
3
4
5
6
7
8
9
10
def fn(self, name='world'):
    print('Hello, %s.' % name)

Hello = type('Hello', (object,), dict(hello=fn))
h = Hello()
h.hello()

print(type(Hello))

print(type(h))





metaclass的作用就是控制类的创建行为。
我们想创建类就必须根据metaclass创建出类,先定义metaclass,再创建类。
metaclass允许你创建类或修改类
元类使用的实例:


1
2
3
4
5
# metaclass是类的模版,所以必须从‘type’类型派生:
class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
      attrs['add'] = lambda self, value: self.append(value)
      return type.__new__(cls, name, bases, attrs)




有了ListMetaclass,我们在定义类的时候还是要指示使用ListMetaclass来定制类,传入关键字参数metaclass:

1
2
class MyList(list, metaclass=ListMetaclass):
    pass




在创建MyList类的时候要通过ListMetaclass.__new__()来创建,我们可以修改类的定义,加上新的方法,返回修改后的定义。
__new__()方法接收到的参数依次是:

[*]当前准备创建的类的对象

[*]类的名字

[*]类继承的父类集合

[*]类的方法集合



一般情况下不会遇到metaclass,在使用ORM的时候总会遇到需要通过metaclass修改类定义的。
ORM--object relational mapping,对象-关系映射。就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样写代码更简单,不用直接操作sql语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
一个简单的ORM框架实例:

1
2
3
4
5
6
7
8
9
10
11
class User(Model):
    # 定义类的属性到列的映射
    id = IntegerField('id')
    name = StringField('username')
    email = StringField('email')
    password = StringField('password')

# 创建一个实例
u = User(id = 123, name='Michael', email='Michael@example.org', password='my-pwd')
# 保存到数据库
u.save()




按上面的接口来实现该ORM

1
2
3
4
5
6
class Field(object):
    def __init__(self, name, column_type):
      self.name = name
      self.column_type = column_type
    def __str__(self):
      return '<%s:%s>' % (self.__class__.__name__, self.name)




定义各种类型的Field

1
2
3
4
5
6
7
class StringField(Field):
    def __init__(self, name):
      super(StringField, self).__init__(name, 'varchar(100)')

class IntegerField(Field):
    def __init__(self, name):
      super(IntegerField, self).__init__(name, 'bigint')






页: [1]
查看完整版本: python面向对象高级编程