Python Class System
2014-03-18 15:51
337 查看
1.序言
本文旨在说明:在Python里自定义class时,方法的第一个参数必须是该class的instance自身的引用(一般用self命名)。在其他语言里,定义方法的时候,第一个参数不必是类实例的引用,一般约定俗成用this关键字来表示当前实例的引用,可是Python自成一派。由于网络上绝大部分文章都说成这是硬性规定,因此笔者觉得很有必要去研究一下Python里的classSystem是如何构筑起来的,并在此基础上说明self一词的作用。
2.面向对象编程
对象是数据和对数据的相关操作的封装。属于对象的数据与操作也可以称之为对象的属性(attributes)。对象具有层次构造,最下层的称之为instance,在其之上的称为class。class也具有层次构造,下层class会继承上层class的属性。有必要的时候可以再定义上层的属性。在Python里,一个class可以继承多个class(多重继承)。更多内容详见
3.Python里class的一般写法
首先,我们使用Python的classsystem来写一段程序。IT公司“LiveGate”雇佣了大量的IT技术人员,并用Python写了一个管理技术人员信息的程序。理应用数据库来储存这些信息,但这里出于演示方便就不使用了。接着我们看一下表示IT技术人员的class的代码:
[code1](workers.py)
代码
01:#!/usr/bin/envpython
02:
03:"""
04:WorkersinaITcompanynamedLiveGate
05:"""
06:
07:classWorkers:
08:"""Thisisaclassofworkersworkinginthecompany."""
09:
10:def__init__(self,name,position,email,age,salary):
11:self.name=name
12:self.position=position
13:self.email=email
14:self.age=age
15:self.salary=salary
16:
17:
18:classITWorkers(Workers):
19:"""ThisisaclassofITengineers."""
20:
21:OS='WinNT'
22:
23:def__init__(self,language,*av):
24:Workers.__init__(self,*av)
25:self.language=language
26:
27:defwork(self,n):
28:"""ITengineersshouldwork."""
29:
30:ifself.position=='webcreator':
31:w='makeswebsite'
32:elifself.position=='serveradministrator':
33:w='checksthetrafic'
34:elifself.position=='programmer':
35:w='writesprograms'
36:
37:print'%s%sfor%d,hoursusing%son%s'%(self.name,w,n,self.language,self.OS)
38:
39:##------------------------------------------------------------------------------------------------
40:henley=ITWorkers('PHP','Henley','webcreator','henley@livegate.com',32,700)
41:thomas=ITWorkers('Python','Thomas','serveradministrator','thomas@livegate.com',37,900)
42:gates=ITWorkers('C','Gates','programmer','gates@livegate.com',42,1200)
43:
44:henley.OS='Mac'
45:thomas.OS='Linux'
46:
47:if__name__=='__main__':
48:
49:henley.work(8)
50:thomas.work(7)
51:gates.work(10)
D:\doc\05-07\py_test>pythonworkers.py
Henleymakeswebsitefor8hours,usingPHPonMac
Thomaschecksthetraficfor7hours,usingPythononLinux
Gateswritesprogramsfor10hours,usingConWinNT
4.假如Python没有classsystem?
这里我们思考一下,假如Python没有classsystem,我们应该如何处理这种情况呢。当然,可以不使用OOP来写程序,但在这里,我们想创建属于自己的classsystem。实际上,使用把函数当成数据一样来对待的编程语言(广义上指函数式语言)来创建OOP语言是非常简单的。可以使用hash表(Python里称字典)来表示各个对象的名字空间,对象的层次构造也可以根据hash表的层次结构来表示。由于Python也是把函数当成数据来对待,所以很容易实现OOP。
我们尝试用自己的classsystem来重新把workers.py写一遍。参考重新编写的代码,那您应该明白方法的第一个参数为什么是self了。
[code2](workers2.py)
代码
01:#!/usr/bin/envpython
02:
03:"""
04:Thiscodedemostrateshoweasytoimprementanobjectorientatedsystemonafunctionalprogramminglanguage.
05:Itonlyrequiresanestedhashtable.
06:"""
07:
08:
09:defCls(cls=None,**key):
10:"""makinganewclass"""
11:key['class']=cls
12:returnkey
13:
14:defnew(cls,**key):
15:"""makinganinstance"""
16:key['class']=cls
17:returnkey
18:
19:
20:defgeta(obj,attr):
21:"""gettingtheattributeofobject"""
22:ifattrinobj:
23:returnobj[attr]
24:elif(obj['class']):
25:returngeta(obj['class'],attr)
26:else:
27:returnNone
28:
29:deftell(obj,method,*av):
30:"""tellobjectdosomething"""
31:fun=geta(obj,method)
32:ifcallable(fun):
33:returnfun(obj,*av)
34:
35:if__name__=='__main__':
36:
37:defit_work(self,n):
38:"""ThisfuncitondemonstrateshowITengineerswork.
39:Noticethatargumentsofthiefunctionisidenticaltothemethod'work'inworkers.py"""
40:
41:ifgeta(self,'position')=='webcreator':
42:w='makeswebsite'
43:elifgeta(self,'position')=='serveradministrator':
44:w='checksthetrafic'
45:elifgeta(self,'position')=='programmer':
46:w='writesprograms'
47:
48:print'%s%sfor%d,hoursusing%son%s'%
(geta(self,'name'),w,n,geta(self,'language'),geta(self,'OS'))
49:
50:workers=Cls()#dummyclass
51:it_workers=Cls(workers,OS='winNT',work=it_work)#classofITworkers
52:
53:henley=new(it_workers,language='PHP',name='henley',
54:position='webcreator',email='henley@livegate.com',age=32,salary=700)
55:thomas=new(it_workers,language='Python',name='Thomas',
56:position='serveradministrator',email='thomas@livegate.com',age=37,salary=900)
57:gates=new(it_workers,language='C',name='Gates',
58:position='programmer',email='gates@livegate.com',age=42,salary=1200)
59:henley['OS']='Mac'
60:thomas['OS']='Linux'
61:
62:tell(henley,'work',8)
63:tell(thomas,'work',7)
64:tell(gates,'work',10)
代码
D:\doc\05-07\py_test>pythonworkers2.py
Henleymakeswebsitefor8hours,usingPHPonMac
Thomaschecksthetraficfor7hours,usingPythononLinux
Gateswritesprogramsfor10hours,usingConwinNT
对比[code1]与[code2],可以看出他们相似的地方:
[code1] | [code2] |
---|---|
obj.attribute | geta(obj,'attribute') |
obj.method(*av) | tell(obj,'method',*av) |
defwork(self,n) | defit_work(self,n) |
D:\doc\05-07\py_test>python
Python2.4.1(#65,Mar302005,09:13:57)[MSCv.131032bit(Intel)]onwin32
Type"help","copyright","credits"or"license"formoreinformation.
[x]>>>importsys
[x]>>>fromworkersimport*
[1]>>>gates.__dict__
{'salary':1200,'name':'Gates','language':'C','age':42,'position':'programmer',
'email':'gates@livegate.com'}
[2]>>>henley.__dict__
{'salary':700,'name':'Henley','language':'PHP','age':32,'position':'webcreator',
'OS':'Mac','email':'henley@livegate.com'}
[3]>>>ITWorkers.__dict__
{'__module__':'workers','work':<functionworkat0x00A34630>,'OS':'WinNT',
'__doc__':'ThisisaclassofITengineers.','__init__':<function__init__
at0x00A345F0>}
[4]>>>ITWorkers.work(gates,10)
Gateswritesprogramsfor10,hoursusingConWinNT
[5]>>>gates.__class__.work(gates,10)
Gateswritesprogramsfor10,hoursusingConWinNT
[6]>>>getattr(henley,'OS')
'Mac'
[7]>>>getattr(henley,'work')
<boundmethodITWorkers.workof<workers.ITWorkersinstanceat0x00A33760>>
[8]>>>getattr(henley,'work')(8)
henleymakeswebsitefor8hours,usingPHPonMac
导入sys和workers模块,然后试试敲进上面的8行命令。Gates的名字空间里([1])有各类项目(entry),但是没有'OS'这一项。Henley的名字空间里([2])有定义'OS'。ITWorkers的名字空间里([3])除了预置的__module__,__doc__,还有我们定义的'OS',work,__init__。特别的,方法(<functionworkat0x00A34630>)作为函数被保存在内存里。正如前面提及的一样,Henley使用自身定义的'OS',而Gates则向上搜寻,使用类ITWorkers里的'OS'('OS'不存在Gates这个名字空间里)。
因为在类ITWorkers里定义了函数work,我们可以试着像[4]那样直接调用它。其输出跟调用gates.work(10)一样。由于每个实例有一个内置属性,__class__,它指向该实例所属的类,所以我们可以像[5]那样调用方法且得到相同的结果。
最后我们试试getattr函数。像[6]那样,getattr(henley,'OS')得到的结果跟henley.OS一样。我们把它应用到方法上看看([7])。返回如下结果:
<boundmethodITWorkers.workof<workers.ITWorkersinstanceat0x00A33760>>
<workers.ITWorkersinstanceat0x00A33760>这是Henley在内存中的地址。这个函数不用'function'而用'boundmethod'表示。其实'boundmethod'可以像[8]那样调用。这就说明了为什么从外部调用类方法的时候,第一个参数不必是实例自身的引用。不过,真正的理由应该是那样的做法不够酷:p。'boundmethod'可以看做是[code2]里tell函数的语法糖(構文糖衣)。
从上面可以看出,在函数式语言里引入classsystem时,作为方法而定义的函数,很自然地,需要指向实例的参数。通过def关键字,在类里面定义过程与定义普通的函数一样,只是其作用域被限定在class里面。所以定义方法的第一个参数必须是self,否则不能引用实例里的变量。
5.结语
Python基本上是函数式语言(广义的),面向对象是其使用hash表后的附属物而已。这一点与原本作为面向对象编程语言而设计的C++,Java,Ruby等相异。Python把过程的定义合并成函数的定义(没有将函数的定义与方法的定义区分开来),但在定义方法时,第一个参数必须是实例的引用。这是约定俗成的。
函数式语言要比面向对象语言更加抽象。Python深受函数式语言Haskell的影响。实际上,像[code2]所示的那样,函数式语言可以简单地实现面向对象编程。
本文出处:
相关文章推荐
- Python Class System
- Python Class System,Python self,面向对象和过程的一致性
- Python Class System
- Python Class System
- ClassNotFoundException: com.and.web.system.listener.OnlineListener
- ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext的区别是什么?
- 普通web项目转换为Maven, 解决 Field 'SYSTEM_PROPERTIES_MODE_ENVIRONMENT' not found in class
- python class属性
- 深刻理解Python中的元类(metaclass)
- Python使用sort和class实现的多级排序功能示例
- 开始学点System.Net NameSpace的Class拉
- 数学模型 机器学习 系统聚类(system clustering) Python实现
- ClassPathXmlApplicationContext 和FileSystemXmlApplicationContext的区别
- Python执行系统命令的方法 os.system(),os.popen(),commands
- python定义类(class)的语法,
- Fragment:java.lang.ClassNotFoundException: android.view.fragment in loader dalvik.system.PathClassLo
- python调用Shell脚本:os.system(cmd)或os.popen(cmd)
- Python调用turtle module来画画:理解类class的概念
- java.lang.UnsatisfiedLinkError: Couldn't load memchunk from loader dalvik.system.PathClassLoader
- python 获取当前运行的 class 的名字