昨日回顾

  • 反射

    • 用"字符串"类型的属性名/方法名来找到
    • 属性的值或者方法的内存地址
  • 所有可以反射的内容实际上都是变量 有内存地址
  • 内存地址存的是"具体的值",直接能取到结果
  • 内存地址存的是"函数\方法\类",取到的是内存地址
  • 有哪些东西你一打印打印出的是地址
    • 函数
    • 类中的各种方法

如何反射类

class Foo:pass
import sys
clas = getattr(sys.modules[__name__],'Foo')
print(clas)   # == Foo
obj = clas()   # Foo() 相当于实例化一个Foo对象的过程

如何反射函数

def func():print('12345')
import sys
func_addr = getattr(sys.modules[__name__],'func')
func_addr() # func()

如何反射变量

全局变量
a = {2,2,3}
import sys
b = getattr(sys.modules[__name__],'a')
print(b)

如何反射类里的成员

  • 类中的成员 : 静态变量 静态方法 类方法 对象方法 property方法
  • 习惯使用类调用的有哪些 : 静态变量 静态方法 类方法
  • 对象中的成员 : 对象属性
  • 习惯使用对象调用的有哪些:对象属性 对象方法 property方法
  • 类和对象中成员的反射 都是遵循"调用习惯"的
class Foo:
    Country = 'China'

    @classmethod
    def showCountry(cls):
        print('in showCountry',cls.Country)

    @staticmethod
    def wahaha():
        print('wahaha')
#类中的静态属性
print(getattr(Foo,'Country'))

类中的类方法

print(getattr(Foo, 'showCountry'))   # Foo.showCountry
getattr(Foo, 'showCountry')()   # Foo.showCountry()

类中的静态方法

getattr(Foo, 'wahaha')()   # Foo.wahaha()

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + ' is eating')

alex = Student('alex',84)
print(getattr(alex,'name'))   # alex.name
print(getattr(alex,'age'))   # alex.age
getattr(alex,'eat')()    # alex.eat()
import time
import re
import os
import sys
import random
import json
import pickle
import collections
import hashlib

lst = [1,2,3,4,5]
random.shuffle(lst)
print(lst)

getattr(random,'shuffle')(lst)
print(lst)

isinstance(对象,类) 判断对象是不是这个类或者这个类的子类的对象
issubclass(类1,类2) 判断类1是不是类2的子类

内置方法

  • 90%
  • 内置方法 双下方法 魔术方法
  • 都是python的对象内部自带的
  • 并且都不需要我们自己去调用它

str

repr

class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period
    def __str__(self):
        '''打印这个对象的时候 自动触发__str__'''
        '''使用%s进行字符串的拼接的时候 自动触发__str__'''
        return '%s,%s,%s'%(self.name,self.price,self.period)

python = Course('python',25000,'6 months')
print(python)
print('course %s'%python)
print(f'course {python}')
#如果 不实现str方法,那么对象打印出来只是一串地址
l = [1,2,3]
#l是对象,打印的时候直接显示的是元素
print(l)
class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period

    def __repr__(self):   # 备胎
        return '%s,%s,%s'%(self.name,self.price,self.period)

    def __str__(self):
        return self.name

python = Course('python',25000,'6 months')
print(python)
print('course %s'%python)
print(f'course {python}')
print(repr(python))
print('course %r'%python)

如果str存在,repr也存在

  • 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
  • 而repr(obj)和%r格式化字符串,都会调用__repr__

如果str不存在,repr存在

  • 那么print(obj),字符串格式化format,%s,%r 和repr(obj)都调用__repr__

如果str存在,repr不存在

  • 那么print(obj)和使用字符串格式化format,%s这两种方式 调用的都是__str__
  • repr(obj)和%r格式化字符串 都会打印出内存地址
class Course(object):
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period

    def __repr__(self):   # 备胎
        return '%s,%s,%s'%(self.name,self.price,self.period)

    # def __str__(self):
    #     return self.name

class Python(Course):
    pass
    # def __repr__(self):   # 备胎
    #     return '%s--%s--%s'%(self.name,self.price,self.period)

    # def __str__(self):
    #     return '全栈开发 :'+self.name

py20 = Python('python',25000,'6 months')
print(py20)

打印对象 先走自己的str,如果没有,走父类的,如果除了object之外的所有父类都没有str再回来,找自己的repr,如果自己没有,再找父类的

repr是str的备胎和所有的字符串格式化以及直接打印这个对象相关

str(obj),repr(obj)

流畅的python - repr

print(str('123'))
print(repr('123'))
  • 有了repr或者str在打印对象的时候 就不会显示用户不关心的内存地址了
  • 增强了用户的体验 在程序开发的过程中
  • 如果我们需要频繁打印对象中的属性,需要从类的外部做复杂的拼接,实际上是一种麻烦
  • 如果这个拼接工作在类的内部已经完成了,打印对象的时候直接就能显示

__new__ 构造方法 生产对象的时候用的 - 单例模式

__del__ 析构方法 在删除一个对象之前用的 - 归还操作系统资源

class Foo:
    def __new__(cls, *args, **kwargs):
        print('in new')   # 先执行
        obj = object.__new__(cls)
        print(obj)
        return obj

    def __init__(self):
        print('init',self)    # 后执行

Foo()
  • 实例化一个Foo的对象

    • 先开辟一块儿空间,使用的是Foo这个类内部的__new__

      • 如果我们的Foo类中是没有__new__方法的
      • 调用object类的__new__方法了
class Foo(object):
    def __new__(cls, *args, **kwargs): # cls永远不能使self参数,因为self在之后才被创建
        obj = object.__new__(cls)   # self是在这里被创造出来的
        print('new : ',obj)
        return obj
    def __init__(self):
        print('init',self)

Foo()
  • 在使用self之前,都还有一个生产self的过程

    • 就是在内存中开辟一块属于这个对象的空间,并且在这个空间中存放一个类指针
    • 以上就是__new__做的所有事情

设计模式 - 单例模式

一个类 有且只能有一个实例

class A:pass
a1 = A()
a2 = A()
print(a1)
print(a2)

class A:
    __flag = None
    def __new__(cls, *args, **kwargs):
        if cls.__flag is None:
            cls.__flag = object.__new__(cls)
        return cls.__flag

    def __init__(self,name=None,age=None):
        self.name = name
        if age:
            self.age = age

a1 = A('alex',84)
print(a1)
a2 = A('alex',83)
print(a2)
a3 = A('alex')
print(a3)
print(a1.age)

保证一个类无论 被实例化多少次,只开辟一次空间,始终使用的是同一块内存地址

__del__方法-python解释器

import time
class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def __del__(self):
        # 只和del obj语法有关系,在执行del obj之前会来执行一下__del__中的内容
        print('执行我啦')

a = A('alex',84)
print(a.name)
print(a.age)
# del a   # 这个变量已经没了
time.sleep(1)
在所有的代码都执行完毕之后,所有的值都会被python解释器回收

python解释器清理内存

  1. 我们主动删除 del obj
  2. python解释器周期性删除
  3. 在程序结束之前 所有的内容都需要清空
import time
class A:
    def __init__(self,path):
        self.f = open(path,'w')
    def __del__(self):
        '''归还一些操作系统的资源的时候使用'''
        '''包括文件\网络\数据库连接'''
        self.f.close()

a = A('userinfo')
time.sleep(1)

__call__

源码里用比较多 Flask web框架

对象()自动触发__call__中的内容

class A:
    def call(self):
        print('in call')
    def __call__(self, *args, **kwargs):
        print('in __call__')

A()()
obj = A()
obj()
obj.call()

with的上下文处理

class File:
    def __enter__(self):
        print('start')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit')

with File():
    print('wahaha')
class myopen:
    def __init__(self,path,mode='r'):
        self.path = path
        self.mode = mode

    def __enter__(self):
        print('start')
        self.f = open(self.path,mode=self.mode)
        return self.f

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()
        print('exit')

with myopen('userinfo','a') as f:
    f.write('hello,world')

pickle

import pickle
class MypickleDump:
    def __init__(self,path,mode = 'ab'):
        self.path = path
        self.mode = mode

    def __enter__(self):
        self.f = open(self.path,self.mode)
        return self

    def dump(self,obj):
        pickle.dump(obj,self.f)

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.f.close()

with MypickleDump('pickle_file') as pickle_obj:
    pickle_obj.dump({1,2,3})
    pickle_obj.dump({1,2,3})
    pickle_obj.dump({1,2,3})
    pickle_obj.dump({1,2,3})
    pickle_obj.dump({1,2,3})
    pickle_obj.dump({1,2,3})
class MypickelLoad:
   def __init__(self,path,mode='rb'):
       self.path = path
       self.mode = mode

   def __enter__(self):
       self.f = open(self.path,self.mode)
       return self

   def loaditer(self):
       while True:
           try:
               ret = pickle.load(self.f)
               yield ret
           except EOFError:
               break

   def __exit__(self, exc_type, exc_val, exc_tb):
       self.f.close()
with MypickelLoad('pickle_file') as mypic:
    for obj in mypic.loaditer():
        print(obj)

在一个函数的前后添加功能

利用使用 装饰器函数中的内容

with语句 就是和 __enter__,__exit__

import time
class Timer:
    def __enter__(self):
        self.start = time.time()
    def __exit__(self, exc_type, exc_val, exc_tb):
        print(time.time() - self.start)

def func():
    print('wahaha')
    time.sleep(1)
    print('qqxing')

with Timer():
    func()
class MypickleDump:
   def __init__(self,path,mode = 'ab'):
       self.path = path
       self.mode = mode

   def __enter__(self):
       self.f = open(self.path,self.mode)
       return self

   def dump(self,obj):
       pickle.dump(obj,self.f)

   def __exit__(self, exc_type, exc_val, exc_tb):
       self.f.close()

with MypickleDump('pickle_file') as obj:
   obj.dump({1,2,3,4})

with MypickelLoad('pickle_file') as obj:
  for i in  obj.loaditer():
      print(i)

重要内置方法

  • __new__
  • __del__
  • __call__
  • __str__
  • __repr__
  • __enter__
  • __exit__

最新文章

  1. PYTHON学习之路_PYTHON基础(2)
  2. DDD~DDD从零起步架构说明
  3. WMI
  4. android开发,静音录制视频,在一般清晰度的前提下保证文件大小越小越好
  5. myeclipse 打开xml jsp页面慢 有时候会自动退出
  6. 自杀程序&递归删除目录
  7. ABAP多表关联查询
  8. ajax(省,市,县)三级联动
  9. 简单利用HTTP中的PUT协议拿下SHELL
  10. 洛谷P3369 【模板】普通平衡树(Treap/SBT)
  11. 从jvm角度看懂类初始化、方法重写、重载。
  12. DRF 序列化器-Serializer (2)
  13. vue页面引入外部js文件遇到的问题
  14. Visual C++没事别启用/Za编译选项
  15. crontab命令行和日志查看
  16. Microsoft SQL Server sa 账户 登录错误18456
  17. 洛谷P4623 [COCI2012-2013#6] BUREK [模拟]
  18. ZH奶酪:Linux/Ubuntu 安装/卸载 软件
  19. Iterable/Iterator傻傻分不清
  20. 笔记:LNK2001不代表链接器真的需要链接相关符号

热门文章

  1. 牛客寒假算法基础集训营6 J-迷宫
  2. 封装jsonp
  3. 【Oracle】【2】复制表结构及其数据
  4. js中BOM与DOM的概念与区别
  5. C++的字符串多行输入
  6. CF-787D-线段树建图+最短路
  7. Leetcode 1002. 查找常用字符
  8. Oracle date timestamp 毫秒 - 时间函数总结(转)
  9. 使用ajax提交form表单,包括ajax文件上传【转载】
  10. SpringBoot配置文件的加载位置