Python学习--Day 20

148.面向对象之应用(小花猫)

  • 跟着老师走了一遍。
  • 加一个下节课听到的知识点在这里吧,这里写比较合适:类中普通方法之间的调用是要通过self进行的。
class cat:
    type = 'cat'
    # 通过魔术函数初始化
    def __init__(self,nickname,age,color):
        self.nickname = nickname
        self.age = age
        self.color = color
    def eat(self,food):
        print('{} like eat {}'.format(self.nickname,food))
    def catch_mouse(self,color,weight):
        print('The {} cat {} catch a mouse whose weight is {}'.format(color,self.nickname,weight))
    def sleep(self,hour):
        if hour < 8:
            print('sleep !')
        else :
            print('get up!')
cat1 = cat('Amy',4,'red')
cat1.sleep(6)

149.面向对象之应用(小花猫)

非常尴尬,这集重复了,跟上面的一样,这里不再听一遍了2333…上传前大概是文件太多老师马虎了,不过作为白嫖党不敢挑了哈哈哈

150.面向对象之类方法

  • 类方法:①定义的时候需要装饰器,@classmethod;②类方法中的参数不是对象,而是类cls;③类方法中只可以使用类属性,类方法不依赖于对象,在对象没有创建之前也可以使用(即加载时机是跟随类被创建时);④类方法不可以调用普通函数(因为self没有被传参),但是普通函数可以调用类方法。
  • 类方法的作用:可以完成一些不依赖于需要先创建对象然后再执行的操作
  • 从这里也可以回答昨天留下来的一个问题,魔术方法__init__创建的不是类属性,是对象属性,要先创建对象然后才能生成,这样的属性通过类方法调用不到,也因此类方法可以执行一些不需要创建对象就能进行的操作。
  • 下面是老师讲过的代码,关键的地方都一样。
class Dog:
    # 通过魔术函数初始化
    def __init__(self,nickname):
        self.nickname = nickname # 动态添加nickname属性
    def run(self): # 依赖于对象才能调用
        print('Dog is running.')
    @classmethod
    def test(cls): # 不依赖于对象调用
        print(cls)
        print(cls.nickname) # AttributeError: type object 'Dog' has no attribute 'nickname'
        # 此时的nickname只是对象有的属性,并不是类具有的属性

d = Dog('Tom')
d.run()
Dog.test() # √
d.test() # 报错

151.面向对象之静态方法

  • 在变量前添加两个横杠__使对象私有化——在类外部调用这个变量是无法访问的。
class Person(object):
    __age = 16 # 变量私有化,对外不开放
    def show(self):
        print(self.age)
    @classmethod
    def test(cls):
        print('类方法')
p = Person()
# 访问出错:
print(p.age) # AttributeError: 'Person' object has no attribute 'age'
  • 静态方法:①类似类方法;②需要使用装饰器@staticmethod;③静态方法无须使用任何参数,可以自己定义参数,但是绝对不需要selfcls;④也只能访问类的属性和方法,对象的属性是无法访问的;⑤加载时机与类方法一致
class Person(object):
    __age = 16 # 变量私有化,对外不开放
    def __init__(self,name):
        self.name = name
    @staticmethod
    def stm():
        print(Person.__age)
Person.stm()
  • 总结:类方法和静态方法
项目类方法静态方法
装饰器@classmethod@staticmethod
参数项有必要参数cls无必要参数
访问权限只能访问类的属性和方法,对象的属性是无法访问的同类方法
调用都可以使用类名进行调用同类方法
创建时间都可以在创建对象之前使用,因为不依赖于对象同类方法
  • 总结:普通方法、静态和类方法
项目普通方法静态与类方法
装饰器
对象依赖依赖对象不依赖
调用只有创建对象才可以调用不必创建对象

152.面向对象之魔术方法(init与new)

  • 魔术方法之__init__()
    触发时机:初始化对象时触发(不是实例化触发,但是和实例化在一个操作中)
    参数:至少一个self
    返回值:无
    作用:初始化对象的成员
    注意:初始化的属性不是类属性

  • 魔术方法之__new__()——实例化的魔术方法
    触发时机:在实例化对象时触发
    参数:至少一个cls接收当前类
    返回值:必须返回一个对象实例
    作用:实例化对象
    注意:实例化对象是object类底层上实现,其他类继承了Object的__new__()才能够示例实例化对象

  • newinit:使用new会将init进行覆盖

class Person:
    def __init__(self,name):
        print('___This is init()')
    def __new__(cls,*args,**kwargs):
        print('___This is new()')
p = Person('Amy') # 执行结果:___This is new()
print(p.name)  # 执行结果:AttributeError: 'NoneType' object has no attribute 'name'
  • 将系统自带的__new__()调用出来的方法:(注意这段老师讲的有点乱,下面代码是老师反复试错的成功案例)
    执行Person()的时候,会先进入函数自己的__new__(),然后该函数返回了object的__new__(),object的__new__()的功能比较单一,就是申请内存开辟空间并返回内存地址,代表对象实例化成功。对象实例化成功后,return出来的地址交给__init__()并执行,获取init执行完毕之后的地址返回给p对象。可以参考图片。
    程序执行过程

__new__()的时机功能是向内存要空间并返回一个地址。

class Person:
    def __init__(self):
        print('___This is init()')
    def __new__(cls,*args,**kwargs):
        print('___This is new()')
        return object.__new__(cls,*args,**kwargs)
p = Person()

153.面向对象之魔术方法(del)

  • 上节课的遗留问题,老师讲解了一下传参应该怎么写:老师随后通过打印__new__()返回的地址和__init__()接收的地址、以及p对象的地址,三者是相同的,证实了上节课所讲的流程。
class Person:
    def __init__(self,name):
    	self.name = name
        print('___This is init()')
    def __new__(cls,*args,**kwargs):
        print('___This is new()')
        return object.__new__(cls) # 注意这里不要写*args,**kwargs了
p = Person('aa')
# 结果:
# ___This is new()
# ___This is init()
  • 魔术方法之__call__()——调用对象的魔术方法
    触发时机:将对象当作函数调用时触发,如果我们向使用对象作为函数调用就要重写__call__(),不重写会报错
    参数:至少一个self接收对象,其余根据调用时参数决定
    调用方法:对象()
    返回值:根据情况而定
    示例:
class Person:
    def __init__(self,name):
        self.name = name
        print('___This is init()')
    def __call__(self, *args, **kwargs):
        print('call')
p = Person('aa')
p() # 将对象当作函数名调用的时候,触发call
  • 魔术方法之__del__()——析构魔术方法
    触发时机:当对象没有用(没有任何变量引用)的时候被触发
    参数:一个self
    返回值:无
    作用:使用完对象进行资源回收
  • 系统方法——sys.getrefcount('p_object')查看当前程序某地址被引用个数是多少,当使用该函数的时候会计一次,因此在程序其他地方引用该地址的数目是返回值-1。注意要使用import sys
import sys
class Person:
    def __init__(self,name):
        self.name = name
        print('___This is init()')
p = Person('aa')
p1 = p
p2 = p
print(sys.getrefcount(p)) # 结果是4,因为该函数本身也调用一次,加前面p1、p、p2一共4次
p1.name = 'tom'
print(p.name) # 修改p1的同时也会修改p 输出结果是tom不是aa
  • 关于__del__()的使用:定义__del__()方法释放资源,执行del 对象的时候只是断掉了p1对p的引用,p的name属性还在。
    ①对象赋值p = Person()+p1 = p,p和p1共同指向同一个地址;②删除地址引用,del p1是删除对地址的引用。③查看引用次数使用sys.getrefcount('p_object');④当一个空间没有了任何引用的时候,才会执行__del__(),python解释器会在程序末尾自动回收所有引用资源,因此如果程序还有未删除的引用该空间的变量名,__del__()就会在最后退出程序的时候才执行。(下面有详细解释)⑤一般别碰这个函数,会导致回收机制紊乱
import sys
class Person:
    def __init__(self,name):
        self.name = name
        # print('___This is init()')
    def __del__(self):
    	print('del----')
p = Person('aa')
p1 = p
p2 = p
print(sys.getrefcount(p)) # 4
del p2
del p1
print(sys.getrefcount(p)) # 3
# 输出结果:
# 4
# 3
# del----
  • __del__()的执行顺序问题(上面④的详解)
    第一段代码是全部铲除了对p的引用(包括p自身),可以发现__del__()被"提前"执行了;第二段是没有全部删除对p的引用,可以发现__del__()是最后才执行的,也就是程序默认的回收程序。
class Person:
    def __init__(self,name):
        self.name = name
    def __del__(self):
        print('del----')
p = Person('aa')
print('程序开始')
p1 = p
p2 = p
del p1
del p2
del p
print('程序末尾')
# 执行结果:
# 程序开始
# del----
# 程序末尾
class Person:
    def __init__(self,name):
        self.name = name
    def __del__(self):
        print('del----')
p = Person('aa')
print('程序开始')
p1 = p
p2 = p
del p1
del p2
print('程序末尾')
# 执行结果:
# 程序开始
# 程序末尾
# del----

154.面向对象之魔术方法(str)

  • __str__()——如果单纯打印对象名称只会返回地址,对于开发者没有太大意义,因此重写该函数会给开发者返回更多的内容。
    触发时机:打印对象名称的时候会自动触发调用__str__()内的内容
    注意:一定要写return,return后面是你需要看到的内容
    示例:
class Person:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __str__(self):
        return '姓名是' + self.name + ',年龄是' + str(self.age) # 注意要使用str转换
p = Person('Amy',34)
print(p) # 因为重写了str魔法函数
# 返回内容:姓名是Amy,年龄是34
  • 魔术方法:不需要调用,在满足特定条件的时候自动触发。
  • 总结魔术方法:重点记init、str;new、del要了解,一般不需要重写,重写会带来更多的麻烦;call视情况自己定。
  • 大总结:
    普通方法定义:def 方法名 (self [, 参数]): 方法体,调用的时候要使用对象.方法名(),方法之间的调用要记得使用self.函数名()
    类方法:@classmethod装饰器的使用+def 方法名(cls,[参数]) : 函数体,调用对象.方法名()类名.方法名()
    静态方法:@staticmethod装饰器的使用+def 方法名([参数]) : 函数体,调用对象.方法名()类名.方法名()
    魔术方法:触发后自动执行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值