就是把数据或者方法封装起来python
封装数据的主要缘由是:保护隐私编程
封装方法的主要缘由是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,好比你没必要知道你本身的尿是怎么流出来的,你直接掏出本身的接口就能用尿这个功能)编程语言
在编程语言里,对外提供的接口(接口可理解为了一个入口),就是函数,称为接口函数,这与接口的概念还不同,接口表明一组接口函数的集合体。函数
第一个层面的封装(什么都不用作):建立类和对象会分别建立两者的名称空间,咱们只能用类名.或者obj.的方式去访问里面的名字,这自己就是一种封装code
注意:对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口对象
第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部没法访问,或者留下少许接口(函数)供外部访问。继承
在python中用双下划线的方式实现隐藏属性(设置成私有的)接口
类中全部双下划线开头的名称如__x都会自动变造成:_类名__x的形式:md5
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的形式访问到.
这种自动变形的特色:utf-8
注意:对于这一层面的封装(隐藏),咱们须要在类中定义一个函数(接口函数)在它内部访问被隐藏的属性,而后外部就可使用了
这种变形须要注意的问题是:
a.__Y = 1 print(a.__dict__) ### {'_A__X': 10, '__Y': 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属性内部进行一系列的逻辑计算,最终将计算结果返回。
# ############### 定义 ############### 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. 调用时,无需括号
#coding=utf-8 # ############### 定义 ############### class Goods: """python3中默认继承object类 以python二、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方法中有个四个参数
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
简而言之,非绑定方法就是将普通方法放到了类的内部。
若是函数体代码须要用外部传入的类,则应该将该函数定义成绑定给类的方法
若是函数体代码须要用外部传入的对象,则应该将该函数定义成绑定给对象的方法
若是函数体代码既不须要外部传入的类也不须要外部传入的对象,则应该将该函数定义成非绑定方法/普通函数