0%

Python 教程学习之 Python 面向对象编程

前言

在之前的学习中,基本上都是使用类似于面对过程的方式来写代码,学习各种 Python 的基础知识,接下来,我们需要继续学习面向对象的Python,也就是类对象继承等概念。

对象和属性,这些概念在任务编程语言中,其定义都是一致的。我们通过一个对象来表示一个物体,而这个物体的一些特征,就是对象中的属性。比如,一个人,作为一个对象 Person,则会有姓名,身高,体重,性别,出生日期等属性,这些属性就是这个人的对外特性了。

Python 面向对象编程介绍

类,就是对一类物体进行抽象的表示,比如上面的 Person;而实例,则是具体化了每一个类的属性值,其可以决定某一个物体特征的对象。

在 Python 中,可以如下来定义一个类:

1
2
3
4
5
6
7
8
9

class Person(object):

"""docstring for Person"""

def __init__(self, name):
super(Person, self).__init__()
self.__name = name

class 用来表示这是一个类,object 表示该类继承的父类,默认是 object,但是推荐是写上父类,即使其继承 object类。

Tips:Python 中,默认规定,类下面的第一行注释,是该类的 doc 说明。

此外,__xx__形式的属性和方法,在Python中都是有特殊用途的,比如 len 方法返回长度,再比如 init 方法是类对象初始化时调用的,new 方法则是构造对象的时候调用的,即在 __init__ 之前调用。

接下来,需要说明的是,Python 的权限控制。

和 Java 完全不一样,Python 没有关键字来说明该变量属性或者方法是 私有的 还是受保护的,亦或者是公共的。

Python 使用一种约定的方式来,声明访问限制的粒度。

  • xx :这种方式命名的变量或者方法,都是 public粒度的;

  • _xx :这种方式命名的变量或者方法,都是 protected粒度的;

  • __xx :私有属性的变量或者方法,外部调用会报错的。

Python 中拥有的一些特殊功能的方法:

  • type() :获取对象的类型,比如,type(‘abc’)会返回 <type 'str'> .

  • isinstance():type 方法不能很好的判断拥有继承关系的对象,而 isinstance 则可以。例如:isinstance(person,object) #person是Person的实例.

  • dir():想要获取一个类下面所有的方法吗?使用 dir 就可以了,比如dir('abc')

  • hasattr/getattr/setattr():依次是判断一个对象是否有指定属性,获取该属性,设置某个属性

Python 面向对象编程技巧

Python 中还有一些比较高大上的技巧。

@property装饰器

装饰器概念,在 Python 函数式编程 中已经介绍了。我们在类的代码 coding 中,有一些可能想要把方法使用如同属性使用般方便,则可以使用@property装饰器。

注解方式,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12

@property
def age(self):
try:
return self.__age
except Exception, e:
return 0

@age.setter
def age(self, value):
self.__age = value

metaclass 元类

Python 中,元类是一个很神奇的东西,由于其涉及到了底层的类结构构造,所以全部深入理解起来,可能会比较复杂。

关于元类的资料,可以参考http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python,第一个 answer 回答的特别棒。

当我们定义了类以后,就可以根据这个类创建出实例,所以:先定义类,然后创建实例。

但是如果我们想创建出类呢?那就必须根据metaclass创建出类,所以:先定义metaclass,然后创建类。

连接起来就是:先定义metaclass,就可以创建类,最后创建实例。

所以,metaclass允许你创建类或者修改类。换句话说,你可以把类看成是metaclass创建出来的“实例”。

现在,一个简单的示例,就是,对于该类所有的自定义属性,其name都大写。

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

class Female(Person.Person):

"""docstring for Female"""

def log_construct(class_name, class_parent, class_attr):
logging.info('==----==---contruct---===---')
upper_attr = {}
for key, value in class_attr.items():
if key.startswith('__'): # 不能改变class自带的属性
upper_attr[key] = value
else:
upper_attr[key.upper()] = value

return type(class_name, class_parent, upper_attr)

def __init__(self, name, married):
Person.Person.__init__(self, name)
self.__married = married

__metaclass__ = log_construct

if __name__ == '__main__':
felame = Female('ketao1989', False)
felame.age = 100
print felame

print hasattr(Female, 'MARRIED') # 返回Ture

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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2015-02-22 19:49:20
# @Author : ketao1989
# @Version : $Id$


import sys
import os
import json

reload(sys)
sys.setdefaultencoding('utf8')


class Person(object):

"""docstring for Person"""

def __init__(self, name):
super(Person, self).__init__()
self.__name = name

@property
def name(self):
return self.__name

@name.setter
def name(self, value):
self.__name = value

def get_name(self):
return self.__tranform_name(self.name)

def __tranform_name(self, name):
return name + "_test"

@property
def age(self):
try:
return self.__age
except Exception, e:
return 0

@age.setter
def age(self, value):
self.__age = value

def __str__(self):
return "%s 's age is : %s" % (self.get_name(), self.age)

if __name__ == '__main__':
person = Person('ketao1989')
person.age = 10
print person.name
print person
print os.uname()
print os.getenv('PATH')
print dir('abc')

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : 2015-02-22 20:34:46
# @Author : ketao1989
# @Version : $Id$


import sys
import Person
import logging
import json

reload(sys)
sys.setdefaultencoding('utf8')
logging.basicConfig(level=logging.INFO)


class Female(Person.Person):

"""docstring for Female"""

def log_construct(class_name, class_parent, class_attr):
logging.info('==----==---contruct---===---')
upper_attr = {}
for key, value in class_attr.items():
if key.startswith('__'): # 不能改变class自带的属性
upper_attr[key] = value
else:
upper_attr[key.upper()] = value

return type(class_name, class_parent, upper_attr)

def __init__(self, name, married):
Person.Person.__init__(self, name)
self.__married = married

__metaclass__ = log_construct

@property
def married(self):
return self.__married

@married.setter
def married(self, value):
self.__married = value

def get_name(self):
return self.name + "_Female____"

def __str__(self):
prefix = Person.Person.__str__(self)
return prefix + ",married is : %s" % str(self.MARRIED)

if __name__ == '__main__':
felame = Female('ketao1989', False)
felame.age = 100
print felame

print hasattr(Female, 'MARRIED')

print Female
print hasattr(Female, 'job')
felame.job = 'dev'
print hasattr(felame, 'job')
print felame.name

felame1 = Female('ketao', True)
print hasattr(Female, 'job')
print hasattr(felame1, 'job')
print hasattr(felame, 'job')
print felame.__class__.__class__
print json.dumps(felame, default=lambda obj: obj.__dict__)
json_str = '{"_Person__name": "ketao1989", "_Person__age": 100, "job": "dev", "_Female__married": false}'
felame2 = json.loads(json_str)
print felame2


Notes : 在Female类中,继承需要写成Person.Person的形式,前面的Person是module,后面的 Person才是类。

此外,使用metaClass方式更改属性时,只会修改该类自己的属性,而不会更改其继承的父类的属性名。