python 面向对象进阶

一、元类
1.类也是对象

元类是类的类,是类的模板
元类的实例为类,正如类的实例为对象。
在这里插入图片描述
2.类的本质是对象, 于是可以对类做如下的操作:

  1. 你可以将它赋值给一个变量
  2. 你可以拷⻉它
  3. 你可以为它增加属性
  4. 你可以将它作为函数参数进行传递

方法一: 通过分支语句动态地创建类

因为类也是对象,运行时在函数中使用class关键字动态的创建类。
当使用class关键字时,Python解释器自动创建这个对象。当然Python提供手动处理的方法。

如:

def create_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return  Foo
    else:
        class Bar(object):
            pass
        return  Bar
 
cls = create_class(name='foo1')
print(cls.__name__)

测试结果:

Bar

方法二: 通过type函数动态创建类

type函数功能一: 判断对象的类型。

type函数功能二: 动态的创建类。type可以接受一个类的描述作为参数,然后返回一个类。

type函数语法: type(类名, 父类名称的元组, 属性信息)
例如:

def hello(self):
    print("hello")
Person = type('Person',(object, ), {'country':'China', 'hello':hello})
p1 = Person()
print(p1.country)
p1.hello()

测试结果:

China
hello

3.什么是元类?

1). 元类就是创建类的类。函数type就是是元类。

2). Python中一切皆对象。包括整数、字符串、函数以及类都是对象,且都是从type类创建而来。

3). 动态生成类,不能控制类是如何生成的。python3 的metaclass可动态创建类。

4). 很多Web框架都会使用metaclass 来创建类。掌握元类对理解源代码至关重要。eg: ORM框架类

4.自定义元类

metaclass的原理是什么呢? 应用场景: Django(ORM)

元类本身而言,它们其实是很简单的:

   1. 拦截类的创建

   2. 修改类

   3. 返回修改之后的类

单例模式作为软件设计模式中最重要的一个模式之一,需好好掌握。当然,在python3中,单例模式的实现不仅仅是元类,还有其他方式,比如说使用装饰器,重写__new__方法等方式。

# 实现单例模式的方法:
#       1. 装饰器
#       2. new魔术方法
#       3. metaclass自定义元类
 
class Singleton(type):
    """
    type(name, bases, attrs)
    自定义元类实现单例模式, 父类是type
    """
    # 所有类和实例化对象之间的关系; eg: {'Person': Pseron()}
    cache = {}
 
    # 1). 为什么是__call__魔术方法?
    def __call__(cls):
        # 判断类是否已经实例化, 如果没有, 实例化后存储到缓存中。 最后将缓存的信息返回给用户。
        if cls not in  cls.cache:
            cls.cache[cls] = super(Singleton, cls).__call__()
        return  cls.cache[cls]
 
 
# type('Pseron', (), {})
# 创建以各类Person, 指定创建Person类的类(元类)是type.
# 2. metaclass是在做什么? 指定元类为Singleton。
class Person(object, metaclass=Singleton):  # Person = Singleton.__new__(Person, (objects, ), {})
    pass
 
# Person是Singleton元类实例化出的对象, Person()就是对象(), 执行Singleton.__call__魔术方法.
p1 = Person()
p2 = Person()
print(p1, p2)

测试结果:

<__main__.Person object at 0x00000241B3386C50> <__main__.Person object at 0x00000241B3386C50>

注意:99%情况不需要自己自定义元类。
二、 抽象基类

1.什么是抽象基类?

抽象基类有两个特点:

1.规定继承类必须具有抽象基类指定的方法

2.抽象基类无法实例化

     基于上述两个特点,抽象基类主要用于接口设计

    实现抽象基类可以使用内置的abc模块

2.抽象基类应用

import abc
class Human(metaclass=abc.ABCMeta):
    """基类, 定义一个抽象类"""
    @abc.abstractmethod               #规定子类必须有名为introduce的实例方法
    def introduce(self):
        print("introduce.....")
    @abc.abstractmethod
    def hello(self):
        print('hello')
 
class Person(Human):
    # 1).规定继承类必须具有抽象基类指定的方法
    def introduce(self):
        print('person')
    def hello(self):
        print('person hello')
 
# 2). 抽象基类无法实例化
# h = Human()
p = Person()
p.introduce()
p.hello()

测试结果:

person
person hello

三、 自省机制

1.什么是自省?

1). 在日常生活中,自省(introspection)是一种自我检查行为。

2). 在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么、它知道什么以及它能做什么。自省向程序员提供了极大的灵活性和控制力。
3). 例如Python, Ruby, object-C, C++都有自省的能力,这里面的C++的自省的能力最弱,只能够知道是什么类型,而像Python可以知道是什么类型,还有什么属性。

Python中比较常见的自省(introspection)机制(函数用法)有: dir()、type()、hasattr(),、setattr()、getattr()、delattr()、isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。

dir() 查看方法、属性
type() 查看数据类型
hasattr() 判断是否拥有某个方法/属性
setattr() 设置方法/属性
getattr() 获取属性
delattr() 删除某个属性
isinstance() 判断是否具有某个属性

另外:在以上机制当中:setattr()、getattr()、delattr()又被称为反省机制。
四、slots

python中的new-style class要求继承Python中的一个内建类型,一般继承object,也可以继承list或者dict等其他的内建类型。
在python新式类中,可以定义一个变量__slots__,它的作用是阻止在实例化类时为实例分配dict,

默认情况下每个类都会有一个dict,通过__dict__访问,这个dict维护了这个实例的所有属性,举例如下:

class base(object):  
    var=9 #类变量  
    def __init__(self):  
        pass  
  
b=base()  
print b.__dict__  
b.x=2 #添加实例变量  
print b.__dict__ 

运行结果:

{ }
{'x': 2}

可见:实例的dict只保持实例的变量,对于类的属性是不保存的,类的属性包括变量和函数。由于每次实例化一个类都要分配一个新的dict,因此存在空间的浪费,因此有了__slots__。
__slots__是一个元组,包括了当前能访问到的属性。
当定义了slots后,slots中定义的变量变成了类的描述符,相当于java,c++中的成员变量声明,类的实例只能拥有slots中定义的变量,不能再增加新的变量。注意:定义了slots后,就不再有dict。如下:

class base(object):  
    __slots__=('x')  
    var=8  
    def __init__(self):  
        pass  
  
b=base()  
b.x=88 #添加实例变量  
print b.x  
#b.y=99 #无法添加slots之外的变量 (AttributeError: 'base' object has no attribute 'y')  
#print b.__dict__ #定义了__slots__后,就不再有__dict__ (AttributeError: 'base' object has no attribute '__dict__')

运行结果:

88

如果类变量与slots中的变量同名,则该变量被设置为readonly

class base(object):  
    __slots__=('y')  
    y=22 # y是类变量,y与__slots__中的变量同名  
    var=11  
    def __init__(self):  
        pass  
      
b=base()  
print b.y  
print base.y  
#b.y=66 #AttributeError: 'base' object attribute 'y' is read-only

运行结果:

22
22

Python是一门动态语言,可以在运行过程中,修改实例的属性和增删方法。一般,任何类的实例包含一个字典__dict__,
Python通过这个字典可以将任意属性绑定到实例上。有时候我们只想使用固定的属性,而不想任意绑定属性,
这时候我们可以定义一个属性名称集合,只有在这个集合里的名称才可以绑定。__slots__就是完成这个功能的。

class test_slots(object):  
    __slots__='x','y'  
    def printHello(self):  
        print 'hello!'  
  
class test(object):  
    def printHello(self):  
        print 'hello'  
  
print dir(test_slots) #可以看到test_slots类结构里面包含__slots__,x,y  
print dir(test)#test类结构里包含__dict__  
print '**************************************'  
ts=test_slots()  
t=test()  
print dir(ts) #可以看到ts实例结构里面包含__slots__,x,y,不能任意绑定属性  
print dir(t) #t实例结构里包含__dict__,可以任意绑定属性  
print '***************************************'  
ts.x=11 #只能绑定__slots__名称集合里的属性  
t.x=12 #可以任意绑定属性  
print ts.x,t.x  
ts.y=22 #只能绑定__slots__名称集合里的属性  
t.y=23  #可以任意绑定属性  
print ts.y,t.y  
#ts.z=33 #无法绑定__slots__集合之外的属性(AttributeError: 'test_slots' object has no attribute 'z')  
t.z=34 #可以任意绑定属性  
print t.z

运行结果:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
**************************************
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'printHello', 'x', 'y']
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'printHello']
***************************************
11 12
22 23
34
正如上面所说的,默认情况下,Python的新式类和经典类的实例都有一个dict来存储实例的属性。这在一般情况下还不错,而且非常灵活,
乃至在程序中可以随意设置新的属性。但是,对一些在”编译”前就知道有几个固定属性的小class来说,这个dict就有点浪费内存了。
当需要创建大量实例的时候,这个问题变得尤为突出。一种解决方法是在新式类中定义一个__slots__属性。
__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量;这样Python就不会再使用dict,从而节省空间

1.动态语言与静态语言的不同?

1). 动态语言:可以在运行的过程中,修改代码

2). 静态语言:编译时已经确定好代码,运行过程中不能修改

2.如果我们想要限制实例的属性怎么办?

  1. Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性

  2. 使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的。

再举一个_slots限制对象属性的例子:

import time
from datetime import  date
 
class Date(object):
    # __slots__ 来限制该对象能添加的属性信息
    __slots__ =  '__year', '__month', '__day'
    def __new__(cls, year, month, day):
        self = object.__new__(cls)
        self.__year = year
        self.__month = month
        self.__day = day
        return  self
    @property
    def year(self):
        return  self.__year
 
    @property
    def month(self):
        return self.__month
 
    @property
    def day(self):
        return self.__day
    @classmethod
    def today(cls):
        time_t = time.localtime()
        return  cls(time_t.tm_year, time_t.tm_mon, time_t.tm_mday)
 
    def __str__(self):
        return  '%s-%s-%s' %(self.__year, self.__month, self.__day)
 
d = Date(2019, 10, 10)
print("对象类型: ", type(d))        # <class 'datetime.date'>
print("判断是否有year这个属性?", hasattr(d, 'year')) # True
print("判断是否有time这个属性?", hasattr(d, 'time')) # False
 
print(Date.today())

运行结果:

对象类型:  <class '__main__.Date'>
判断是否有year这个属性? True
判断是否有time这个属性? False
weixin063传染病防控宣传微信小程序系统的设计与实现+springboot后端毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值