13. 面向对象(多态/封装)

[TOC]

多态

同一种事物的多种形态
增加了程序的灵活性
增加了程序的可扩展性

封装

封装数据:保护隐私
封装方法:隔离复杂度

第一种封装:
什么都不做

第二种封装:
双下划线的隐藏属性
语法糖:_xxx====>类__xxx #这个过程就是变形

特性

@property #xxx = property(xxx)
def xxx():
pass

class Squera:      #定义一个正方形的类
    def __init__(self,lenth):   #定义一个边长参数
        self.lenth = lenth

    @property     #使用特性装饰器,不用调用外部模块,因为可以在内置模块中看到property()函数,这个装饰器的实现效果其实就是area = property(area)
    def area(self):
        return self.lenth*self.lenth

    @property
    def perimeter(self):
        return 4* self.lenth

s = Squera(10)
# print(s.area())    #如果不添加property,打印这个面积需要使用调用函数的方法,但是实际上,为了统一这些参数的调用,并且规范调用方式,所以才使用property
# print(s.perimeter())

print(s.area)
print(s.perimeter)

除了如上注释中描述的优点,我们需要注意,这个area和perimeter看起来像作为一个参数属性在引用,但是实际上他本质上仍然是一个计算函数的结果。
所以在修改了lenth的长度之后,再次调用print(s.area)就会发现结果已经改变了。

被property装饰的属性会优于对象的属性被引用。并且property的相关方法也会关联一些语句,并且优先走有关联语句的部分,例如下面代码的xxx.name = 'xxxxx'就指向了name.setter函数,无论这个赋值是多少,优先运行name.setter的函数内容。
如果说这个name.setter中并没有赋值相关的操作,那么这个动作就按照name.setter来运行。不执行赋值。

class Name:
    def __init__(self,NAME):
        self.__name = NAME

    @property   #将一个隐藏属性定义成一个函数,并且把这个函数的计算结果返回出来
    def name(self):
        print(self.__name)

    @name.setter  #setter接口,用于设置之前property装饰的函数,在函数内部修改被隐藏的值
    def name(self,value):  #定义一个可用值传入
        if type(value)==str:
            self.__name = value   #将隐藏值在函数内部修改,如果在外部直接修改name,因为name是被property装饰的一个函数,所以无法修改,起到了保护原隐藏值的作用。
        else:
            raise TypeError('please enter str type')

    @name.deleter
    def name(self):   #定义删除原隐藏值函数
        del self.__name

peo1 = Name('scott')
#定义对象peo1
print(peo1.name)
#输出对象名,由于__name 被隐藏,所以这里输出的其实是name()的运算结果
peo1.name = 'jerry'
#当出现针对name(其实是函数)的赋值动作,被setter装饰的函数运行;扩展:可以进行添加age隐藏参数,同__name,也给age添加修改方法,但是添加name.setter,看修改的是哪个值。需要注意setter方法前需要注明修改的对象
print(peo1.name)#查看结果
peo1.name = 123     #输入错误类
print(peo1.name)
del peo1.name    #出现删除操作的时候,执行.deleter装饰的方法
print(peo1.name)

str

class people:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return 'name:%s,age:%s'%(self.name,self.age)

p1 = people('scott',23)
print(p1)

>>>name:'scott',age:23

定义在类的内部,必须返回一个字符串类型。
打印有这个类产生的对象时,会触发执行。
其实str(p1)=========>p1.str()

staticmethod解除绑定方法

添加了@staticmethod之后,类中的方法就不再是绑定方法了,也就不存在self自动传值的动作。
在类中,需要定义一个函数,就是给类使用的,而不和对象绑定,就要用到staticmethod。如果需要调用一个类的方法,并且不传入self(也就是不绑定对象),也没有使用staticmethod,那么在实例调用的时候,就会报缺少参数的错。

import time
class Date:
    def __init__(self,year,month,day):# 定义一个基础函数,传入年月日
        self.year = year
        self.month = month
        self.day = day

    def test():            #定义一个test()方法,这个方法不与类绑定,在调用的时候与对象传参无关(不接受对象的传参)这时候其实test会有红线提示,不规范的写法
        print('from test') #返回一个标识结果

    @staticmethod          #静态方法(用于将装饰的函数从类中解除绑定)
    def now():             #定义的函数无需self传值,但仍然可以作为类中的方法被对象调用
        t = time.localtime()    #.localtime()地方法传给t,是一个类,包含着年月日时间参数
        obj = Date(t.tm_year,t.tm_mon,t.tm_mday) #将t的年月日信息传给Date类,生成obj对象
        return obj     #返回,将now()的结果变成obj对象

    @staticmethod
    def tomorrow():
        t = time.localtime(time.time()+86400)
        return Date(t.tm_year,t.tm_mon,t.tm_mday)

class EuroDate(Date):
    def __str__(self):
        return '%s year %s month %s day'%((self.year,self.month,self.day))

d = Date(17,4,20)     #设置对象
d.test()              #报错,对象不能调用test方法
#TypeError: test() takes 0 positional arguments but 1 was given
Date.test()           #类可以调用方法,但是没有意义,此时的test和类外部的函数一样。

静态方法的引用:

t = d.now()
print(t.year,t.month,t.day)
l = time.localtime()
print(type(l))

结果

2017 4 21
<class 'time.struct_time'>

实例也可以使用,但通常静态方法都是给类用的,实例在使用时丧失了自动传值的机制

在类中,如果没被装饰器装饰过,就是绑定方法

import time
class Date:
    def __init__(self,year,month,day):
        self.year=year
        self.month=month
        self.day=day
    @staticmethod
    def now():
        t=time.localtime()
        return Date(t.tm_year,t.tm_mon,t.tm_mday)

class EuroDate(Date):
    def __str__(self):
        return 'year:%s month:%s day:%s' %(self.year,self.month,self.day)

e=EuroDate.now()
print(e) #我们的意图是想触发EuroDate.__str__,但是结果为
'''
输出结果:
<__main__.Date object at 0x1013f9d68>
'''

classmethod

@classmethod
http://blog.csdn.net/handsomekang/article/details/9615239#

把一个方法绑定给类

一般来说,要使用某个类的方法,需要先实例化一个对象再调用方法。

而使用@staticmethod或@classmethod,就可以不需要实例化,直接类名.方法名()来调用。

这有利于组织代码,把某些应该属于某个类的函数给放到那个类里去,同时有利于命名空间的整洁。

既然@staticmethod和@classmethod都可以直接类名.方法名()来调用,那他们有什么区别呢

从它们的使用上来看,

  • @staticmethod不需要表示自身对象的self和自身类的cls参数,就跟使用函数一样。
  • @classmethod也不需要self参数,但第一个参数需要是表示自身类的cls参数。

如果在@staticmethod中要调用到这个类的一些属性方法,只能直接类名.属性名或类名.方法名。

而@classmethod因为持有cls参数,可以来调用类的属性,类的方法,实例化对象等,避免硬编码。

差别:绑定给对象的,第一个位置不用传参staticmethod
绑定给类的(类.绑定给类的方法()),会把类本身当作第一个参数(原self)传给类

class A(object):
    bar = 1
    def foo(self):
        print 'foo'

    @staticmethod
def static_foo():
    print 'static_foo'
    print A.bar

@classmethod
def class_foo(cls):
    print 'class_foo'
    print cls.bar
    cls().foo()

A.static_foo()
A.class_foo() 

拿到一个类的内存地址后,就可以实例化或者引用类的属性了。

小结:

在类内部定义的函数无非三种用途
一:绑定到对象的方法
    只要是在类内部定义的,并且没有被任何装饰器修饰过的方法,都是绑定到对象的

    class Foo:
        def test(self): #绑定到对象的方法
            pass
        def test1(): #也是绑定到对象的方法,只是对象.test1(),会把对象本身自动传给test1,因test1没有参数所以会抛出异常
            pass

    绑定到对象,指的是:就给对象去用,
    使用方式:对象.对象的绑定方法(),不用为self传值
    特性:调用时会把对象本身当做第一个参数传给对象的绑定方法

二:绑定到类的方法:classmethod
    在类内部定义的,并且被装饰器@classmethod修饰过的方法,都是绑定到类的

#用来计算类被实例化的次数
# def get_no_(cls_obj):
#     return cls_obj.times_inst

class Exm_cls:
   #实例化次数的初始值为0
   times_inst = 0
   #类被实例化一次,就+1
   def __init__(self):
       Exm_cls.times_inst +=1

   #在内部定义这个函数,并且把他绑定到类
   @classmethod
   def get_no_(cls):
       return cls.times_inst


exm1 = Exm_cls()
exm2 = Exm_cls()

print(Exm_cls.get_no_())
# print(get_no_(Exm_cls))    
    绑定到对象,指的是:就给对象去用,
    使用方式:对象.对象的绑定方法()
    特性:调用时会把对象本身当做第一个参数传给对象的绑定方法

三:解除绑定的方法:staticmethod
    既不与类绑定,也不与对象绑定,不与任何事物绑定
    绑定的特性:自动传值(绑定到类的就是自动传类,绑定到对象的就自动传对象)
    解除绑定的特性:不管是类还是对象来调用,都没有自动传值这么一说了

    所以说staticmethod就是相当于一个普通的工具包

class Foo:
    def test1(self):
        pass
    def test2():
        pass

    @classmethod
    def test3(cls):
        pass
    @classmethod
    def test4():
        pass

    @staticmethod
    def test5():
        pass

test1与test2都是绑定到对象方法:调用时就是操作对象本身
    <function Foo.test1 at 0x0000000000D8E488>
    <function Foo.test2 at 0x0000000000D8E510>
test3与test4都是绑定到类的方法:调用时就是操作类本身
    <bound method Foo.test3 of <class '__main__.Foo'>>
    <bound method Foo.test4 of <class '__main__.Foo'>>
test5是不与任何事物绑定的:就是一个工具包,谁来都可以用,没说专门操作谁这么一说
    <function Foo.test5 at 0x0000000000D8E6A8>

反射
getattr
setattr
delattr
hasattr

定制

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,839评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,543评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,116评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,371评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,384评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,111评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,416评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,053评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,558评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,007评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,117评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,756评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,324评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,315评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,539评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,578评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,877评论 2 345

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,869评论 6 13
  • @(python)[笔记] 目录 前言 在python中,一切皆对象面向对象的程序设计的核心就是对象;面向对象的程...
    CaiGuangyin阅读 587评论 0 5
  • 今天看了charlotte,说真的,第一集确实有些讨厌,不过男主的帅气和那个时不时出现的摄影机还是吸引了我,于是继...
    小浔阅读 205评论 0 0
  • 文/红线 第一次拜读丹尼尔·平克的作品,这本书名声在外,对于我这个社会小白、职场小白来说,还是有很多影响力的。因为...
    红线533阅读 1,340评论 0 0
  • 之前培训就听过这句话,不要用放大镜去看下属的缺点,明明是一件小事,却被放大无数倍,导致我们对下属各种不信任。...
    姜杨Ada阅读 212评论 0 0