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
36class 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
2class Student(object):
__slots__ = ('name', 'age')
在创建Student实例的时候只能动态绑定name和age这两个属性。
__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用。
[email protected]
@property是python内置的装饰器,它的作用就是把一个方法变成属性访问。1
2
3
4
5
6
7
8
9
10
11class 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
4s = 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
10class 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
20class 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
4class Dog(Mammal, Runnable):
pass
class Bat(Mammal, Flyable):
pass
python中的MixIn
MixIn的作用就是为了更好地看出继承关系,目的就是给一个类增加多个功能,这样在设计类的时候,我们有限考虑通过多重继承来组合多个MixIn的功能 ,而不是设计多层次的复杂的继承关系。
python自带库使用MixIn的实例举例:
TCPSserver和UDPServer要同时服务多个用户就必须使用多进程或多线程模型。这两种模型由ForkingMixIn和ThreadingMixIn提供。
多进程的TCP服务:
1
2class MyTCPServer(TCPServer, ForkingMixIn):
pass
多线程的UDP服务:
1
2class MyUDPServer(UDPServer, ThreadingMixIn):
pass
更先进的协程模型,编写一个CoroutineMixIn:
1
2class MyTCPServer(TCPServer, CoroutineMixIn):
pass
python定制类
1
2
3
4
5class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'Student object (name: %s)' % self.name
1
2print(Student('Michael'))
Student object (name: Michael)
1
2
3s = Student('Michael')
s
0x345ldf05d
直接显示变量调用的不是__str__(),而是__repr__()。
__str__()和__repr__()的区别是:__str__()返回用户看到的字符串,__repr__()返回程序开发者看到的字符串__repr__()是为调试服务的。
1
2
3
4
5
6class 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
21class 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
6class 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
19class 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
5f = Fib()
f[0:5]
[1,1,2,3,5]
f[:10]
[1,1,2,3,5,8,13,21,34,55]
对一个__getitem__()方法的参数做判断。并对此进行做其他工作。对step的处理,对负数的处理,等等。
__getattr__():该方法动态返回一个属性。
当调用一个不存在的属性的时候,python会试图调用__getattr__(self, 'score')来尝试获得属性。
__call__()方法直接在实例本身上调用,直接对实例调用。
1
2
3
4
5
6
7
8
9class 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
2from enum import Enum
Month = Enum('Month', ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'))
枚举类的使用:
直接使用Month.Jan来引用一个常量,或者枚举它的所有成员。
1
2for name, member in Month.__members__.items():
print(name, '=>', member, ',', member.value)
1
2
3
4
5
6
7
8
9
10form 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
10def 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
2class 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
11class User(Model):
# 定义类的属性到列的映射
id = IntegerField('id')
name = StringField('username')
email = StringField('email')
password = StringField('password')
# 创建一个实例
u = User(id = 123, name='Michael', [email protected]', password='my-pwd')
# 保存到数据库
u.save()
按上面的接口来实现该ORM
1
2
3
4
5
6class Field(object):
def __init__(self, name, column_type):
self.name = name
self.column_type = column_type
def __str__(self):
return '' % (self.__class__.__name__, self.name)
定义各种类型的Field
1
2
3
4
5
6
7class 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')