类和方法学习笔记(python)

类和方法

 

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) 如果提供两个实参,它会覆盖hourminute;

(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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值