封装,property装饰器,绑定方法

1、什么封装
封:属性对外是隐藏的,但对内是开放的
装:申请一个名称空间,往里装入一系列名字/属性

2、为什么要封装
封装数据属性的目的
首先定义属性的目的就是为了给类外部的使用使用的,
隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
然后让类外部的使用通过接口来间接地操作隐藏的属性。
精髓在于:我们可以在接口之上附加任意逻辑,从而严格控制使用者对属性的操作

封装函数属性
首先定义属性的目的就是为了给类外部的使用使用的,
隐藏函数属性是为了不让外不直接使用,需要类内部开辟一个接口
然后在接口内去调用隐藏的功能
精髓在于:隔离了复杂度

3、如何封装

# 如何隐藏:在属性前加上__开头
#1、 这种隐藏仅仅只是一种语法上的变形操作
#2、 这种语法上的变形只在类定义阶段发生一次,因为类体代码仅仅只在类定义阶段检测一次
#3、 这种隐藏是对外不对内的,即在类的内部可以直接访问,而在类的外则无法直接访问,原因是
# 在类定义阶段,类体内代码统一发生了一次变形
#4、 如果不想让子类的方法覆盖父类的,可以将该方法名前加一个__开头

# class People:
#     __country="China"
#     def __init__(self,name,age,sex):
#         self.__name=name
#         self.age=age
#         self.sex=sex
#
#     def eat(self):
#         print("eat....")
#         print(People.__country)#凡是在内部进行查看都时没问题,
#         print(self.__name)     #因为在定义的时候都一起发生改变
#
#
# obj=People("yf",18,"mael")
# obj.eat()              #这是访问类内部的函数名,所以内部访问可以看见
# print(People.__country)#当类的数据变量名被隐藏的时候直接去访问时看不见
# print(People.eat(123)) #当类去访问其内部的函数间接访问该内容的时候可以看得见
# print(obj.__name)
# People.__x=11          #因为时在定义阶段进行封装发生一次,所以后面就算添加进去也只是其添加时形态__x
# print(People.__dict__) #通过查看类的内部情况可以看见,所有被隐藏的属性,都
# 是在前面变化成 _类名 的形式
# print(People._People__country)#按照其封装方式 _类名__属性 的形式时可以查到
# peo1=People("egon",18,"male")
# print(peo1.__dict__)
# peo1.__111
# print(peo1.__dict__)
# class Foo:
#     def __f1(self):
#         print("Foo.f1")
#
#     def f2(self):
#         print("Foo.f2")
#         self.__f1()
#
# class Bar(Foo):
#     def __f1(self):
#         print("Bar.f1")
#
# obj=Bar()
# obj.f2()
#在没隐藏的状态下显示Foo.f2   Bar.f1
#如果隐藏子类
#显示 Foo.f2   Foo.f1
简单示范讲解
# class People:
#     def __init__(self,name,age):
#         self.__name=name
#         self.__age=age
#
#     def tell_info(self):
#         print("%s:%s" %(self.__name,self.__age))
#         # self.set_info(self.__name,self.__age)
#     def set_info(self,name,age):
#         if type(name) is not str:
#             raise TypeError("用户名必须为str类型")#主动报错方式,是自己设置的内容,
#             # 代替了print与return
#         if type(age) is not int:
#             raise TypeError("年龄必须为int类型")
#
#         self.__name=name#当逻辑判断都通过的时候就可以更改属性
#         self.__age=age


# peo1=People("egon",18)
# peo1.tell_info()
# #首先定义属性的目的就是为了给类外部的使用使用的
# # 隐藏之后是为了不让外部使用直接使用,需要类内部开辟一个接口
# #然后让类外部的使用通过接口来间接的操作是隐藏的属性
# #精髓在于:我们可以再接口上附加任意逻辑,从而严格控制使用者对属性的操作
# peo1.set_info("egon",19)
# peo1.tell_info()
# peo1.__name=123#经过隐藏后,要像直接修改属性的姓名密码,都是不会成功,
# 除非是按照改变方式作死的去改
# peo1.age=22
# peo1.tell_info()
封装数据属性的用途
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()
封装函数的用途

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

# 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)
#
# peo1=People("yf",68,1.75)
# print(peo1.bmi)
# peo1.height=1.85#通过更改身高,对象使用bmi属性可以达到改变的效果,表示property装饰器有效
# print(peo1.bmi)
property装饰器
# class People:
#     def __init__(self,name):
#         self.name=name
#
#     @property
#     def name(self):
#         return "<名字是:%s>" %self.__name
#
#     @name.setter
#     def name(self,name):
#         if type(name) is not str:
#             raise TypeError("名字必须是str类型")
#         self.__name=name
#
#     @name.deleter
#     def name(self):
#         del self.__name
#
# peo1=People("egon")
# print(peo1.name)
#
# peo1.name="Egon"#会自动判断进行的是修改或者查看,删除
# print(peo1.name)
#
# del peo1.name
# print(peo1.name)#如果没有property那么这些操作都是先按照最后一个对象属性的这个名字操作(这样就乱了)


1、绑定方法
特性:绑定给谁就应该由谁来调用,谁来调用就会讲谁当作第一个参数自动传入
《精髓在于自动传值》
绑定方法分为两类
1.1绑定给对象方法
在类内部定义的函数(没有被任何装饰器修改的),默认就是绑定给对象用的
1.2绑定给类的方法
在类内部定义的函数如果被装饰器@classmethod装饰,
那么则是绑定给累的,应该由类来调用,类来调用就自动将类当作第一个参数自动传入
2、非绑定方法
类中定义的函数如果被装饰器@staticmethodz装饰,那么该函数就变成非绑定方法
既不与类绑定,又不与对象绑定,意味着类与对象都可以来调用
但是无论谁来调用,都没有任何自动传值的效果,就是一个普通函数

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

# class Foo:
#     @classmethod#绑定给类
#     def f1(cls):#绑定给类的函数,内部会自动传入cls代表是跟类绑定
#         print(cls)
#     def f2(self):
#         print(self)
# obj=Foo()
# print(obj.f2)
# print(Foo.f1)
# #1、f1绑定给类的
# #了解:绑定给类的应该由类来调用,但对象其实也可以使用,只不过自动传入的任然是类
# print(Foo.f1)#<bound method Foo.f1 of <class '__main__.Foo'>>
# print(obj.f1)#<bound method Foo.f1 of <class '__main__.Foo'>>#对象调用类的绑定可以不用传值,但是类还是会自动传入,# 显示绑定给类的
# Foo.f1()#<class '__main__.Foo'>
# obj.f1()#<class '__main__.Foo'>
#2、f2是绑定给对象的
# obj.f2()
# Foo.f2(obj)
# import settings
# import uuid
# class Mysql:
#     def __init__(self,ip,port):
#         self.uid=self.create_uid()
#         self.ip=ip
#         self.port=port
# 
#     def tell_info(self):
#         print("%s:%s" %(self.ip,self.port))
#         #类获取到外部导入的IP与PORT后直接通过对象进行查看
#     @classmethod
#     def from_conf(cls):
#         return cls(settings.IP,settings.PORT)
#         #因为是从外部导入内容,所以需要通过类导入进行获取
#     @staticmethod#加上这个装饰器后变成普通函数
#     def func():#这里面有几个形参,对象或者类调用就必须要有几个实参
#         print("不与任何人绑定")
#     @staticmethod
#     def create_uid():#自动生成id,uuid生成的id每次都不一样
#         return uuid.uuid1()
# 
# # 默认的实例化方式:类名(..)
# obj=Mysql('10.10.0.9',3307)
# # 一种新的实例化方式:从配置文件中读取配置完成实例化
# # ojb=Mysql.from_conf()#类的传值基本都用于配置文件的读取
# # ojb.tell_info()
# 
# #普通函数都可以直接使用,只是有几个参数就传几个,没有自动传入
# # obj.func()
# # Mysql.func()
# # print(obj.func)
# # print(Mysql.func)
# 
# print(obj.uid)#是调用对象内的id属性看id
绑定的具体示范
原文地址:https://www.cnblogs.com/yf18767106368/p/9239546.html