day13笔记 动态、限制绑定,构造、 析构函数,封装私有化

一、面向对象基础

1.动态绑定属性和限制绑定
#1.动态绑定属性
class Person():
 def show(self):
     print("姓名:%s,成绩:%d,身高:%.2f" % (self.name,self.score,self.height))

per1 = Person()
#注意:被绑定的属性只能被当前对象持有
per1.name = "张三"
per1.score = 99
per1.height = 173.0
per1.age = 18

per1.show()

per2 = Person()
#print(per2.name) #AttributeError属性错误: 'Person' object has no attribute 'name'


#2.限制绑定
class Person1():

 #注意:使用__slots__限制需要绑定的属性,语法:__slots__ = ("属性1","属性2"。。。。)
 #魔术方法:__xxxx__,一般都是系统的函数或者变量,自定义的函数或者变量尽量不要使用__xxx__
 __slots__ = ("name","score","height")

 def show(self):
     print("姓名:%s,成绩:%d,身高:%.2f" % (self.name,self.score,self.height))

p1 = Person1()
p1.name = "李四"
p1.score = 77
p1.height = 183.3
#p1.age = 18  #AttributeError: 'Person1' object has no attribute 'age'


p1.show()
2.内存中的对象
class Person():
 #类属性
 name = "abc"

 def show(self):
     print("showing")

#1.注意1:一个普通的类,理论上可以创建无数个对象
p1 = Person()
p2 = Person()
print(id(p1),id(p2))  #4378443336 4378443392

p1.show()
p2.show()
print(p1.name,p2.name)

#2.注意2:不同的对象直接访问【对象.变量】定义在类中的变量,访问的是同一块内存空间
print(p1.name is p2.name)
print(id(p1.name) == id(p2.name))  #4378171632 4378171632

#3.注意3:不同的对象通过动态绑定的方式绑定了相同成员变量,指向不同的内存空间
#对象.变量  = 值
#实例属性
p1.age = 18
p2.age = 18
print(p1.age is p2.age)    #True
print(id(p1.age) == id(p2.age))  ##True

p1.age = 20
print(p2.age)
print(p1.age is p2.age)   #False
print(id(p1.age) == id(p2.age))  #False

"""
总结:
 a.变量中存储的是数据的地址
 b.通过动态绑定的方式给对象绑定属性,不同对象的属性指向不同的内存空间,
   但是,该内存空间中如果存储的数据相同,那么通过is或者id比较结果为True
"""
3.构造函数
使用直接赋值【动态绑定属性】方式创建对象,可以使用,但是代码比较繁杂,一般情况下,很多类倾向于将对象创建为有初始状态的,在类中可以定义一个函数,名称为__init__,该特殊的函数被称为构造函数,主要用于创建对象并将对象的数据做出初始化

强调:构造函数包括__new__和__init__

构造函数,也被称为构造器,指的是当创建对象的时候,被自动调用的函数

语法:
def __init__(self):
 函数体
3.1__init__
#1.直接赋值
#缺点:代码比较繁杂,后期不利于维护,可读性低
"""
class Dog():
 pass

d1 = Dog()
d1.name = "小白"
d1.kind = "泰迪"
d1.color = "棕色"

d2 = Dog()
d2.name = "大黄"
d2.kind = "土狗"
d2.color = "浅黄色"

d3 = Dog()
d3.name = "旺财"
d3.kind = "二哈"
d3.color = "白色"
"""

#2.__init__:构造函数
"""
a.可以用来创建对象,并可以将对象创建为初始数据的
b.创建对象的过程中会被自动调用
"""
# a.无参
class Dog():

 def __init__(self):
     print("init被调用了")

 def show(self):
     print("showing")

d1 = Dog()
d1.show()
# d1.__init__()
"""
注意:
 a.当创建对象的时候,会自动调用__init__函数,当没有显式的书写__init__时,
  系统默认提供了一个无参的__init__
 b.d1.__init__()可以手动调用,但是一般不这样使用 
  
"""

print("=" * 30)

#b.有参
class Dog():
 def __init__(self,name,kind,color):
     #当创建对象的时候,当前被创建的对象会自动传参,传给self
     self.name = name
     self.kind = kind
     self.color = color

     #return 399  #TypeError: __init__() should return None, not 'int'

 def show(self):
     print("show~~~bbbb",self.name,self.kind,self.color)

d1 = Dog("小白","泰迪","棕色")
d2 = Dog("大黄","土狗","浅黄色")
print(d1.name)
print(d2.kind)

d3 = Dog("旺财","二哈","白色")

d1.show()
d2.show()
d2.show()
d2.show()

#说明:__init__和__slots__是两回事,在__init__中定义了变量,如果没有限制绑定,还是可以动态绑定
d1.age = 5
print(d1.age)

"""
注意:
 a.__init__和普通函数的用法相同,仍然需要注意参数的匹配
 b.__init__在创建有初始化数据的对象时,可以简化代码
 
 
【面试题】简述构造函数__init__和普通成员函数之间的区别
 a.构造函数仍然是一个成员函数
 b.构造函数的函数名是固定的,但是普通成员函数的函数名可以自定义
 c.构造函数不需要手动调用,系统自动调用,但是普通成员函数必须手动调用
 d.一般情况下,对于一个对象而言,构造函数只会被调用一次,但是,普通成员函数可以被调用无数次
"""
3.2__new__
"""
__init__可以定义一个对象的初始化操作,但是,__init__并不是第一个被自动调用的函数,
实际上,还有一个__new__,两个函数构成了构造函数
"""

#1.只定义__init__
class Check1():
 def __init__(self):
     print("init被调用了")

c1 = Check1()
print(type(c1))   #<class  '__main__.Check1'>

print("=" * 30)

#2.定义__init__和__new__
class Check2():
 #a.init:self表示当前的实例【对象】
 def __init__(self):
     print("init被调用了~~~~",self)

 # b.new:cls表示当前类
 # def __new__(cls, *args, **kwargs):
 #     print("new被调用了", cls)
 #
 #     return super(Check2,cls).__new__(cls, *args, **kwargs)

c2 = Check2()
print(c2)
print(type(c2))

"""
一般情况下,使用init较多,直接创建有初始化数据的对象
但是,构造函数的调用先调用new,然后再调用init
"""
4.析构函数
构造函数:当对象创建的时候自动调用的函数
和构造函数相反,当对象被销毁的时候自动调用的而寒暑,称为析构函数,函数名为__del__
class Person():
 def __init__(self):
     print("init被调用了")
 def __del__(self):
     print("del被调用了")

#1.将对象定义成全局变量,程序执行完毕,对象自动被销毁
# print("start")
# p1 = Person()
# print("end")
"""
start
init被调用了
end
del被调用了
"""

#2.将对象定义成局部变量
# def show():
#     p2 = Person()

# print("start")
# show()
# print("end")
"""
start
init被调用了
del被调用了
end
"""

#3.程序未执行完毕,对象被手动销毁
print("start")

p3 = Person()

print("end")

del p3

print("over")
"""
start
init被调用了
end
del被调用了
over
"""

#总结:del函数的作用:一般用来进行一些清理工作,比如:操作文件之后关闭文件,操作数据库之后关闭数据库等
5.练习

"""
富二代类:
 特征:姓名
 行为:开车,炫耀
"""
class Richman():
 def __init__(self,name):
     self.name = name

 #car表示汽车的对象,实参必须是一个汽车的对象
 def drive(self,car):
     print(self.name + "开着豪车" + car.brand)

 #per表示女友的对象
 def show(self,per,car):
     print(self.name + "向" + per.name + "炫耀豪车" + car.brand + ",你看你这颜色" + car.color + "啧啧啧~~~~")
"""
汽车类:
 特征:品牌,颜色
 行为:奔跑
"""
class Car():
 def __init__(self,brand,color):
     self.brand = brand
     self.color = color

 def run(self):
     print(self.brand + "running")
class Gf():
 def __init__(self,name):
     self.name = name
#测试文件

"""
注意:
 a.在创建包的时候【导入模块】,注意命名:尽量不要出现中文和特殊符号
"""

"""
需求:富二代王思聪开着新车兰博基尼,向他的新女友炫耀

富二代类:
 特征:姓名
 行为:开车,炫耀

汽车类:
 特征:品牌,颜色
 行为:奔跑

女友类:
 特征:姓名
"""
from practice01.richman import Richman
from  practice01.car import Car
from practice01.gf import Gf

#1.创建对象
wang = Richman("王思聪")
car = Car("五菱宏光","骚粉色")
gf = Gf("凤姐")

#2.让富二代执行自己的行为
wang.drive(car)
wang.show(gf,car)

二、封装

1.概念

广义的封装:函数的定义和类的提取,都是封装的体现

狭义的封装:在面向对象编程中,一个类的某些属性,在使用的过程中,如果不希望被外界【直接】访问,就可以将该属性封装【将不希望被外界直接访问的属性私有化private,该属性只能被当前类持有,此时可以给外界暴露一个访问的函数即可】

封装的本质:就是属性私有化的过程

封装的好处:提高了数据的安全性,提高了数据的复用性

举例:插排,不需要关心属性在类的内部被做了什么样的操作,只需要关心可以将值传进去,也可以将值获取出来

2.属性私有化
#1.属性未被私有化
class Person1():
 def __init__(self,name,age):
     self.name = name
     self.age = age

 def show(self):
     print(self.name,self.age)
p1 = Person1("张三",10)
p1.show()
#通过对象直接访问属性,并且给属性重新赋值
p1.name = "jack"
p1.age = 20
p1.show()

print("=" * 30)

#2.属性私有化
#语法:在属性的前面添加两个下划线
class Person2():
 def __init__(self,name,age):
     #私有属性
     self.__name = name
     #公开属性
     self.age = age

 def show(self):
     print(self.__name,self.age)

p2 = Person2("张三",10)
p2.show()

#注意:私有化的属性只能在类的内部被直接访问,在外界不能直接访问
#print(p2.__name)  #AttributeError: 'Person2' object has no attribute '__name'

#动态绑定属性
# p2.name = "jack"
# p2.show()
# p2.__name = "hello"
# p2.show()

#工作原理:一般情况下,私有化的属性被Python解释器解释称了  _类名__属性名,
# 但是不希望通过这种方式访问私有化属性,因为Python是跨平台的,不同的解释器可能会解释成不同的格式
#print(p2._Person2__name)

print("=" * 30)

#3.提供暴露给外界的函数
class Person3():
 def __init__(self,name,age):
     self.__name = name
     self.__age = age

 def show(self):
     print(self.__name,self.__age)

 #传值,修改私有属性的值,设置参数
 def setName(self,name):
     self.__name = name

 #获取值,将私有属性的值返回,设置返回值
 def getName(self):
     return self.__name

 def setAge(self,age):
     if age < 0:
         age = -age
     self.__age = age

 def getAge(self):
     return self.__age

p3 = Person3("张三",10)
p3.show()

#在类的外面访问私有化属性:传值或者获取值
p3.setName("jack")
p3.show()
n = p3.getName()
print(n)

p3.setAge(-37)
print(p3.getAge())

print("=" * 30)

#4.@property
class Person4():
 def __init__(self,name,age):
     self.__name = name
     self.__age = age

 def show(self):
     print(self.__name,self.__age)

 #@property, 获取值,将私有属性的值返回,设置返回值
 #注意:@property装饰器的作用将函数转化为属性使用
 @property
 def name(self):
     print("name~~~property")
     return self.__name

 #@xxx.setter,传值,修改私有属性的值,设置参数
 #注意:xxx表示被@property修饰的函数的函数名
 @name.setter
 def name(self,name):
     print("name~~~~~~~~~setter")
     self.__name = name

 @property
 def age(self):
     return self.__age
 @age.setter
 def age(self,age):
     if age < 0:
         age = -age
     self.__age = age

p4 = Person4("tom",22)
p4.show()

#print(p4.name())  #TypeError: 'str' object is not callable
print(p4.name)  #对象.函数名  相当于调用被@property修饰的函数

p4.name = "bob"   #对象.函数名 = 值 相当于调用被@xxx.setter修饰的函数
print(p4.name)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值