设为首页 收藏本站
查看: 814|回复: 0

[经验分享] python面向对象高级编程

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2016-3-17 08:57:50 | 显示全部楼层 |阅读模式
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[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
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、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-191860-1-1.html 上篇帖子: python中的错误处理 下篇帖子: python之syslog模块 python
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表