类的封装

就是把数据或者方法封装起来

为什么要封装

封装数据的主要原因是:保护隐私

封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,比如你不必知道你自己的尿是怎么流出来的,你直接掏出自己的接口就能用尿这个功能)

在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体。

两个层面的封装

第一个层面

第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装

注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

第二个层面的封装

第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。

在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的形式访问到.

这种自动变形的特点:

  1. 类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
  2. 这种变形其实正是针对内部的变形,在外部是无法通过__x这个名字访问到的。
  3. 在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

注意:对于这一层面的封装(隐藏),我们需要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,然后外部就可以使用了

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

  1. 这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
  2. 变形的过程只在类的定义时发生一次,在定义后的赋值操作,不会变形
a.__Y = 1
print(a.__dict__)
###
{'_A__X': 10, '__Y': 1}
  1. 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
# 把fa定义成私有的,即__fa
class A:
def __fa(self): # 在定义时就变形为_A__fa
print('from A') def test(self):
self.__fa() # 只会与自己所在的类为准,即调用_A__fa class B(A):
def __fa(self):
print('from B') b = B()
b.test()
##########
from A

私有模块

python并不会真的阻止你访问私有的属性,模块也遵循这种约定,如果模块中的变量名_private_module以单下划线开头,那么from

module import *时不能被导入该变量,但是你from module import

_private_module依然是可以导入该变量的

类的property特性

什么是property特性

property装饰器用于将被装饰的方法伪装成一个数据属性,在使用时可以不加括号而直接使用。

property属性内部进行一系列的逻辑计算,最终将计算结果返回。

# ############### 定义 ###############
class Foo:
def func(self):
pass # 定义property属性
@property
def prop(self):
pass # ############### 调用 ###############
foo_obj = Foo()
foo_obj.func() # 调用实例方法
foo_obj.prop # 调用property属性`

property属性的定义和调用要注意一下几点:

1. 定义时,在实例方法的基础上添加 @property 装饰器;并且仅有一个self参数

2. 调用时,无需括号

新式类具有三种@property装饰器

#coding=utf-8
# ############### 定义 ###############
class Goods:
"""python3中默认继承object类
以python2、3执行此程序的结果不同,因为只有在python3中才有@xxx.setter @xxx.deleter
""" @property
def price(self):
print('@property') @price.setter
def price(self, value):
print('@price.setter') @price.deleter
def price(self):
print('@price.deleter') # ############### 调用 ###############
obj = Goods()
obj.price # 自动执行 @property 修饰的 price 方法,并获取方法的返回值
obj.price = 123 # 自动执行 @price.setter 修饰的 price 方法,并将 123 赋值给方法的参数
del obj.price # 自动执行 @price.deleter 修饰的 price 方法
@property
@price.setter
@price.deleter

新式类中的属性有三种访问方式,并分别对应了三个被 @property、@方法名.setter、@方法名.deleter 修饰的方法。必须先有@property

由于新式类中具有三种访问方式,我们可以根据它们几个属性的访问特点,分别将三个方法定义为对同一个属性:获取、修改、删除

class Goods(object):
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 # 修改商品原价
del obj.price # 删除商品原价

类属性方法

创建值为property对象的类属性

class Foo:
def get_bar(self):
return 'laowang' BAR = property(get_bar) obj = Foo()
reuslt = obj.BAR # 自动调用get_bar方法,并获取方法的返回值
print(reuslt) #laowang

property方法中有个四个参数

  1. 第一个参数是方法名,调用 对象.属性 时自动触发执行方法
  2. 第二个参数是方法名,调用 对象.属性 = XXX 时自动触发执行方法
  3. 第三个参数是方法名,调用 del 对象.属性 时自动触发执行方法
  4. 第四个参数是字符串,调用 对象.属性.doc ,此参数是该属性的描述信息
class Goods(object):
def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 def get_price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price def set_price(self, value):
self.original_price = value def del_price(self):
del self.original_price PRICE = property(get_price, set_price, del_price, '价格属性描述...') obj = Goods()
obj.PRICE # 获取商品价格
obj.PRICE = 200 # 修改商品原价
del obj.PRICE # 删除商品原价

通过使用property属性,能够简化调用者在获取数据的流程

类与对象的绑定方法与非绑定方法

绑定方法

对象的绑定方法

在类中没有被任何装饰器修饰的方法就是 绑定到对象的方法,这类方法专门为对象定制。

这类方法不在对象的名称空间中,而在类的名称空间中。

通过对象调用绑定到对象的方法,会有一个自动传值的过程,即自动将当前对象传递给方法的第一个参数(self,一般都叫self,也可以写成别的名称);若是使用类调用,则第一个参数需要手动传值。

p = Person('Kitty', 18)
p.speak() # 通过对象调用

类的绑定方法

类中使用 @classmethod 修饰的方法就是绑定到类的方法。这类方法专门为类定制。通过类名调用绑定到类的方法时,会将类本身当做参数传给类方法的第一个参数。

class Operate_database():
host = '192.168.0.5'
port = '3306'
user = 'abc'
password = '123456' @classmethod
def connect(cls): # 约定俗成第一个参数名为cls,也可以定义为其他参数名
print(cls)
print(cls.host + ':' + cls.port + ' ' + cls.user + '/' + cls.password) Operate_database.connect() #############
<class '__main__.Operate_database'>
192.168.0.5:3306 abc/123456

通过对象也可以调用,只是默认传递的第一个参数还是这个对象对应的类。

Operate_database().connect()  # 输出结果一致

非绑定方法

在类内部使用 @staticmethod 修饰的方法即为非绑定方法,这类方法和普通定义的函数没有区别,不与类或对象绑定,谁都可以调用,且没有自动传值的效果。

import hashlib

class Operate_database():
def __init__(self, host, port, user, password):
self.host = host
self.port = port
self.user = user
self.password = password @staticmethod
def get_passwrod(salt, password):
m = hashlib.md5(salt.encode('utf-8')) # 加盐处理
m.update(password.encode('utf-8'))
return m.hexdigest() hash_password = Operate_database.get_passwrod('lala', '123456') # 通过类来调用
print(hash_password)
########
f7a1cc409ed6f51058c2b4a94a7e1956
p = Operate_database('192.168.0.5', '3306', 'abc', '123456')
hash_password = p.get_passwrod(p.user, p.password) # 也可以通过对象调用
print(hash_password)
###########
0659c7992e268962384eb17fafe88364

简而言之,非绑定方法就是将普通方法放到了类的内部。

小结

绑定方法

如果函数体代码需要用外部传入的类,则应该将该函数定义成绑定给类的方法

如果函数体代码需要用外部传入的对象,则应该将该函数定义成绑定给对象的方法

非绑定方法

如果函数体代码既不需要外部传入的类也不需要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数

类的封装,property特性,类与对象的绑定方法和非绑定方法,的更多相关文章

  1. python 类的封装/property类型/和对象的绑定与非绑定方法

    目录 类的封装 类的property特性 类与对象的绑定方法与非绑定方法 类的封装 封装: 就是打包,封起来,装起来,把你丢进袋子里,然后用绳子把袋子绑紧,你还能拿到袋子里的那个人吗? 1.隐藏属性和 ...

  2. Python面向对象之封装、property特性、绑定方法与非绑定方法

    一.封装 ''' 1.什么封装 封:属性对外是隐藏的,但对内是开放的(对内是开放的是因为在类定义阶段这种隐藏已经发生改变) 装:申请一个名称空间,往里装入一系列名字/属性 2.为什么要封装 封装数据属 ...

  3. day22-类的封装、property特性以及绑定方法与非绑定方法

    目录 类的封装 两个层面的封装 第一个层面 第二个层面 封装的好处 私有模块 类的propertry特性 setter 和 deleter 类与对象的绑定方法与非绑定方法 类的封装 将类的属性或方法隐 ...

  4. 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法

    1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...

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

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

  6. python 旧类中使用property特性的方法

    在python中,我们可以拦截对象的所有特性访问.通过这种拦截的思路,我们可以在旧式类中实现property方法. __getattribute__(self, name) #当特性name被访问时自 ...

  7. Python类总结-封装(Property, setter, deleter)

    Property #property #内置装饰器函数,只在面向对象中使用 from math import pi class Circle: def __init__(self,r ): self. ...

  8. 类锁和对象锁,synchronized修饰static方法与非static方法的区别

    当synchronized修饰一个static方法时,多线程下,获取的是类锁(即Class本身,注意:不是实例), 作用范围是整个静态方法,作用的对象是这个类的所有对象. 当synchronized修 ...

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

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

随机推荐

  1. bzoj4811 [Ynoi2017]由乃的OJ 树链剖分+位运算

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4811 因为位运算的结果有可合并性,所以可以树链剖分,线段树维护: 细节很多,特别要注意从左往 ...

  2. coderfoces446c (斐波那契数列)

    题目描述: 区间增值,但是每一项增加的值为Fi - l + 1,F[i]为斐波那契数列,求区间和? 考虑线段树,刚开始想用斐波那契数列的前n项和,可是推不出来,考虑到每个区间的增值序列都是一段斐波那契 ...

  3. 美化console.log的文本(转载)

    原文地址:http://www.css88.com/archives/5260 JavaScript Console 那些少人所知的特性 console.log("%c css88.com& ...

  4. 洛谷 P1081 开车旅行【双向链表+倍增】

    倍增数组的20和N写反了反复WAWAWA-- 注意到a和b在每个点上出发都会到一个指定的点,所以这样构成了两棵以n点为根的树 假设我们建出了这两棵树,对于第一问就可以枚举起点然后倍增的找出ab路径长度 ...

  5. CF670C Cinema 【离散化+map】

    题意翻译 莫斯科在举办一场重要的有 nn 个不同国家的珂学家参与的国际会议,每个珂学家都只会一种语言.为了方便起见,我们规定一种语言用 11 到 10^9109 的数来描述. 在会议之后的晚上,珂学家 ...

  6. [转]Boosting

    1 Boosting算法的起源 Boosting方法是一种用来提高弱分类算法准确度的方法,这种方法通过构造一个预测函数系列,然后以一定的方式将他们组合成一个预测函数.Boosting是一种提高任意给定 ...

  7. 51nod 1100 斜率最大

    可以用三个点简单证明斜率最大的直线两个点! #include <bits/stdc++.h> #define MAXN 10010 using namespace std; struct ...

  8. magento controller直接渲染Block 以及传参

    class Jago_Deal_IndexController extends Mage_Core_Controller_Front_Action { public function ajaxActi ...

  9. Java多线程学习---------超详细总结(java 多线程 同步 数据传递 )

    目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么 ...

  10. D. Mahmoud and a Dictionary 种类并查集

    http://codeforces.com/contest/766/problem/D 所谓种类并查集,题型一般如下:给定一些基本信息给你,然后又给出一些信息,要求你判断是真是假.例如给出a和b支持不 ...