面向对象补充

一、isinstance\issubclass

isinstance(obj,cls):判断某个对象是不是某个类的实例

issubclass(sub,super):判断sub类是不是 super类子类/派生类 (所有类都是object的子类或子子类)

class Person:
    pass
class Student(Person):
    pass

stu = Student()

print(type(1) == type(1))  # True

print(isinstance(stu,Student))  # True

print(issubclass(Student,Person))  # True
举个栗子

二、反射:对象具备修正错误的能力

程序可以访问、检测和修改它本身状态或行为的一种能力(自省),通过字符串来操作属性 

hasattr: 是否存在某个属性
getattr: 获取某个属性的值
setattr: 设置某个属性的值
delattr: 删除某个属性
class BlackMedium:
    feature='Ugly'
    def __init__(self,name,addr):
        self.name=name
        self.addr=addr

    def sell_house(self):
        print('%s 黑中介卖房子啦' %self.name)
    def rent_house(self):
        print('%s 黑中介租房子啦' %self.name)

b1=BlackMedium('万成置地','回龙观天露园')

#检测是否含有某属性
print(hasattr(b1,'name'))
print(hasattr(b1,'sell_house'))

#获取属性
n=getattr(b1,'name')
print(n)
func=getattr(b1,'rent_house')
func()

# getattr(b1,'aaaaaaaa') #报错
print(getattr(b1,'aaaaaaaa','不存在啊'))

#设置属性
setattr(b1,'sb',True)
setattr(b1,'show_name',lambda self:self.name+'sb')
print(b1.__dict__)
print(b1.show_name(b1))

#删除属性
delattr(b1,'addr')
delattr(b1,'show_name')
delattr(b1,'show_name111')#不存在,则报错

print(b1.__dict__)
View Code 
#!/usr/bin/env python
# -*- coding:utf-8 -*-

import sys


def s1():
    print 's1'


def s2():
    print 's2'


this_module = sys.modules[__name__]

hasattr(this_module, 's1')
getattr(this_module, 's2')
反射当前模块成员
class CMD:

    def dir(self):
        print("列出当前文件夹目录....")

    def tasklist(self):
        print("查看任务列表.....")


cmd = CMD()


res = input("请输入指令:").strip()

if hasattr(cmd,res):
    func = getattr(cmd,res)
    print(func)
    func()
else:
    print("输入的指令不正确....")
需要编写一个CMD工具 这个工具可以支持两个命令 dir ,tasklist

优点:可以事先定义好接口,接口只有在被完成后才会真正执行,即可以事先把主要逻辑写好(只定义接口),然后后期去实现接口的功能。可以动态导入模块(基于反射当前模块成员)

前后带杠杠的都是特殊的内置函数 会在某些时机自动执行 一般情况我们不应该直接调用他们
__str__:

当我们需要自定义打印显示内容时 就需要实现__str__方法
该方法必须返回一个字符串 返回的是什么 打印出来就是什么

class Test:
    def __init__(self,name):
        self.name = name
    def __str__(self):
        print("str run....")
        return self.name
t = Test("haha")

print(str(t))  # str run....     haha
__str__

改变对象的字符串显示__str__,__repr__

自定制格式化字符串__format__

__del__:

对象被从内存中删除时会自动执行。程序员手动删除这个对象也会自动执行

当使用python打开了一个不属于python管理的数据,因python解释器无法操作系统内存,故python解释器运行结束后,文件依然处于打开状态,此时就需要使用__del__关闭系统资源。简而言之,在程序运行结束时进行清理操作。

__del__也称之为析构函数,即分析构造,并拆除这个对象

class TextFile:

    def __init__(self,filepath,mode="rt",encoding="utf-8"):
        self.file = open(filepath,mode=mode,encoding=encoding)

    def read(self):
        return self.file.read()

    def write(self,text):
        self.file.write(text)

    # 该方法其实就是一个通知性质 仅仅是告诉程序员 对象即将被删除
    def __del__(self):
        # 在这里关闭系统的文件 妥妥的
        self.file.close()


tf = TextFile("2.今日内容.txt")

print(tf.read())

# tf.file.close() 不需要手动关闭了  在对象删除时会自动关闭

tf.read()
__del__

exec 执行字符串类型的python代码

exec(execute):执行,解析执行python代码,并且将得到的名称存储到指定的名称空间,解释器内部也是调用它来执行代码的

# 参数一 需要一个字符串对象 表示需要被执行的python语句
# 参数二 是一个字典 表示全局名称空间
# 参数三 也是一个字典 表示局部名称空间


globalsdic = {}
localsdic = {}

exec("""
aaaaaaaaaaa = 1
bbbbbbbbbbb = 2
def func1():
    print("func1")
""",globalsdic,localsdic)


# 如果同时制定全局和局 则 会将字符串中包含的名称 解析后存到局部中
# print(globalsdic)
print(localsdic)
localsdic["func1"]()
# 如果只传了一个传参数 则 将字符串中包含名称 解析后存到全局中

典型的应用场景:

创建数据库类,用该类实例化出数据库链接对象,对象本身是存放于用户空间内存中,而链接则是由操作系统管理的,存放于内核空间内存中。

当程序结束时,python只会回收自己的内存空间,即用户态内存,而操作系统的资源则没有被回收,这就需要我们定制__del__,在对象被删除前向操作系统发起关闭数据库链接的系统调用,回收资源。这与文件处理是一个道理。

f=open('a.txt') #做了两件事,在用户空间拿到一个f变量,在操作系统内核空间打开一个文件
del f #只回收用户空间的f,操作系统的文件还处于打开状态

#所以我们应该在del f之前保证f.close()执行,即便是没有del,程序执行完毕也会自动del清理资源,于是文件操作的正确用法应该是
f=open('a.txt')
读写...
f.close()
很多情况下大家都容易忽略f.close,这就用到了with上下文管理
文件处理

元类:用于产生类的类,type就是元类

所有的自定义类都是通过type实例化得来

创建模块的过程
1.创建一个空的名称空间
2.执行内部的代码
3.将得到的名字放到名称空间中

控制类的创建过程
1.创建一个元类 (需要继承type)
2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 ,
可以利用这些信息在做处理
3.对于需要被控制的类 需要指定metaclass 为上面的元类 

控制类实例化对象的过程
1.创建一个元类 (需要继承type)
2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来
3.在__call__方法中 必须要先编写模板代码
3.1创建空对象
3.2调用类的__init__方法来初始化这个空对象
3.3返回该对象
4.加入你需要控制的逻辑 
创建模块的过程
1.创建一个空的名称空间
2.执行内部的代码
3.将得到的名字放到名称空间中

控制类的创建过程
1.创建一个元类 (需要继承type)
2.覆盖__init__方法 该方法 会将新建的类对象 类名 父类们 名称空间 都传进来 ,
可以利用这些信息在做处理
3.对于需要被控制的类 需要指定metaclass 为上面的元类 

控制类实例化对象的过程
1.创建一个元类 (需要继承type)
2.覆盖__call__方法 会将 正在实例化对象的类 调用类是传入的参数 都传进来
3.在__call__方法中 必须要先编写模板代码
3.1创建空对象
3.2调用类的__init__方法来初始化这个空对象
3.3返回该对象
4.加入你需要控制的逻辑 

类的三个组成部分:类名 父类们 名称空间

# myclass 包含的代码
code = """
name = "张三"
age = 18
def hello(self):
    print("hello %s" % self.name)
"""

class_name = "MyClass"  # 类的名字
base_classes = (object,)  # 类的的父类们
namespace = {}  # 类的名称空间
exec(code,{},namespace)
res = type(class_name,base_classes,namespace)

print(Student)
print(res.name)
print(res.age)
print(res.hello)

# 1.类是由type实例化产生的
# 2.我们可以使用type来产生一个类
# 3.一个类是由 类名字 类的父类元祖 类的名称空间 三个部分组成

class Test(object): #Test = type("Test",(object,),{})
    pass

元类 -> 实例化产生 -> 类 -> 实例化产生 -> 对象

1. 通过元类来控制类的创建过程 实现 类中必须包含 __doc__ 类名必须是大写开头。

要控制类的创建过程 只要找到类所属的类 中的__init__即可

2. 通过元类来实现一个单例

单例模式:一种设计模式(套路)

单个实例:一个类如果只有一个实例 那么该类称之为单例

为什么需要单例:通过这种方法,可以保证只有一个对象(以__call__控制实例化过程,保证每一次调用都返回一个实例)

__call__方法:对象后面加括号,触发执行。

自定义元类 的目的
1.可以通过__call__ 来控制对象的创建过程
2.可用控制类的创建过程

# 自定义一个元类 元类也是一个类   但是需要继承type
class MyMeta(type):

    def __call__(self, *args, **kwargs):  # self 表示要创建对象的那个类(Person)  *args是调用Person类时传入的参数

        print("MyMte中的 call run'")
        print(self,*args,**kwargs)

        # 下面的三步是固定写法 一个模板 只要你需要控制对象的创建过程 就应该先把模板写出来

        # 1.创建空对象
        obj = object.__new__(self)
        # 2.调用初始化方法
        self.__init__(obj,*args,**kwargs)
        # self.__init__(obj)
        # 3.得到一个完整的对象
        return obj

class Person(metaclass=MyMeta):  # 修改Person类的元类为MyMeta
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __call__(self, *args, **kwargs):
        print("call run...")

p = Person("王二狗",66)   # 调用Person这个对象时 执行的是 Person的类(type)中__call__ 方法
print(p)  # 当调用对象时 会执行该对象所属类中的__call__方法
# p() 可以这样调用哟

print(p.name)
print(p.age)
自定义一个元类

注意:构造方法的执行是由创建对象触发的,即:对象 = 类名() ;而对于 __call__ 方法的执行是由对象后加括号触发的,即:对象() 或者 类()()

猜你喜欢

转载自www.cnblogs.com/dongzhihaoya/p/10146850.html
今日推荐