内置函数、反射、自定义内置方法来定制类的功能、元类

内置函数

isinstance(obj,cls):检查obj是否是类cls的对象

1 class Foo(object):
2     pass
3  
4 obj = Foo()
5  
6 isinstance(obj, Foo)

在python3中统一类与类型的概念

d={'x':1}#d=dict('x':1)
print(type(d) is dict)
print(isinstance(d,dict))

issubclass(sub, super):检查sub类是否是 super 类的派生类

1 class Foo(object):
2     pass
3  
4 class Bar(Foo):
5     pass
6  
7 issubclass(Bar, Foo)

 

反射

1.什么是反射

    通过字符串来操作类或者对象的属性

2.如何用

    hasattr:检查对象是否拥有某个属性
    getattr:获取文件属性
    setattr:将对象中的属性设置为新的属性
    delattr:删除对象中的属性

class People:
    country='China'

    def __init__(self,name):
        self.name=name

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

peo1=People('egon')

print(hasattr(peo1,'eat')) # peo1.eat,结果:True

print(getattr(peo1,'eat')) # peo1.eat
print(getattr(peo1,'xxxx',None)) # 如果xxxx存在则返回该值,如果不存在得返回None(默认设置为None可更改)

setattr(peo1,'age',18) # peo1.age=18,注意age为字符串类型
print(peo1,age) # 结果:18

print(peo1.__dict__) # 结果:{'name': 'egon'}
delattr(peo1.'name') # del peo1.name
print(peo1.__dict__) #结果:{}

反射练习:

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def get(self):
        print('get')
    def put(self):
        print('put')
    def run(self):
        while True:
            choice=input('>>>: ').strip()
            if hasattr(self,choice):
                method=getattr(self,choice)
                method ()
            else:
                print('输入的指令不存在') 
peo1=People('egon',18)
peo1.run()

交互界面:
>>>:     #输入 put,get会打印相应提示,否则就打印输入的指令不存在

 

自定义内置方法来定制类的功能

 1.__str__方法(改变对象字符串显示):

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

    #在对象被打印时,自动触发,应该在该方法内采集与对象self有关的信息,然后拼成字符串返回
    def __str__(self):
        print('======>')
        return '<name:%s age:%s>' %(self.name,self.age)

obj=People('egon',18)
obj1=People('alex',18)
print(obj)  #obj.__str__()
print(obj)  #obj.__str__()
print(obj)  #obj.__str__()
print(obj1)  #obj1.__str__()


d={'x':1} #d=dict({'x':1})
print(d)

2、__del__析构方法
__del__会在对象被删除之前自动触发

class People:
    def __init__(self,name,age):
        self.name=name
        self.age=age
        self.f=open('a.txt','rt',encoding='utf-8')

    def __del__(self):
        # print('run=-====>')
        # 做回收系统资源相关的事情
        self.f.close()

obj=People('egon',18)

print('主')

 

元类

1、什么是元类

    在python中一切皆对象,那么我们用class关键字定义的类本身也是一个对象
    负责产生该对象的类称之为元类,即元类可以简称为类的类
        class Foo:  # Foo=元类()
        pass

2、为何要用元类

    元类是负责产生类的,所以我们学习元类或者自定义元类的目的
    是为了控制类的产生过程,还可以控制对象的产生过程

3、如何用元类

    一、储备知识 :内置函数exec的用法,exec 执行储存在字符串或文件中的Python语句,相比于 eval,exec可以执行更复杂的 Python 代码。

cmd="""
x=1
def func(self):
    pass
"""

class_dic={}
exec(cmd,{},class_dic) # exec(object,globals,locals)
print(class_dic)
# 结果:{'x': 1, 'func': <function func at 0x008BA618>}

    二、创建类的方法有两种

大前提:如果说类也是对象的话,那么用class关键字的去创建类的过程也是一个实例化的过程
该实例化的目的是为了得到一个类,调用的是元类

    2.1:用的默认的元类type

class People: # People=type(...)
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age

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

print(type(People))  # 结果:<class 'type'>

    2.1.1创建类的3个要素:类名、基类、类的名称空间

class_name='People'    # 类名
class_bases=(object,)    #基类
class_dic={}    # 类的名称空间
class_body="""    # 类体代码
country='China'
def __init__(self,name,age):
    self.name=name
    self.age=age

def eat(self):
    print('%s is eating' %self.name)
"""
exec(class_body,{},class_dic)

# 准备好创建类的三要素
# print(class_name)
# print(class_bases)
# print(class_dic)

# People=type(类名,基类,类的名称空间)

# People1=type(class_name,class_bases,class_dic)
# print(People1)
# obj1=People1('egon',18)
People=type(class_name,class_bases,class_dic)
# print(People)
obj=People('egon',18)
#
# obj1.eat()
obj.eat()

    2.2 方式二:用的自定义的元类

class Mymeta(type): # 只有继承了type类的才能称之为一个元类,否则就是一个普通的自定义类
    def __init__(self,class_name,class_bases,class_dic):
        print(self)
        print(class_name)
        print(class_bases)
        print(class_dic)
        super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类的功能


分析用class自定义的运行原理(而非元类的运行原理): 

1、拿到一个字符串格式的类名class_name='People' 
2、拿到一个类的基类们class_bases=(object,) 
3、执行类体代码,拿到一个类的名称空间class_dic={...} 
4、调用People=type(class_name,class_bases,class_dic)
class People(object,metaclass=Mymeta): # People=Mymeta(类名,基类们,类的名称空间)
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def eat(self):
        print('%s is eating'%self.name)
应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程
class Mymeta(type): # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
        def __init__(self,class_name,class_bases,class_dic):
        if class_dic.get('__doc__') is None or len(class_dic.get('__doc__').strip()) == 0:
            raise TypeError('类中必须有文档注释,并且文档注释不能为空')
        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')
        super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类的功能

class People(object,metaclass=Mymeta): #People=Mymeta('People',(object,),{....})
    """这是People类"""
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age

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

只有继承了type类的才能称之为一个元类,否则就是一个普通的自定义类

    def __init__(self,class_name,class_bases,class_dic):
        print(self)
        print(class_name)
        print(class_bases)
        print(class_dic)
        super(Mymeta,self).__init__(class_name,class_bases,class_dic) # 重用父类的功能
分析用class自定义的运行原理(而非元类的运行原理): 
1、拿到一个字符串格式的类名class_name='People'
2、拿到一个类的基类们class_bases=(object,)
3、执行类体代码,拿到一个类的名称空间class_dic={...}
4、调用People=type(class_name,class_bases,class_dic) 
class People(object,metaclass=Mymeta): # People=Mymeta(类名,基类们,类的名称空间)
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def eat(self):
        print('%s is eating'%self.name)
应用:自定义元类控制类的产生过程,类的产生过程其实就是元类的调用过程

3.储备知识:call

Python中,只要在创建类型的时候定义了__call__()方法,这个类型就是可调用的。

举例一:

class Foo:

    def __init__(self):
        pass
    
    def __call__(self, *args, **kwargs):

        print('__call__')


obj = Foo() # 执行 __init__
obj()       # 执行 __call__

举例二: 

class Foo:
    def __call__(self,*args,**kwargs):
        print(self)
        print(args)
        print(kwargs)
obj=Foo()
# 要想让obj这个对象变成一个可调用的对象,需要在该对象的类中定义一个方法__call__方法
# 该方法会在调用对象时自动触发
obj(1,2,3,x=1,y=2)

4、自定义元类来控制类的调用的过程,即类的实例化过程

class Mymeta(type):

    def __call__(self, *args, **kwargs):
        # print(self) # self是People
        # print(args)
        # print(kwargs)
        # return 123

        # 1、先造出一个People的空对象
        obj=self.__new__(self)
        # 2、为该对空对象初始化独有的属性
        # print(args,kwargs)
        self.__init__(obj,*args,**kwargs)

        # 3、返回一个初始化的对象
        return obj


class People(object,metaclass=Mymeta):
    country='China'
    def __init__(self,name,age):
        self.name=name
        self.age=age

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

    def __new__(cls, *args, **kwargs):
        print(cls)
        # cls.__new__(cls) # 错误
        obj=super(People,cls).__new__(cls)
        return obj

# 分析:调用Pepole的目的
# 1、先造出一个People的空对象
# 2、为该对空对象初始化独有的属性
obj1=People('egon1',age=18)
obj2=People('egon2',age=18)
print(obj1)
print(obj2)

obj=People('egon',age=18)
print(obj.__dict__)
print(obj.name)
obj.eat()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值