python面向对象高级编程
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python面向对象高级编程相关的知识,希望对你有一定的参考价值。
python中属性和方法的动态绑定
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__变量的作用就是限制该类实例能添加的属性:
class Student(object): __slots__ = (‘name‘, ‘age‘)
在创建Student实例的时候只能动态绑定name和age这两个属性。
__slots__定义的属性仅对当前类实例起作用,对继承的子类不起作用。
python的@property装饰器
@property是python内置的装饰器,它的作用就是把一个方法变成属性访问。
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
s = Student() s.score = 60 # 实际转化为s.set_score(60) s.score # 实际转化为s.get_score() 60
只定义getter方法,不定义setter方法就是一个只读属性
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的多重继承
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...")
类的多继承
class Dog(Mammal, Runnable): pass class Bat(Mammal, Flyable): pass
python中的MixIn
MixIn的作用就是为了更好地看出继承关系,目的就是给一个类增加多个功能,这样在设计类的时候,我们有限考虑通过多重继承来组合多个MixIn的功能 ,而不是设计多层次的复杂的继承关系。
python自带库使用MixIn的实例举例:
TCPSserver和UDPServer要同时服务多个用户就必须使用多进程或多线程模型。这两种模型由ForkingMixIn和ThreadingMixIn提供。
多进程的TCP服务:
class MyTCPServer(TCPServer, ForkingMixIn): pass
多线程的UDP服务:
class MyUDPServer(UDPServer, ThreadingMixIn): pass
更先进的协程模型,编写一个CoroutineMixIn:
class MyTCPServer(TCPServer, CoroutineMixIn): pass
python定制类
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)
s = Student(‘Michael‘) s 0x345ldf05d
直接显示变量调用的不是__str__(),而是__repr__()。
__str__()和__repr__()的区别是:__str__()返回用户看到的字符串,__repr__()返回程序开发者看到的字符串__repr__()是为调试服务的。
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退出循环。
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__()方法:
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。 需要对该参数做判断。
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
f = 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__()方法直接在实例本身上调用,直接对实例调用。
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的枚举类
定义一个枚举类:
from enum import Enum Month = Enum(‘Month‘, (‘Jan‘, ‘Feb‘, ‘Mar‘, ‘Apr‘, ‘May‘, ‘Jun‘, ‘Jul‘, ‘Aug‘, ‘Sep‘, ‘Oct‘, ‘Nov‘, ‘Dec‘))
枚举类的使用:
直接使用Month.Jan来引用一个常量,或者枚举它的所有成员。
for name, member in Month.__members__.items(): print(name, ‘=>‘, member, ‘,‘, member.value)
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的方法名称与函数绑定,
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允许你创建类或修改类
元类使用的实例:
# 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:
class MyList(list, metaclass=ListMetaclass): pass
在创建MyList类的时候要通过ListMetaclass.__new__()来创建,我们可以修改类的定义,加上新的方法,返回修改后的定义。
__new__()方法接收到的参数依次是:
当前准备创建的类的对象
类的名字
类继承的父类集合
类的方法集合
一般情况下不会遇到metaclass,在使用ORM的时候总会遇到需要通过metaclass修改类定义的。
ORM--object relational mapping,对象-关系映射。就是把关系数据库的一行映射为一个对象,也就是一个类对应一个表,这样写代码更简单,不用直接操作sql语句。
要编写一个ORM框架,所有的类都只能动态定义,因为只有使用者才能根据表的结构定义出对应的类来。
一个简单的ORM框架实例:
class User(Model): # 定义类的属性到列的映射 id = IntegerField(‘id‘) name = StringField(‘username‘) email = StringField(‘email‘) password = StringField(‘password‘) # 创建一个实例 u = User(id = 123, name=‘Michael‘, email=‘[email protected]‘, password=‘my-pwd‘) # 保存到数据库 u.save()
按上面的接口来实现该ORM
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
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‘)
以上是关于python面向对象高级编程的主要内容,如果未能解决你的问题,请参考以下文章