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

多态
封装
特性
str
staticmethod解除绑定方法
classmethod
小结:

多态

同一种事物的多种形态

增加了程序的灵活性

增加了程序的可扩展性

封装

封装数据:保护隐私

封装方法:隔离复杂度

第一种封装:

什么都不做

第二种封装:

双下划线的隐藏属性

语法糖:__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

定制

时间: 2024-11-10 00:18:00

13.面向对象(多态/(性)/封装)的相关文章

(1) 深入理解Java面向对象三大特性 封装 继承 多态

转眼已经工作快6年了,最开始做了2年J2EE:然后整了2年的数据仓库,主要是Cognos的报表开发:现在从事4G LTE核心网的开发,用的语言任然是Java,但写代码的机会不多,基本都是看代码找BUG,偶尔做点new feature也是在比较成熟的框架上复制.粘贴.修改,大部分时间还是在理解业务,钱多.事少.离家近,当时来这家公司图的是后面2点,2年过去了,英文水平有所提升,对敏捷开放也有一定的了解,但技术方面明显退步了或者说没有进步吧,本来以前也不怎么好,因为工作上用不到,自己也没怎么学习,所

Mysql数据库大量删除操作及谈面向对象中的封装继承和多态原理(图)

Mysql数据库大量删除操作及谈面向对象中的封装继承和多态原理(图)最近进行数据库操作,遇到一个问题,就是大量删除一个数据表中的数据后,由于设定了id是自增的,导致再插入时,默认生成的id会很大,这个时候想要再次插入新的数据,应该怎么办呢?1.明确目前最后一个id的大小select id from tags order by id DESC limit 0,1; 假设返回的是9,则设置数据表从10开始自增 2.修改这个数据表从10开始自增alter table tags auto_increme

类与对象 面向对象和面向过程对比 面向对象三大特征:封装 继承 多态

 初识面向对象 面向过程: 一切以事务的发展流程为中心. 面向对象: 一切以对象为中心. 一切皆为对象. 具体的某一个事务就是对象 打比方: 大象进冰箱 步骤: 第一步, 开门, 第二步, 装大象, 第三步, 关门 面向对象:大象, 你进冰箱. 此时主语是大象. 我操纵的是大象. 此时的大象就是对象 1. 面向过程: 一切以事物的流程为核心. 核心是"过程"二字, 过程是指解决问题的步骤, 即, 先?干什么, 后干什么. 基于该思想编写程序就好比在编写一套流水线. 是一种机械 式的编程

面向对象特性之封装性(set方法、get方法)

初学者:可理解为,封装就是对成员变量(属性)的封装,把属性隐藏起来,对外提供一个方法,让外界通过一个方法设置属性的值.即,封装性就是隐藏实现细节,将属性私有化,提供公有方法访问私有属性. 进一层:方法也是封装.把一堆代码封装到一个方法里面去,隐藏实现细节. 再进一层:类也是一个封装.把类里面所有的方法都隐藏起来,只对你暴露一些接口. 再再进一层:一个包一个框架也是一个封装.例如,系统给我们提供了Foundation框架,我们只需知道有哪些接口,哪些方法,直接调用就可以了. 封装的目的:同set方

[.net 面向对象编程基础] (11) 面向对象三大特性——封装

[.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承.多态. 1.封装概念 封装:每个对象都包含有它能进行操作的所有信息,这个特性称为封装.这样的方法包含在类中,通过类的实例来实现. 2.封装的优点 A.良好的封装能够减少耦合(比如实现界面和逻辑分离) B.可以让类对外接口不变,内部可以实现自由的修改 C.类具有清晰的对外接口,使用者只需调用,无需关心

C#面向对象-多态

面向对象的三大特性(封装,继承,多态)大多少人都应该知道.前两个的话比较容易理解.本文主要说一下面向对象中的多态. 什么是多态?不同的对象对同一操作,产生不同的执行结果.这就是多态.那么多态又包含了:重载,重写,虚方法,抽象方法. 1,重载什么叫重载?在同一个作用域的两个或多个方法函数名相同,参数列表不同的方法叫做重载.重载有三个特点:1.1:方法名必须相同.1.2:参数列表必须不同.1.3:返回值类型可以不相同. 列如: 1 public void Animal() 2 { 3 Console

09.面向对象多态的概述及其代码体现

09.01_面向对象(多态的概述及其代码体现) A:多态(polymorphic [,p?l?'m??f?k])概述 事物存在的多种形态 B:多态前提 a:要有继承关系. b:要有方法重写. c:要有父类引用指向子类对象. C:案例演示 代码体现多态 案例: class Demo1_Polymorphic { public static void main(String[] args) { Cat c = new Cat();//猫是一只猫 c.eat(); Animal a = new Cat

面向对象多态之接口

申明下:我也是新手,以下如有不对或不合适的地方望指出,一起交流O(∩_∩)O哈! 好了,转入正题 1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 6 namespace Interface 7 { 8 class InterfaceTest 9 { 10 static void Main(string[] args) 11 { 12 #region 测试

python Selenium2Library element操作的健壮性封装、普通操作不受影响

"""     对Selenium2Library element操作的健壮性封装.普通操作不受影响.     每个element操作方法生成一个操作对象    ''' 2类对象:         father类型: fatherName=None eleMethodName=webObj.browserName,            一般在webObj创建时配套创建, _eleMethod_objDc中记录,形如{fatherName:{}}        非father

面向对象的JavaScript --- 封装

面向对象的JavaScript --- 封装 封装 封装的目的是将信息隐藏.一般而言,我们讨论的封装是封装数据和封装实现.真正的封装为更广义的封装,不仅包括封装数据和封装实现,还包括封装类型和封装变化. 封装数据 封装实现 封装类型 封装变化 封装数据 在许多语言的对象系统中,封装数据是由语法解析来实现的,这些语言也许提供了 private.public.protected 等关键字来提供不同的访问权限.但JavaScript并没有提供对这些关键字的支持,我们只能依赖变量的作用域来实现封装特性,