# P155-156
# 函数练习题 没做笔记
# 面向对象练习
# 房子 House 有户型 总面积 剩余面积 总面积的60% 家具名称列表 属性
# 新房子没有任何家具
# 新家具的名称追加到家具列表里
# 判断家具的面积 是否超出剩余面积 超过了 提示放不下
# 家具 Furniture 有名字 占地属性
# 席梦思 bed 4 衣柜 chest 2 餐桌 table 1.5
# 将以上3件家具 添加到 房子里
# 打印房子时要求输出 户型 总面积 剩余面积 家具名称列表
class House(object):
# 缺省参数
def __init__(self,house_type,total_area,fru_list=None):
if fru_list is None: # 如果这个值是None
fru_list = [] # 将 fru_list 设置为空列表
self.house_type = house_type
self.total_area = total_area
self.free_area = total_area * 0.6
self.fru_list = fru_list
def add_fru(self,x):
if self.free_area < x.area:
print('剩余面积不足,{}放不下了'.format(x.name))
else:
self.fru_list.append(x.name)
self.free_area -= x.area
def __str__(self):
return ('户型:{}总面积:{}剩余面积:{}家具:{}'.format(self.house_type,self.total_area,self.free_area,self.fru_list))
# 用return 而不是 print
class Furnitur(object):
def __init__(self,name,area):
self.name = name
self.area = area
# 创建房间的时候 传入户型 和 总面积
house = House('两室一厅',20)
sofa = Furnitur('沙发',10)
bed = Furnitur('席梦思',4)
chest = Furnitur('衣柜',2)
table = Furnitur('餐桌',1.5)
# 把家具添加到房间 (面向对象关注点 让谁做)
house.add_fru(bed)
house.add_fru(sofa)
house.add_fru(chest)
house.add_fru(table)
print(house)
# print 打印一个对象的时候 会调用这个对象的__repr__ 或者 __str__ 方法 获取他们的返回值
# 运算符相关的魔法方法
class Person(object):
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(self.name + "正在吃东西")
def __eq__(self,other):
return self.name == other.name and self.age == other.age
# def __ne__(slef,other): # != 调用这个方法
# def __lt__(slef,other): # < 调用这个方法
# def __le__(slef,other): # <= 调用这个方法
# def __add__(slef,other): # + 加法 调用这个方法
# def __sub__(slef,other): # - 减法 调用这个方法
# def __mul__(slef,other): # * 乘法 调用这个方法
# def __truediv__(slef,other): # / 除法 调用这个方法
# def __pow__(slef,power,modulo=None): # ** 幂运算
# ......
def __gt__(self,other): # > 大于 会自动调用这个方法
return self.age > other.age
# def __ge__(self,other): # 大于等于 >= 调用这个方法
p1 = Person('张三',18)
p2 = Person('李四',20)
p3 = Person('张三',18)
print(p1 is p2)
# == 运算符本质其实是调用对象的__eq__方法 获取他们的返回值
# a == b ---- a.___eq__(b)
print(p1 == p3)
# != 本质上是调用 __ne__ 方法 或者 ___eq__ 方法取反
print(p1 != p2)
print(p2 > p1)
# # 用了这个运算符 就会调用对应方法 如果方法没定义 会报错 具体看内部定义
print(str(p1)) # 转换为字符串 默认会转换为类型加内存地址
# str() 将对象转换成字符串 会自动调用 __str__ 方法
# 1.str() 2.打印对象也会调用
#print(p1)
# int() 调用对象的 __int__ 方法
# float() __float__
### 底层思想 用什么命令 调用对应对象的方法 根据其定义返回指定的值
# 内置属性
class Person(object):
# __slots__ = ('name','age')
# 允许出现的对象属性
'''
注释说明
'''
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self):
print(self.name + "正在吃东西")
p = Person('张三',18)
print(dir(p))
# ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'age', 'eat', 'name']
print(p.__class__)
print(p.__dict__) # 将对象变成字典
print(p.__doc__) # 拿到对象的 '''...''' 的说明
print(Person.__doc__)
# print(p.__slots__)
# P161
# 把对象当作一个字典使用
class Person(object):
# __slots__ = ('name','age')
# 允许出现的对象属性
'''
注释说明
'''
def __init__(self,name,age):
self.name = name
self.age = age
def __setitem__(self,key,value):
# print(key,value)
self.__dict__[key] = value
def __getitem__(self,item):
return self.__dict__[item]
p = Person('张三',18)
print(p.__dict__)
# 将对象转换成字典
# 不能直接将一个对象当作字典来使用
p['name'] = 'jack' # 会调用对象的__setitem__方法
s = Person('张三',18)
s['name'] = 'ww'
print(s.name)
print(p.name)
print(p['name']) # 会调用对象的__getitem__方法
# 对象属性 和 类属性
class Person(object):
# __slots__ = ('name','age')
# 允许出现的对象属性
'''
注释说明
'''
type = 'zss' # 这个定义在类里 函数之外 称之为类属性
def __init__(self,name,age):
self.name = name
self.age = age
# 对象 p1 p2 是通过 Person 类对象 创建的 实例对象
# name age 对象属性 在 __init__ 方法里 以参数的形式定义的
# 每个实例对象都会单独保存一份的属性
# 每个实例对象之间的属性没有关联 互不影响
p1 = Person('张三',18)
p2 = Person('李四',18)
# 类属性可以通过类对象和实例对象获取
print(Person.type)
print(p1.type)
print(p2.type)
# 类属性只能通过类对象修改 实例对象无法修改
p1.type = 'human' # 实例对象并不会修改类属性 而是给实例对象添加了一个新的对象属性
print(p2.type)
Person.type = 'love' # 类对象修改了类属性
print(p2.type)
print(p1.type) # human 自己有了 就不会再去找类属性了 之前添加了一个
# 私有属性
class Person(object):
# __slots__ = ('name','age')
# 允许出现的对象属性
'''
注释说明
'''
type = 'zss' # 这个定义在类里 函数之外 称之为类属性
def __init__(self,name,age):
self.name = name
self.age = age
self.__money = 1000 # 私有变量 __开头的 以两个下划线开始的变量
def test(self):
self.__money += 10 # 内部可以访问私有属性
def get_money(self): # 函数调用私有函数返回值
return self.__money
def set_money(self,qian):
if type(qian) != int:
print('不合法')
return
self.__money = qian
def __demo(self): # 以两个下划线开始的函数 私有函数 外部无法调用 内部使用的
print('demo')
def test(self):
self.__demo() # 内部可以直接调用
p = Person('张三',18)
print(p.name,p.age) # 可以直接获取到
# 私有变量无法直接获取
# p.__demo 不能直接调用 私有方法
p._Person__demo() # 硬调也是可以的
# 获取私有变量的方法:
# 1.使用 对象._类名__私有变量名 获取
print(p._Person__money)
# 2.定义 get 和 set 方法获取
print(p.get_money())
p.set_money(30)
print(p.get_money())
print(p.test())
# 3.使用property 来获取
# 类方法和静态方法
class Person(object):
type = 'live'
def __init__(self,name,age):
self.name = name
self.age = age
def eat(self,food): # 对象方法有一个参数self 指的是实例对象
print(self.name + '正在吃' + food)
# 如果一个方法里没有用到实例对象的任何属性 可以将这个方法写成staic
@staticmethod # 静态方法
def demo():
print('hello')
@classmethod # 类方法
def test(cls): # 如果这个函数只用到了类属性 我们可以把他定义为一个类方法
print('yes') # 类方法 会有一个cls 也不需要手动传参数 自动传参
# cls 指的是类对象 cls ==== Person
print(cls.type)
p = Person('张三',18)
p2 = Person('李四',18)
# 实例对象在调用方法时 不需要给形参self传参 会自动把实例对象传递给self
p.eat('辛拉面') # 直接使用实例对象调用方法
# 对象方法 可以直接使用实例对象.方法名(参数)调用
# 会用到实例对象的属性 p = Person('张三',18)
# 1. 实例对象.方法名(参数)
# 使用实例对象.方法名(参数)调用的方式 不需要传递self
# 会自动将对象名传递给self
p.eat('拉面')
# 对象方法还可以使用 类对象 来调用类名.方法名()
# 2. 类名.方法名()
# 这种方式 不会自动给self 传参 需要手动指定self
Person.eat(p2,'猪头肉')
# 类方法 可以使用实例对象和类对象调用
# 只使用到了类属性 type = 'live'
# 会有一个cls cls 指的是类对象 cls ==== Person
p.test()
# 静态方法
# 没有用到实例对象的任何属性
Person.demo()
p.demo()
class Calculator(object):
@staticmethod
def minus(a,b):
return a - b
@staticmethod
def add(a,b):
return a + b
# 直接使用 不用到实例对象的属性
# 不用创建实例 直接使用
print(Calculator.add(1,4))
print(Calculator.minus(1,4))
# 单例设计模式
class Singleton(object):
__instance = None # 类属性 ##
__is_first = True ##
@classmethod
def __new__(cls,*args,**kwargs):
if cls.__instance is None:
# 申请内存 创建一个对象 并把对象类型设置为cls
cls.__instance = object.__new__(cls)
return cls.__instance
# 如果是空 就申请 s1 就会申请 s2 就不会申请 而是直接指向s1 一样的内存地址
# 不会申请内存地址了 但下面的 __init__ 方法还是会执行 所以后面的会覆盖前面的a和b 这样不符合 要不覆盖
def __init__(self,a,b):
if self.__is_first:
self.a = a
self.b = b
self.__is_first = False # 添加一个 self.__is_first = False
# 类属性只能通过类对象修改 实例对象无法修改 在这里添加了一个self.__is_first = False 后面的就都是Flase
# 只第一次的a b 生效 后面的就不要了
# 第一次 __is_first 这个函数里没有 就调用类属性
# 第二次 __is_first 函数里就有了 是 False
# 调用 __new__ 方法申请内存
# 如果不重写 __new__ 方法 会调用object 的 __new__ 方法取反
# object的 __new__ 方法 会申请内存
# 如果重写了 __new__ 方法 需要自己手动申请内存
s1 = Singleton('s1','ss1')
s2 = Singleton('s2','ss2')
s3 = Singleton('s3','ss3')
print(s1 is s2) # True
print(s1.a) # s2
print(s2.a) # s2
# s1 s2 2个对象实例 而且不一样 但是通过申请相同的内存空间 变一样了
# 单例的思想 让s1 和 s2 一样 后面全部一样