习惯了C++和Java OO(面向对象)思想的程序员刚转到python会有些不习惯,python中对很多操作都做了简化,完全的面向过程编程也很容易(事实上很多人确实在这样做),但是实际上python针对类提供了很多有用的特性,了解这些可以编写更好的Python OO程序。
1.命名元组
默认的python元组访问时,需要按照序号访问,这样一是不易阅读二是扩展比较困难,python collections组提供了命名元组的功能解决此功能,元组直接当做对象,元素当做对象属性即可。
import collections
# 命名元组
def name_tuple_test():
User = collections.namedtuple('User', ['id', 'name', 'age', 'weight'])
u = User(12, 'jim wen', 20, 140)
print(u)
print(u.id, u.name, u.age, u.weight)
2.函数对象
编程中我们经常抽象一个公用模型,通过指定回调函数来完成功能的定制和补充,c++中可以指定函数指针来完成,但是函数指针的可扩展性和复用性有限,最常见的是需要针对不同情况给回调一个初始值,这种情况更常用的做法是指定函数对象(重载()操作符);而在java中我们通常是指定一个接口来完成回调。引入lamda表达式后,c++和java都可以借助lamda表达式减少回调编程工作。
而在python中我们因为所有的类或函数都是一级对象,所以常常习惯是直接指定函数。在一些扩展性要求更强的情况,需要我们使用函数对象,如下:
class FillDefaultValue():
def __init__(self, prefix):
self.__data = prefix
def __call__(self):
return "other value-%d" %self.__data
def function_object_test():
m = {"1": "one", "2": "two", "3": "three", "4": "four"}
m_wrap = collections.defaultdict(FillDefaultValue(0), m)
for i in xrange(1, 6):
print("Index:%d , Result:%s\n" % (i, m_wrap[str(i)]))
这里通过重载__call__实现函数对象,这里借助函数对象我们可以在生成函数对象时指定默认值。
3.操作符重写
OO编程中,重写操作符也是常用操作,特别在实现自定义数据结构时,为了和python内置操作保持同样范式,需要实现默认操作符重写。和java类似,python提供了指定操作类的基类接口,我们继承实现即可,这些接口在collections包中,如下我们实现一个最简单的List类,继承sequence基类:
class MyList(collections.Sequence):
def __init__(self):
self.__data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
def __getitem__(self, i):
return self.__data.__getitem__(i)
def __len__(self):
return len(self.__data)
def my_list_test():
l = MyList()
for i in xrange(0, len(l)):
print(l[i])
4.类泛型
简单点说:类制造对象,传入参数是数据;泛型制造类,传入参数是类。python中类型操作得到简化,通常我们只用到类->对象,但是有时会还是需要用到泛型。比如,需要定义一个函数来解析不同类型的Data,函数传入不同的类,需要制造出不同的类对象并用制造的对象解析数据。python中没有提供直接的泛型支持,但是通过classmethod属性可以完成类似操作,类成员函数第一个参数是self,即在类对象上操作,classmethod类函数第一个参数是类名,函数体中直接生产对应类对象,某种程度上简化了泛型的定义。
class GenericData():
def output(self):
pass
@classmethod
def create_class(cls, data):
return cls(data)
class JsonData(GenericData):
def __init__(self, data):
self.__data = json.loads(data, "utf-8")
def output(self):
print(self.__data['key'])
class XmlData(GenericData):
def __init__(self, data):
self.__data = ET.fromstring(data)
def output(self):
print(self.__data.tag, self.__data.text)
def dump_data_test(d, data):
d = d.create_class(data)
d.output()
如下调用:
dump_data_test(JsonData, '{"key":"Json Data"}')
dump_data_test(XmlData, '<key>Xml Data</key>')
即完成泛型功能。
演示代码下载链接
原创,转载请注明来自http://blog.csdn.net/wenzhou1219