您的位置:首页 > 编程语言 > Python开发

类和方法学习笔记(python)

2016-10-16 09:31 302 查看
类和方法
 
1、 
面向对象的特性
python是一门面向对象编程语言,它提供了一些语言特性来支持面向对象的编程。
 
  python提供的面向对象的编程特性,严格来说,不是必需的,他们大部分是我们已经做过的事情的另一种选择方案,但是在很多情况下,这种方案更简洁,更能准确的表达程序的结构。
方法(method):在类定义之内定义的函数,在类的实例上调用。
面向对象编程(object-orientedprogramming):一种编程风格,数据和修改数据的操作组织成类和方法的形式。
面向对象的语言(object-orientedlanguage):
一种提供诸如用户定义类型、方法语法之类的语言特性,以方便面向对象编程的语言。
主体(subject):
调用方法所在的对象。
方法和类在语义上是一样的,但在语法上又两个区别:
(1)      方法定义写在类定义之中,更明确的表示类和方法的关联;
(2)      调用方法和调用函数的语法形式不同。
 
2、 
打印对象
In[5]:
class Time(object):
   ...: """Represents
the time of day.
   ...:

   ...: attributes:
hour, minute, second
   ...: """
   ...: def print_time(t):
   ...: print '%.2d:%.2d:%.2d'
% (t.hour, t.minute, t.second)
   ...:

   ...:

In[6]:
start=Time()
   ...: start.hour=9
   ...: start.minute=45
   ...: start.second=00
(1)调用方式一
In[7]:
Time.print_time(start)
09:45:00
(2)另一种更简洁的调用方式
In[8]:
start.print_time()
09:45:00
在这里的句点表示法中,start是调用这个方法的对象,也称为主体(subject)。和一句话中主语用来表示这句话是关于什么东西一样,方法调用的主体表示这个方法是关于哪个对象的。在方法之中,主体会被赋值在一个形参上,所以本例中start被赋值到time上。
依惯例,方法的第一个形参通常叫做self,所以print_time通常写成:
def print_time(self):

   
print '%.2d:%.2d:%.2d' % (self.hour,self.minute, self.second)
也即:
In [10]: class Time(object):
    ...: """Represents the time of day.
    ...:

    ...: attributes: hour, minute, second
    ...: """
    ...: def print_time(self):
    ...: print '%.2d:%.2d:%.2d' % (self.hour,
self.minute,self.second)
    ...:

    ...:

In [11]: start=Time()
    ...: start.hour=9
    ...: start.minute=45
    ...: start.second=00
    ...:

    ...: print_time(start)
09:45:00
In [12]: start.print_time()
09:45:00
 
3、另外一个示例
In [55]: def int_to_time(seconds):
    ...: time = Time()
    ...: minutes, time.second = divmod(seconds,
60)
    ...: time.hour, time.minute = divmod(minutes,
60)
    ...: return time
    ...:

    ...:

    ...:

    ...: class Time(object):
    ...: """Represents the time of day.attributes:
hour, minute, second"""
    ...: def print_time(self):
    ...: print '%.2d:%.2d:%.2d' % (self.hour,
self.minute,self.second)
    ...:

    ...: def time_to_int(self):
    ...: minutes = self.hour * 60 + self.minute
    ...: seconds = minutes * 60 + self.second
    ...: return seconds
 
    ...:

    ...: def increment(self, seconds):
    ...: seconds += self.time_to_int()
    ...: return int_to_time(seconds)
    ...:

    ...:

 
In [56]: start=Time()
    ...: start.hour=0
    ...: start.minute=1
    ...: start.second=1
    ...:

 
In [57]: start.print_time()
00:01:01
 
In [58]: start.time_to_int()
    ...:

Out[58]: 61
 
In [59]: start.increment(5).time_to_int()
Out[59]: 66
 
In [60]: start.print_time()
00:01:01
 
In [61]: end=start.increment(10)
 
In [62]: end.print_time()
00:01:11
上述主体赋值给第一个形参self,实参10赋值给第二个形参seconds。
 

4、init方法
init方法(即“initialization”的简写)是一个特殊的方法,当对象初始化时会被调用。它的全民是_
_init_ _(无空格,两个下划线,接着是init,再接着是两个下划线)。Time类的初始化方法,可以如下所示:
In [74]: def int_to_time(seconds):
    ...: time = Time()
    ...: minutes, time.second = divmod(seconds,
60)
    ...: time.hour, time.minute = divmod(minutes,
60)
    ...: return time
    ...:

    ...:

 
In [75]: class Time(object):
    ...: """Represents the time of day.attributes:
hour, minute, second"""
    ...: def __init__(self, hour=0, minute=0,
second=0):
    ...: self.hour=hour
    ...: self.minute=minute
    ...: self.second=second
    ...:

    ...: def print_time(self):
    ...: print '%.2d:%.2d:%.2d' % (self.hour,
self.minute,self.second)
    ...:

    ...: def time_to_int(self):
    ...: minutes = self.hour * 60 + self.minute
    ...: seconds = minutes * 60 + self.second
    ...: return seconds
    ...:

    ...: def increment(self, seconds):
    ...: seconds += self.time_to_int()
    ...: return int_to_time(seconds)
    ...:

    ...:

 
In [76]: start=Time()
In [77]: start.print_time()
00:00:00
In [78]: start.time_to_int()
Out[78]: 0
In [79]: start.increment(5).time_to_int()
Out[79]: 5
In [80]: start.print_time()
00:00:00
In [81]: end=start.increment(10)
    ...:

In [82]: end.print_time()
00:00:10
对__init__:

(1) 如果你提供一个实参,它会覆盖hour;

(2) 如果提供两个实参,它会覆盖hour和minute;

(3) 如果提供三个实参,他们会覆盖全部三个默认值。
 
5、__str__方法
__str__方法与__init__方法类似,它用来返回对象的字符串表达形式。当打印时,Python会调用str方法。如下:
In [86]: class Time(object):
    ...: """Represents the time of day.attributes:
hour, minute, second"""
    ...: def __init__(self, hour=0, minute=0,
second=0):
    ...: self.hour=hour
    ...: self.minute=minute
    ...: self.second=second
    ...:

    ...: def __str__(self):
    ...: return '%.2d:%.2d:%.2d' % (self.hour,
self.minute, self.second)
    ...:

    ...: def time_to_int(self):
    ...: minutes = self.hour * 60 + self.minute
    ...: seconds = minutes * 60 + self.second
    ...: return seconds
    ...:

    ...: def increment(self, seconds):
    ...: seconds += self.time_to_int()
    ...: return int_to_time(seconds)
    ...:

    ...:

 
In [87]: start=Time()
    ...:

 
In [88]: print start
00:00:00
当编写一个新类时,可以这样开始:

(1) 先写__init__,以便初始化对象;

(2) 然后写__str__以便调试。
 

5、操作符重载
一些特殊符号,表示向加法乘法这样的运算。操作符所操作的值,称为操作对象。
通过定义其它特殊方法,可以为用户定义类型的各种操作指定行为。例如:如果为Time类定义一个__add__方法,则可以在时间对象上使用+操作符。从而,当你对时间对象应用“+”操作时,python会调用__add__,当你打印结果时,python会调用__str__。
 
 
 
In [96]: def int_to_time(seconds):
    ...: time = Time()
    ...: minutes, time.second = divmod(seconds,
60)
    ...: time.hour, time.minute = divmod(minutes,
60)
    ...: return time
    ...:

    ...:

 
In [97]: class Time(object):
    ...: """Represents the time of day.attributes:
hour, minute, second"""
    ...: def __init__(self, hour=0, minute=0,
second=0):
    ...: self.hour=hour
    ...: self.minute=minute
    ...: self.second=second
    ...:

    ...: def __str__(self):
    ...: return '%.2d:%.2d:%.2d' % (self.hour,
self.minute,self.second)
    ...:

    ...: def time_to_int(self):
    ...: minutes = self.hour * 60 + self.minute
    ...: seconds = minutes * 60 + self.second
    ...: return seconds
    ...:

    ...: def increment(self, seconds):
    ...: seconds += self.time_to_int()
    ...: return int_to_time(seconds)
    ...:

    ...: def __add__(self,other): #操作符重载
    ...: seconds=self.time_to_int()+other.time_to_int()
    ...: return int_to_time(seconds)
    ...:

    ...:

 
In [98]: start=Time(9,45)
 
In [99]: dutation=Time(1,35)
 
In [100]: print start+dutation
11:20:00
 
In [101]: start.increment(dutation.time_to_int())
Out[101]: <__main__.Time at
0xa0889b0>
 
In [102]: print start.increment(dutation.time_to_int())
11:20:00
修改操作符的行为以便它能够作于于用户定义类型,这个过程称为操作符重载。对于每一个操作符,python都提供了一个对应的特殊方法,比如:__add__,__or__,__lt__,__del__等。
 

6、基于类型的分发
def int_to_time(seconds):
   
time = Time()
   
minutes,time.second = divmod(seconds, 60)
   
time.hour,time.minute = divmod(minutes, 60)
   
return time
 
 
class Time(object):
   """Represents the time of day. attributes: hour, minute,second"""
   
def__init__(self, hour=0, minute=0, second=0):
       self.hour=hour
       self.minute=minute
       self.second=second
   

   
def__str__(self):
       
return'%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)
   

   
deftime_to_int(self):
       
minutes =self.hour * 60 + self.minute
       
seconds =minutes * 60 + self.second
       
returnseconds
           

   
defincrement(self, seconds):
       
seconds +=self.time_to_int()
       
returnint_to_time(seconds)
   

   
def__add__(self,other):
       
ifisinstance(other,Time):
           
returnself.add_time(other)
       
else:
           
returnself.increment(other)
       
            
   
defadd_time(self,other):  
       seconds=self.time_to_int()+other.time_to_int()
       
returnint_to_time(seconds)
 
In [116]: t1=Time(0,0,10)
     ...:

     ...: t2=Time(0,1,0)
 
In [117]: print t1+t2
00:01:10
 
In [118]: print t1+60
00:01:10
 
In [119]: print t1+61
00:01:11
 
然后,不满足交换律
In [120]: print 10+t1
Traceback
(most recent calllast):
 
File
"<ipython-input-120-b1ba7d83dd7a>", line
1,in
<module>
print 10+t1
 
TypeError: unsupported operand type(s) for
+: 'int' and 'Time'。
解决方法:
特别方法__radd__,即右加法。当时间对象出现在+号的右侧时,会调用这个方法,它的定义如下:
def __radd__(self, other):
       
returnself.__add__(other)
完整的例子如下:
def int_to_time(seconds):
   
time = Time()
   
minutes,time.second = divmod(seconds, 60)
   
time.hour,time.minute = divmod(minutes, 60)
   
return time
 
 
class Time(object):
   """Represents the time of day. attributes: hour, minute,second"""
   
def__init__(self, hour=0, minute=0, second=0):
       self.hour=hour
       self.minute=minute
       
self.second=second
   

   
def__str__(self):
       
return'%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)
   

   
deftime_to_int(self):
       
minutes =self.hour * 60 + self.minute
       
seconds =minutes * 60 + self.second
       
returnseconds
           

   
defincrement(self, seconds):
       
seconds +=self.time_to_int()
       
returnint_to_time(seconds)
   

   
def__add__(self,other):
       
ifisinstance(other,Time):
           
returnself.add_time(other)
       
else:
           
returnself.increment(other)
                   
   
defadd_time(self,other):  
       seconds=self.time_to_int()+other.time_to_int()
       
returnint_to_time(seconds)
   

   
def__radd__(self, other):
       
returnself.__add__(other)
 
In [122]: t1=Time(0,0,10)
     ...:

     ...: t2=Time(0,1,0)
 
In [123]: print t1+t2
     ...:

00:01:10
 
In [124]: print t1+60
00:01:10
 
In [125]: print t1+61
00:01:11
 
In [126]: print 10+t1
00:00:20
 
 

7、多态
可以处理多个类型的函数称为多态(polymorphic)。多态可以促进代码复用。最好的多态是,当你发现一个写好的函数竟可以用户从未处理过的类。
 
def histogram(s):
   
d=dict()
   
for c in s:
       
if c not ind:
           
d[c]=1
       
else:
           
d[c] +=1
   
return d
       

 
s="Hello, World"
 
s=["spam", 'egg', 'spam', 'spam', 'bacon','spam']
 
histogram(s)
 
 
 
In [128]: s="Hello, World"
In [129]: histogram(s)
Out[129]: {' ': 1, ',': 1,
'H': 1, 'W': 1, 'd': 1, 'e': 1, 'l': 3, 'o': 2, 'r': 1}
In [130]: s=["spam", 'egg', 'spam',
'spam', 'bacon', 'spam']
In [131]: histogram(s)
Out[131]: {'bacon': 1, 'egg':
1, 'spam': 4}
由于时间对象提供了add方法,他们也可以用sum:
t1=Time(7,43)
t2=Time(7,41)
t3=Time(7,37)
 
total=sum([t1,t2,t3])
print total
 
In [136]: total=sum([t1,t2,t3])
In [137]: print total
23:01:00
 
 
 
 

8、调试
在程序运行的任何时刻,往对象上添加属性都是合法的。但如果你遵守更严格的类型理论,让对象拥有相同类型却有不同的属相值,是非常奇怪的(最开始便是这种非规范使用)。通常来说,在init方法中,初始化对象的全部属性是个好习惯(推荐)。
(1)如果不知道对象是否有某个属性,可以使用内置函数hasattr.
In[143]:
hasattr(t1,'hour')
Out[143]:
True

(2)另一种访问一个对象的属性的方法是通过特别的属性__dict__,它是一个映射,将属性名称(字符串形式)映射要属性值。
In[145]:
t1.__dict__
Out[145]:{'hour':
7, 'minute': 43, 'second': 0}

(3)为了调试方便,将这个函数放置在手边是很有用的。
In[146]:
def print_attributes(obj):
     ...: for attr in obj.__dict__:

     ...: print attr,getattr(obj,attr)

     ...:

     ...:

 

In [147]:print_attributes(t1)

second 0

minute 43

hour 7

内置函数getattr接收一个对象以及一个属性名称(字符串形式)并返回函数的值。
 
9、接口和实现
面向对象的设计目标之一是提高软件的可维护性,即当系统的其它部分改变时,程序还能够正确的运行,并且能够修改程序来适应新的需求。
将接口与实现相分离,可以帮助更容易达到这个目标。
将接口和实现分开,意味着你需要将属性隐藏起来,程序的其它部分的代码(类定义外的),应当使用方法来读写对象的状态,他们不该直接访问属性。这个原则称为信息隐藏(information
hiding)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: