day 23 二十三、对象方法,类方法,封装,绑定方法
一、对象的特有名称空间
__init__方法会在实例化对象时被调用
1、会为实例化的对象形成空的名称空间
2、就是一个方法,可以被传参,在类名(实参)这种方式下调用并传参 __init__(self 形参)
3、第一个self就是要产生的当前对象 重点:在方法内部,形参拿到了实参值,利用self.属性名 = 形参 = 实参值, 对对象的名称空间添加属性
class Student: # def __init__(self, name, sex): # print('2>>>', self) # self.name = name # self.sex = sex # def fn(): # print('fn run ') def set_stu(stu, name, sex): stu.name = name stu.sex = sex # print(Student.__dict__) # Student.fn() # fn run stu1 = Student() print(stu1.__dict__) # {} Student.set_stu(stu1, 'Bob', 'male') print(stu1.__dict__) # {'name': 'Bob', 'sex': 'male'} print(stu1.name) # Bob print(stu1.sex) # male stu2 = Student() Student.set_stu(stu2, 'Tom', 'female') print(stu2.__dict__) # {'name': 'Tom', 'sex': 'female'} print(stu2.name, stu2.sex) # Tom female
二、对象方法:
对象调用类的方法(类中方法的第一个默认参数:对象方法),建议使用对象调用
class Student: def __init__(self, name): self.name = name def study(self): print(self.name + 'study') stu = Student('Bob') stu.study() # Bobstudy stu2 = Student('Tom') stu2.study() # Tomstudy # 类中方法的第一个默认参数:对象方法 # 总结:对象调用类的方法 class Student: pass stu = Student() def fn(a, b): print('fn run') stu.fn = fn stu.fn(, ) # fn run class A: def test(self): print(self) pass a = A() a.test() # <__main__.A object at 0x0000000002767550> A.test(a) # <__main__.A object at 0x0000000002767550> A.__dict__['test'](a) # <__main__.A object at 0x0000000002767550>
三、类方法:
可以被类与对象调用的方法,第一个参数一定是类,类方法不建议拿对象来调用
class Tool: # 类自己的方法 def add(cls, n1, n2): cls.fn() return n1 + n2 def fn(): pass # a如果被外界对象tool调用,那么内部调用b,b其实也是被外界对象tool调用的 def a(self): self.b() def b(self): pass res = Tool.add(Tool, , ) # 类调用,外界传入两个参数,内部接收到两个 print(res) # # 问题:类的名字,对象都可以使用,但是出现了类与对象使用时,参数个数不一致 # tool = Tool() # print(tool.add(, )) # 对象调用,外界传入两个参数,内部接收到三个,第一个是对象本身 class Tool: def add(cls, n1, n2): return n1 + n2 print(Tool.add(Tool, , )) # # 类调用 tool = Tool() print(tool.add(, )) # # 对象调用 class Tool: # 类方法:可以被类与对象调用的方法,第一个参数一定是类 # 类方法不建议拿对象来调用 @classmethod def add(cls, n1, n2): print(id(cls)) # cls.test() return n1 + n2 @classmethod def test(cls): pass print(Tool.add(, )) # tool = Tool() print(tool.add(, )) # print(id(Tool), id(tool)) # # 对象调用所属类的类方法,默认第一个参数传入的是 对象.__class__ 就是所属类 print(tool.__class__) # <class '__main__.Tool'>
四、属性与方法的总结
class OldBoy: # 属于类的属性 name = '老男孩' # 属于对象的属性 def __init__(self, name): self.name = name # 属于类的方法 # 需求:获取机构的名字 @classmethod def get_class_name(cls): return cls.name # 属于对象的方法 # 需求:获取校区的名字 @classmethod def get_school_nmae(cls): return cls.name # 创建校区 shanghai = OldBoy('上海校区') shenzhen = OldBoy('深圳校区') # 类方法的使用:建议使用类调用 print(OldBoy.get_class_name()) # 老男孩 # 对象方法的使用:建议使用对象调用 print(shanghai.get_school_nmae()) # 老男孩 print(shenzhen.get_school_nmae()) # 老男孩
五、封装:(封装的终极奥义:明确地区分内外,对外是隐藏的,对内是开放的)
1、定义:
对外隐藏类中一些属性与方法的实现细节,封装(从字面意思理解)就是隐藏,隐藏指的是在类内部将一个属性藏起来 让类外部的使用者无法直接用到
封装(从字面意思理解)就是隐藏,隐藏指的是在类内部将一个属性藏起来 让类外部的使用者无法直接用到。在py中就是用__开头将一个属性藏起来. 补充说明:封装绝对不是单纯意义的隐藏 需知定义属性的目的就是为了让使用者去用,使用者要想使用类内部隐藏的属性 需要类的设计者在类内部开一个接口(定义一个方法),在该方法内访问隐藏的属性 使用者以后就通过该方法来“间接地”访问内部隐藏的属性 作为类的设计者可以在接口之上附加任意逻辑从而严格控制类的使用者对属性的操作
优点:外界不能直接访问,让内部的属性与方法具有安全保障
2、如何封装(封装语法)
封装的原理:把用__开头的名字更名为 _类名__变量名,所以直接通过 变量名 | __变量名就访问不到
对象属性的封装,对外提供接口
如何把属性隐藏起来,就在属性前面加上__开头(注意不要加__结尾)
①其实这种隐藏只是一种语法上的变形,对外不对内
class Foo: __x = # _Foo__x= def __init__(self, y): self.__y = y # self._Foo__y=y def __f1(self): # _Foo__f1 print('Foo.f1') def get_y(self): print(self.__y) # print(self._Foo__y) obj = Foo() # print(obj.x) # 报错 # print(obj.__x) # 报错 print(obj._Foo__x) # print(obj._Foo__y) # obj._Foo__f1() # Foo.f1 obj.get_y() #
②这种语法意义上变形,只在类定义阶段发生一次,类定义之后,新增的__开头的属性都没有变形的效果
Foo.__aa= print(Foo.__dict__) obj.__bb= print(obj.__dict__) # {, }
③如果父类不想让子类覆盖自己的方法,可以在方法名前加__开头
class Foo: def __f1(self): # _Foo__f1 print('Foo.f1') def f2(self): print('Foo.f2') self.__f1() # obj._Foo__f1() class Bar(Foo): def __f1(self): # _Bar__f1 print("Bar.f1") obj = Bar() obj.f2() # 结果为: # Foo.f2 # Foo.f1
3、为什么要用封装(封装的目的)
①封装数据属性的目的:把数据属性封装起来,然后需要开辟接口给类外部的使用者使用,
好处是:我们可以在接口之上添加控制逻辑,从而严格空间访问者对属性的操作
class People: def __init__(self, name, age): self.__name = name self.__age = age def tell_info(self): # u=input('user>>: ').strip() # p=input('pwd>>: ').strip() # ': print(self.__name, self.__age) def set_info(self, name, age): if type(name) is not str: raise TypeError('用户名必须为str类型') if type(age) is not int: raise TypeError('年龄必须为int类型') self.__name = name self.__age = age p = People() p.tell_info() # egon p.set_info() p.tell_info() # EGON
②封装函数属性的目的:为了隔离复杂度
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() obj = ATM() obj.withdraw() # 结果为: # 插卡 # 用户认证 # 输入取款金额 # 打印账单 # 取款
4、封装特性:@property
①property是一种特殊的属性,访问它时会执行一段功能(函数)然后有返回值
②为什么要用:将一个类的函数定义成特性以后,对象再去使用的时候obj.name, 根本无法察觉自己的name是执行了一个函数然后计算出来的,
这种特性的使用方式遵循了统一访问的原则
③用法:
例题: BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解) 成人的BMI数值: 过轻:低于18. 正常:18.5-23.9 过重:- 肥胖:- 非常肥胖, 高于32 体质指数(BMI)=体重(kg)÷身高^(m) EX:70kg÷(1.75×1.75)=22.86 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 * self.height) egon = People(, 1.80) print(egon.bmi) # 加上@property后,egon.bmi后不加括号,相当于调用了bmi() # 没有加上@property,要想运行,egon.bmi() # 首先需要明确.bmi是算出来的,不是一个固定死的值,也就说我们必须编写一个功能,每次调用该功能都会立即计算一个值 egon = People(, 1.80) # 但很明显人的bmi值听起来更像一个名词而非动词 print(egon.bmi()) # 会报错。egon.bmi后面加括号相当于是调用了bmi函数,但是bmi函数上被property装饰了之后 # ,bmi函数被伪装成一个数据属性了。 # 于是我们需要为bmi这个函数添加装饰器@property,将其伪装成一个数据属性 egon.weight = print(egon.bmi) # 调用egon.bmi本质就是触发函数bmi的执行,从而拿到其返回值
六、对象的属性方法封装与接口
1、对象的属性封装
①对象的属性值一般都来源于外界,外界是有权力再次访问的
②封装的目的不是让外界无法访问,而且不让其直接访问,可以在完成安全处理后再访问
③如何做到外界还是通过变量名来对属性进行取值赋值
-- __money被封装,外界还是可以通过 对象.money 取值赋值
2、对象的方法封装一般的实现需求都是,这些方法只在内部使用
# 对象的属性与方法封装集中与类的属性与方法封装原理一样 class AAA: def __init__(self, money): self.__money = money self.__id = @property def id(self): return self.__id @id.setter def id(self, id): self.__id = id # 对象的属性封装 # .对象的属性值一般都来源于外界,外界是有权力再次访问的 # .封装的目的不是让外界无法访问,而且不让其直接访问,可以在完成安全处理后再访问 # .如何做到外界还是通过变量名来对属性进行取值赋值 # -- __money被封装,外界还是可以通过 对象.money 取值赋值 # 取值 @property # 在外界可以 对象.money 进行取值 def money(self): # print('走方法拿到的money') return self.__money # 赋值 @money.setter # 在外界可以 对象.money = 新值 进行赋值 def money(self, money): self.__money = money # 删除 @money.deleter def money(self): # print('逗你玩') del self.__money def get_money(self, flag): if flag == '自家人': return self.__money def set_money(self, money): self.__money += money # 对象的方法封装一般的实现需求都是,这些方法只在内部使用 def __test(self): print('test run') a = AAA() print(a.get_money( a.set_money() print(a.get_money( print(a.money) # a.money = print(a.money) #
七、绑定方法和非绑定方法
1、对象的绑定方法:有被任何装饰器装饰的方法
在类内部定义的函数,默认就是给对象来用,而且是绑定给对象用的,称为对象的绑定方法
绑定对象的方法特殊之处:应该由对象来调用,对象来调用,会自动将对象当作第一个参数传入self
2、类的绑定方法:用classmethod装饰器装饰的方法。
classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数
(即便是对象来调用也会将类当作第一个参数传入), python为我们内置了函数classmethod来把类中的函数定义成类方法
class People: country = 'china' def __init__(self, name): self.name = name def run(self): print('%s running...' % self.name) @classmethod def eat(cls, name): cls.name = name print(cls.name +' eating') p1 = People('l_egon') People.eat('egon') # egon eating
3、非绑定方法:用staticmethod装饰器装饰的方法
特性:既不跟类绑定,也不跟对象绑定,这意味着谁都能用,谁来用都是一个普通函数,也就是说没有自动传值的特性了
class People: country = 'china' def __init__(self, name): self.name = name def run(self): print('%s running...' % self.name) @staticmethod def eat(): # 被装饰之后eat()就是一个普通的函数, print('eat') p = People('tank') p.eat() # eat People.eat() # eat
day 23 二十三、对象方法,类方法,封装,绑定方法的更多相关文章
- 类的封装,property特性,类与对象的绑定方法和非绑定方法,
类的封装 就是把数据或者方法封装起来 为什么要封装 封装数据的主要原因是:保护隐私 封装方法的主要原因是:隔离复杂度(快门就是傻瓜相机为傻瓜们提供的方法,该方法将内部复杂的照相功能都隐藏起来了,比如你 ...
- Python面向对象之封装、property特性、绑定方法与非绑定方法
一.封装 ''' 1.什么封装 封:属性对外是隐藏的,但对内是开放的(对内是开放的是因为在类定义阶段这种隐藏已经发生改变) 装:申请一个名称空间,往里装入一系列名字/属性 2.为什么要封装 封装数据属 ...
- day22-类的封装、property特性以及绑定方法与非绑定方法
目录 类的封装 两个层面的封装 第一个层面 第二个层面 封装的好处 私有模块 类的propertry特性 setter 和 deleter 类与对象的绑定方法与非绑定方法 类的封装 将类的属性或方法隐 ...
- 1.面向过程编程 2.面向对象编程 3.类和对象 4.python 创建类和对象 如何使用对象 5.属性的查找顺序 6.初始化函数 7.绑定方法 与非绑定方法
1.面向过程编程 面向过程:一种编程思想在编写代码时 要时刻想着过程这个两个字过程指的是什么? 解决问题的步骤 流程,即第一步干什么 第二步干什么,其目的是将一个复杂的问题,拆分为若干的小的问题,按照 ...
- Python--多态与多态性、绑定方法与非绑定方法
多态与多态性 多态 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承) 1. 序列类型有多种形态:字符串,列表,元组. s='hello' l=[,,] t=('a',' ...
- python 类的绑定方法和非绑定方法
一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. class People: def __ ...
- Day 5-5 绑定方法与非绑定方法
绑定方法与非绑定方法: 在类内部定义的绑定方法,分两大类: classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入 ...
- 全面解析python类的绑定方法与非绑定方法
类中的方法有两类: 绑定方法 非绑定方法 一.绑定方法 1.对象的绑定方法 首先我们明确一个知识点,凡是类中的方法或函数,默认情况下都是绑定给对象使用的.下面,我们通过实例,来慢慢解析绑定方法的应用. ...
- python基础之多态与多态性、绑定方法和非绑定方法
多态与多态性 多态 多态并不是一个新的知识 多态是指一类事物有多种形态,在类里就是指一个抽象类有多个子类,因而多态的概念依赖于继承 举个栗子:动物有多种形态,人.狗.猫.猪等,python的序列数据类 ...
随机推荐
- 初步认识Promise
在解释什么是Promise之前,先看一道练习题,做完练习题也就知道Promise到底是干嘛用的了. 假设现在有个需求:你要封装一个方法,我给你一个要读取文件的路径,你这个方法能帮我读取文件,并把内容返 ...
- SpringBatch框架简介
概观 轻量级,全面的批处理框架,旨在开发对企业系统日常运营至关重要的强大批处理应用程序. Spring Batch提供了可重复使用的功能,这些功能对于处理大量记录至关重要,包括记录/跟踪,事务管理,作 ...
- iTOP-4412开发板_驱动_adc驱动升级和测试例程
本文档介绍 iTOP-4412 开发板的 adc 驱动的升级和测试例程.自带的驱动只能支持一路 adc,本文介绍如何修改可以支持 4 路 adc 的控制.1 硬件简介如下图所示,这是 4412 的 d ...
- POJ 1269 Intersecing Lines (直线相交)
题目: Description We all know that a pair of distinct points on a plane defines a line and that a pair ...
- POJ 2031 Building a Space Station (计算几何+最小生成树)
题目: Description You are a member of the space station engineering team, and are assigned a task in t ...
- ROS-PCL点云库的安装
网上各种说安装点云库还慢,中间出现一些没有依赖库的情况,但在我这里都是很顺利,难道是一开始安装了ROS的原因?不是很清楚,暂且将过程写下来. 一,下载PCL $ git clone https://g ...
- C++入门篇二
c++是c语言的增强版,但是和c语言之间有何区别呢? c和c++的区别: 1.全局变量检测增强int a;int a=10; 2.函数检测增强,参数类型增强,返回值检测增强,函数调用参数检测增强(参数 ...
- 转载:.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法
.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法 阐述签名工具这个概念之前,我先说说它不是什么: 1.它不是用于给程序集加密的工具,它与阻止Reflector或ILSpy对程序集 ...
- hdu4352 数位dp+状态压缩+一个tip
按照nlogn求lis的方法,把lis的状态压缩了,每次新加一个数就把它右边第一个数的位置置为0,然后把这个数加进去 一个需要注意的地方,如果前面都是0,那么状态s中代表0的位置不可以是1,因为这种情 ...
- python设计模式---创建型之单例模式
数据结构和算法是基本功, 设计模式是最佳实现. 作为程序员,必须有空了就练一练哈. # coding = utf-8 """ # 经典单例 class Singleton ...