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的序列数据类 ...
随机推荐
- Anaconda+django安装问题
Anaconda使用中常遇到如下问题: 如果Anaconda不是最新版本,可在Anaconda Prompt中使用如下命令更新至最新版 conda update -n base -c defaults ...
- 爬虫工程师JD归纳
核心能力归纳 负责:多平台信息的抓取,清洗和分析工作 要求: 熟悉常用开源爬虫框架,如 scrapy / pyspider 了解基于Cookie的登录原理,熟悉常用的信息抽取技术,如正则表达式.XP ...
- webpack学习记录
webpack 中文网站 https://webpack.docschina.org/ webpack1 有编译打包 模块热更新 代码分割 文件处理功能 webpack2 tree Shaking( ...
- java 面经
1.什么是Java虚拟机(JVM)?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. ...
- Window10系统中MongoDB数据库导入数据文件
首先进入C:\Program Files\MongoDB\Server\4.0\bin> 打开cmd 创建一个空的数据库集合 db.createCollection("myColl ...
- 关于TabLayout与ViewPager在Fragment中嵌套Fragment使用或配合使用的思考
注意: 因为继承的是Fragment,所以getSupportFragmentManager()与getFragmentManager()方法无法使用,这里需要用到getChildFragmentMa ...
- Machine Schedule poj1325
Machine Schedule Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 17454 Accepted: 7327 ...
- 【原创】Java基础之ClassLoader类加载器简介
classloader简介 1 classloader层次结构(父子关系) Bootstrap(ClassLoader) ExtClassLoader AppClassLoader XXXClassL ...
- PDF怎样添加注释,PDF文件添加注释的方法
Word文件跟纸质文件想要添加注释相信大家都知道该怎么添加,那么现在也使用频率挺高的PDF格式的文件要怎么添加注释呢?添加注释的方法有什么呢?有许多的小伙伴们都想知道吧,今天小编就来跟大家分享一下,想 ...
- SQL反模式学习笔记12 存储图片或其他多媒体大文件
目标:存储图片或其他多媒体大文件 反模式:图片存储在数据库外的文件系统中,数据库表中存储文件的对应的路径和名称. 缺点: 1.文件不支持Delete操作.使用SQL语句删除一条记录时,对应的文 ...