【封装】

隐藏对象的属性和实现细节,仅对外提供公共访问方式。

【好处】

1. 将变化隔离;

2. 便于使用;

3. 提高复用性;

4. 提高安全性;

【封装原则】

1. 将不需要对外提供的内容都隐藏起来;

2. 把属性都隐藏,提供公共方法对其访问。

私有变量和私有方法

在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)

私有变量

#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A:
__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X=10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print('from A')
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到. #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
__author__ = 'Administrator'
class Person:
def __init__(self,name,age,height,weight):
self.name=name
self.age=age
self.__height=height
self.__weight=weight def bmi(self):
return self.__weight/(self.__height**2)
def getHeight(self):
print(self.__height) def getWight(self):
print(self.__weight) def setWeight(self,newWeight):
self.__weight=newWeight p=Person("ctz",21,1.72,63)
print(p.name)
#print(p.__weight)报错
print(p._Person__weight)#外部调用私有方法
p.getHeight()
p.setWeight(62)
p.getWight()
'''封装数据属性:明确的区分内外, 控制外部对隐藏属性的操作行为'''
# class People:
# def __init__(self, name, age):
# self.__name = name
# self.__age = age
# def tell_info(self):
# print('Name:<%s>,Age:<%s>' % (self.__name, self.__age))
# def set_info(self, name, age):
# if not isinstance(name, str): # isinstance()
# print('名字必须是字符串类型')
# return
# if not isinstance(age, int):
# print('年龄必须是数字 类型')
# return
# self.__name = name
# self.__age = age
# p = People('xander', 23)
# p.tell_info()
# p.set_info('Xander', 23)
# p.tell_info()

这种自动变形的特点:

1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果

2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

'''隐藏'''
# class A:
# __x = 1 # 在定义阶段自动变形成_A__x = 1
#
# def __init__(self, name):
# self.__name = name
# def __foo(self):
# print('run foo')
# def bar(self):
# self.__foo()
# print('run bar')
# a = A('xander')
# print(a.__dict__)
# print(A.__dict__)
# print(a._A__x)
'''变形特点
1.外部无法直接obj._AttrName
2.在类内部是可以直接使用:obj._AttrName(定义的时候已经变形了)
3.在子类无法覆盖父类__开头的属性
'''
# class Foo:
# def __func(self): # _Foo__func() 名字不一样了,无法被覆盖
# print('from foo')
# class Bar(Foo):
# def __func(self): # _Bar__func(0
# print('from bar')
# a = Bar()
# # a.func()
'''总结这种变形,需要注意的问题
1.可以通过例如_A__func()访问(有点多余)
2.类定义阶段就会发生'''
# class A:
# __x = 1
# def __init__(self, name):
# self.__name = name
# a = A('xander')
# a.__y = 2
# print(a.__dict__) # 还是__y
'''3.子类无法覆盖'''
# class A:
# def foo(self):
# print('in A.foo')
# def bar(self):
# print('in A.bar')
# self.foo()
# class B(A):
# def foo(self):
# print('in B.foo')
# b = B()
# b.bar() # class A:
# def __foo(self): # _A__foo
# print('in A.foo')
# def bar(self):
# print('in A.bar')
# self.__foo() # _A__bar
# class B(A):
# def foo(self):
# print('in B.foo')
# b = B()
# b.bar() # class A:
# def foo(self):
# print('in A.foo')
# def bar(self):
# print('in A.bar')
# self.foo()
# class B(A):
# def __foo(self): # _B__foo
# print('in B.foo')
# b = B()
# b.bar()

这种变形需要注意的问题是:

1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

2.变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形

私有方法

3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的

__author__ = 'Administrator'
class Person:
def __init__(self,name,height,weight):
self.name=name
self.height=height
self.weight=weight def dmi(self):
return self.weight/self.__hpow()
def __hpow(self):
return self.height**2 p=Person("ctz",1.73,64)
print(p.dmi()) #p.__hpow baocuo print(p._Person__hpow())

'''封装方法:隔离复杂度'''
# class ATM:
# def __card(self):
# print('插卡')
# def __auth(self):
# print('用户认证')
# def __input(self):
# print('输入取款金额')
# def __print_bill(self):
# print('打印账单')
# def __take_money(self):
# print('取款')
# def withdraw(self):
# self.__card()
# self.__auth()
# self.__input()
# self.__print_bill()
# self.__take_money()
# a=ATM()
# a.withdraw()

封装与扩展性

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。

#类的设计者
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
return self.__width * self.__length #使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()

property属性

什么是特性property

property是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值

圆的面积和周长

__author__ = 'Administrator'
from math import pi
class Circle:
def __init__(self,radius):
self.radius=radius @property
def raea(self):
return self.radius**2*pi
@property
def perometer(self):
return self.radius*2*pi c=Circle(5)
print(c.radius)
class People:
def __init__(self,name,weight,height):
self.name=name
self.weight=weight
self.height=height
@property
def bmi(self):
return self.weight / (self.height**2) p1=People('egon',75,1.85)
print(p1.bmi)


BMI指数

__author__ = 'Administrator'
class Num:
def __init__(self,*args):
if len(args)==1and(type(args[0]) is list or type(args[0]) is tuple ):
self.members=args[0]
else:
self.members=args @property
def sum(self):
return sum(self.members) @property
def avg(self):
return self.sum/len(self.members)
@property
def min(self):
return min(self.members)
@property
def max(self):
return max(self.members) n=Num(1,9,6)
print(n.max)
print(n.avg)
print(n.min)
print(n.sum)
print("*"*50)
n2=Num([1,5,3,4])
print(n2.max)
print(n2.avg)
print(n2.min)
print(n2.sum)

为什么要用property(把方法伪装成数据

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

除此之外,看下

ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开

python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现

class Foo:
def __init__(self,val):
self.__NAME=val #将所有的数据属性都隐藏起来 @property
def name(self):
return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError('%s must be str' %value)
self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter
def name(self):
raise TypeError('Can not delete') f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'

setter

__author__ = 'Administrator'
class Good:
__discount=0.8
def __init__(self,name,price):
self.name=name
self.__price=price @property
def goodMoney(self):
return self.__price*Good.__discount @goodMoney.setter
def changeprice(self,newprice):
self.__price=newprice g=Good("a",10)
print(g.goodMoney)
g.changeprice=20
print(g.goodMoney)

一个静态属性property本质就是实现了get,set,delete三种方法

class Foo:
@property
def AAA(self):
print('get的时候运行我啊') @AAA.setter
def AAA(self,value):
print('set的时候运行我啊') @AAA.deleter
def AAA(self):
print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
class Foo:
def get_AAA(self):
print('get的时候运行我啊') def set_AAA(self,value):
print('set的时候运行我啊') def delete_AAA(self):
print('delete的时候运行我啊')
AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA

怎么用?

class Goods:

    def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 @property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price @price.setter
def price(self, value):
self.original_price = value @price.deleter
def price(self):
del self.original_price obj = Goods()
obj.price # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价 
__author__ = 'Administrator'
from urllib.request import urlopen
class WeBpage:
def __init__(self,url):
self.url=url
self.__content=None
@property
def content(self):
if self.__content:
return self.__content
else:
self.__content=urlopen(self.url).read()
return self.__content mypage=WeBpage("http://www.baidu.com")
print(mypage.content)

staticmethod 和 classmethod

'''在类内定义的函数分为两种
1.绑定方法:绑定给谁,就应该由谁来使用,谁来调用就把谁当调用者当作第一个参数自动传入
绑定到对象方法:在类内定义没有被装饰器修饰的
绑定到类方法:在类内部定义的被装饰器classmethod装饰的方法
2.非绑定方法:没有自动传值这么一说,就是类中普通的函数
不与类和方法绑定'''
# class Foo:
# def __init__(self, name): # 绑定到对象,
# self.name = name
# def tell(self): # 绑定到对象
# print(self.name)
# @classmethod # 绑定到类
# def func(cls):
# print(cls)
# @staticmethod # 普通函数
# def func1(x, y):
# return x + y
# f = Foo('xander')
# print(Foo.tell)
# Foo.tell(f)
# print(Foo.func)
# Foo.func()
# print(Foo.func1(1, 4))
# print(f.func1(1, 4))
'''应用'''
class People:
def __init__(self, name, age, sex):
self.name = name
self.age = age
self.sex = sex
def tell_info(self): # 由功能决定,必定是绑定到对象是方法,将对象作为第一个参数传入
print('Name:%s Age:%s Sex:%s'%(self.name, self.age, self.sex))
p = People('xander', 23, 'boy')
p.tell_info()
#staticmethod
#classmethod
class Student:
f = open('student', encoding='utf-8')
def __init__(self):
pass def func(self):
pass @classmethod #类方法:默认参数cls,可以直接用类名调用,可以与类属性交互
def show_student_info_class(cls):
for line in cls.f:
name, sex = line.strip().split(',')
print(name, sex) @staticmethod #静态方法 : 让类里的方法直接被类调用,就像正常的函数一样
def show_student_info_static():
f = open('student', encoding='utf-8')
for line in f:
name, sex = line.strip().split(',')
print(name, sex)
print(Student.func)
print(Student.show_student_info_class)
print(Student.show_student_info_static)
# 海娇 = Student()
# 海娇.show_student_info() #Student.show_student_info(海娇)
# Student.show_student_info()
# class Teacher:
# pass
#classmethod和staticmethod
#相同:都可以直接被类调用,不需要实例化
#不同:
#类方法必须有一个cls参数表示这个类,可以使用类属性
#静态方法不需要,静态方法不能直接使用 # def show_student_info():
# f = open('student', encoding='utf-8')
# for line in f:
# name, sex = line.strip().split(',')
# print(name, sex) #绑定方法
#非绑定方法 #普通方法 默认有一个self对象传进来,并且只能被对象调用——绑定到对象
#类方法 默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用——绑定到类
#静态方法 没有默认参数,并且可以被类和对象(不推荐)调用——非绑定
 

python 封装,隐藏属性,绑定方法classmethod和staticmethod的更多相关文章

  1. python基础语法17 面向对象4 多态,抽象类,鸭子类型,绑定方法classmethod与staticmethod,isinstance与issubclass,反射

    多态 1.什么是多态? 多态指的是同一种类型的事物,不同的形态. 2.多态的目的: “多态” 也称之为 “多态性”,目的是为了 在不知道对象具体类型的情况下,统一对象调用方法的规范(比如:名字). 多 ...

  2. 绑定方法与非绑定方法 classmethod和staticmethod

    一:绑定方法:特点:绑定给谁就应该是由谁来调用,谁来调用就会将谁当做第一个参数传入 1:绑定给对象的方法:类中定义的函数默认就是绑定给对象的 例:        2:绑定给类的方法:为类中定义的函数加 ...

  3. python3 封装之property 多态 绑定方法classmethod 与 非绑定方法 staticmethod

    property 特性 什么是特性property property 是一种特殊的属性,访问它时会执行一段功能(函数),然后返回值 例如 BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而 ...

  4. python基础之封装与绑定方法

    封装 1.什么是封装: 封:属性对外隐藏,但对内开放 装:申请一个名称空间,往里装入一系列名字/属性 2.为什么要封装: 封装数据属性:不让外部使用者直接使用数据,需要类内部开辟一个接口,让外部通过接 ...

  5. python 封装、绑定

    目录 python 封装.绑定 1.数据.方法的封装 2.隐藏属性 3.开放接口 4.绑定方法 1.对象的绑定 2.类的绑定(classmethod) 3.非绑定方法(staticmethod) 4. ...

  6. day 23 二十三、对象方法,类方法,封装,绑定方法

    一.对象的特有名称空间 __init__方法会在实例化对象时被调用 1.会为实例化的对象形成空的名称空间 2.就是一个方法,可以被传参,在类名(实参)这种方式下调用并传参 __init__(self ...

  7. python 类的绑定方法和非绑定方法

    一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. class People: def __ ...

  8. 全面解析python类的绑定方法与非绑定方法

    类中的方法有两类: 绑定方法 非绑定方法 一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. ...

  9. Python—面向对象04 绑定方法

    坚持把梳理的知识都给记下来....... 嗯哼哼 1.绑定方法与非绑定方法 在类内部定义的函数,分为两大类: 绑定到类的方法:用classmethod装饰器装饰的方法. 为类量身定制 类.boud_m ...

随机推荐

  1. NodeJS下的阿里云企业邮箱邮件发送问题

    还没有到11点,再顺带发一个上次碰到NodeJS的邮箱插件nodeMailer不支持阿里云邮件问题. 网上很多资料都默认使用QQ之类的邮箱,因为nodeMailer默认添加了QQ之类的SMTP地址,但 ...

  2. ThinkPhp数据缓存技术

    1.缓存初始化 在 ThinkPHP 中,有一个专门处理缓存的类:Cache.class.php(在Thinkphp/Library/Think/cache.class.php,其他的各种缓存类也在这 ...

  3. .NET基础 (01).NET基础概念

    .NET基础概念 1 什么是CTS.CLS和CLR2 开发和运行.NET程序需要的最基本环节是什么3 .NET是否支持多编程语言开发4 CLR技术和COM技术的比较5 什么是程序集和应用程序域 1 什 ...

  4. sql五大类中的 DTL 数据事务语言

    DTL,数据事务语言 事务的定义:就是指一组相关的SQL操作,我们所有的操作都是事务中的. 注意:在数据库中,执行业务的基本单位是[事务],不是以某一条SQL.    数据库在默认情况下,事务是都打开 ...

  5. CSS 实现等高布局以及多行文本垂直居中

    将display属性设置为table-cell,具有table的特点. 1.同行等高. 2.宽度自动调节. 相当于表格是td, <style type="text/css"& ...

  6. CodeForces 327E Axis Walking(状压DP+卡常技巧)

    Iahub wants to meet his girlfriend Iahubina. They both live in Ox axis (the horizontal axis). Iahub ...

  7. 基于Qt5 跨平台应用开发

    1.Qt简介 2.Qt 编程关键技术 2.1 信号与槽 2.2 Qt事件处理 3.Qt开发与实例分析 3.1 开发环境 3.2 系统实现基本框架 3.3 数据库管理 3.5 对Excel进行操作 4. ...

  8. svn(subversion)代码管理

    想必大家现在都比较喜欢使用svn(subversion)完成代码管理了,因为它的开源,轻巧,易用.但是这样一个宝贝如果不知道其正确的用法,也会让我们百思不得其解,甚至耽误项目进度,浪费程序员的心血和结 ...

  9. linux mysql 权限

    原文地址:http://www.cnblogs.com/eczhou/archive/2012/07/12/2588187.html Linux下mysql新建账号及权限设置 1.权限赋予 说明:my ...

  10. Linux基础--安装搭建tomcat+java+mysql

    一.安装jdk 1.可选安装yum -y install lrzsz方便传文件.(yum -y意思是所有的都选yes) yum update -y  更新yum镜像 yum list lrzsz* 列 ...