Python中对象的创建与销毁 以及单例类工厂模式相关简述


文章参考: https://www.cnblogs.com/zhangchaoyang/articles/4984768.html

对象的创建

关于__new__ 和 init

在python的类中__new__方法先于__init__方法执行
__new__可以理解为类的实例方法,属于类级别的方法
__init__可以理解为类的初始化方法,属于对象(实例)级别的方法
因此在python中使用类,是用__new__来创建对象,实例对象之后会立即调用__init__方法来对对象属性进行变量初始化,或动态添加对象属性并赋值。
需要注意的是,在重写 new 方法与 init 方法的参数应该保持一致

class Student(object):

    cnt = 0  # 用于记录该类的实例创建了多少个

    def __new__(cls, *args, **kwargs):
        print '__new__'
        cls.cnt += 1
        return super(Student, cls).__new__(cls, *args, **kwargs)

    def __init__(self):
        print '__init__'
        self.name = 'ELE' + str(self.cnt)


if __name__ == '__main__':
    inst1 = Student()
    print 
    inst2 = Student()
    print inst2.name
    print Student.cnt

输出结果

__new__
__init__

__new__
__init__
ELE2
2

关于__call__

关于 call 方法,不得不先提到一个概念,就是可调用对象(callable),我们平时自定义的函数、内置函数和类都属于可调用对象,但凡是可以把一对括号()应用到某个对象身上都可称之为可调用对象,判断对象是否为可调用对象可以用函数 callable
如果在类中实现了 call 方法,那么实例对象也将成为一个可调用对象。
此处参考:https://www.jianshu.com/p/e1d95c4e1697
个人理解可以理解为调用对象的__call__方法,相当于是__call__重载了小括号运算符

对象的销毁

python是垃圾自动回收的,不需要我们显式的销毁对象,当没有引用指向内存中的对象时,即引用计数为0时自动销毁。
当执行del obj时会调用对象的__del__方法, 这时对象的引用计数会减1,当对象的引用计数为0时,对象会被销毁,内存就会被回收。
代码解释如下:

import gc

class A(object):

    def __init__(self):
        self.large_list=[i for i in xrange(10000000)]

    def __del__(self):
        print "__del__"

@profile
def foo():
    a=A()
    b=a
    del b
    del a
    gc.collect()
    print

if __name__ == '__main__':
    foo()

单例模式

通过__new__直接实现单例

既然__new__是类级别的方法,则可以通过这个实例类的方法的重载实现python类的单例模式,如下(此处用name来验证是否是同一个实例对象,并动态创建类属性_instance)

class Singleton1(object):

    name = ''

    def __new__(cls, *args, **kwargs):
        if not '_instance' in vars(cls):
            print 'creating instance of Singleton1'
            cls._instance = super(Singleton1, cls).__new__(cls)
            if len(args) > 0:
                cls.name = args[0]
            elif 'name' in kwargs:
                cls.name = kwargs['name']
        return cls._instance
        
inst1 = Singleton1('a')
inst2 = Singleton1(name='b')
print inst1 is inst2
print inst1.name
print inst2.name

<creating instance of Singleton1
<True
<a
<a

或是以下不采用super的方法

class Singleton2(object):
	_instance = None
	def __new__(cls, *arg, **kwargs):
		if cls._instance is None:
			cls._instance = object.__new__(cls, *arg, **kwarg)
		return cls._instance

inst1 = Singleton2()
inst2 = Singleton2()
print inst1 is inst2

<True

通过元类mateclass方式创建单例类

metaclass 元类

首先简述两种创建类的方法:

1:
class X(object):
        a = 1
2:
X = type('X', (object,), dict(a=1))

其中type(name, bases, dict)实际是构造函数,返回的为一个类对象,其实这里可以理解为一个类就是type的对象。
此处引入元类(metaclass)的解释X = type(‘X’, (object,), dict(a=1)),即类的类,而type就是一个元类,并且 它是python中所有类的元类。
既然知道type可以动态的创建类,则我们可以自定义的实现元类
参考: http://kissg.me/2016/04/25/python-metaclass/
我们为我们创建的新类中的类属性都手动的添加kissg_为前缀

# 我们已经知道type是一个元类,因此自定义元类应继承自type或其子类
# 有一个约定俗成的习惯,自定义元类一般以Metaclass作为后缀,以明确表示这是一个元类
class AddPrefixMetaclass(type):
   # __new__方法在__init__方法之前被调用
   # 因此,当我们想要控制类的创建行为时,一般使用__new__方法
   # 定义普通类的方法时,我们用self作为第一个参数,来指向调用方法的类实例本身
   # 此处addprefix_metaclass的意义与self类似,用于指向使用该元类创建的类本身
   # 其他参数就是类的定义了,依次是类名,父类的元组,属性的字典
   def __new__(addprefix_metaclass, class_name, class_bases, class_dict):
       prefix = "kissg_"
       addprefix_dict = {} # 我们用一个新的字典来储存加了前缀的属性
       # 遍历类的属性,为所有非特殊属性与私有属性加上前缀
       for name, val in class_dict.items():
           if not name.startswith('_'):
               addprefix_dict[prefix + name] = val
           else:
               addprefix_dict[name] = val

       # 调用type函数来返回类,此时我们使用的是加了前缀的属性字典
       return type(class_name, class_bases, addprefix_dict)

# 指定metaclass为自定义的元类,将在创建类时使用该自定义元类
class Myclass(object, metaclass=AddPrefixMetaclass):
   name = "kissg"

kg = Myclass()
print(hasattr(Myclass, "name"))
# 输出: False
print(hasattr(Myclass, "kissg_name"))
# 输出: True
print(kg.kissg_name)
# 输出: kissg

依照oop写法,以上代码可写成:

class AddPrefixMetaclass(type):
    # 此处__new__的参数也是约定俗成的写法,就像用**kw表示关键字参数一样
    # cls - 使用自定义元类要创建的类,你可以就简单地记成self
    # clsname - 类名
    # bases - 父类的元组的(tuple)
    # dct - 类属性的字典
    def __new__(cls, clsname, bases, dict_):
        prefix = "kissg_"
        addprefix_dict = {}
        for name, val in dict_.items():
            if not name.startswith('_'):
                addprefix_dict[prefix + name] = val
            else:
                addprefix_dict[name] = val
        # 元类也是可以被继承的。
        # 调用父类的__new__方法来创建类,简化继承
        return super(AddPrefixMetaclass, cls).__new__(cls, clsname, bases, addprefix_dict)

最后原博客还强调,创建类的元类是可以被继承的,有点拗口,但请区别于元类是可以被继承的。这句话的意思是:定义子类时没有指定元类(即没有metaclass=XXXMetaclass),将自动使用其父类的元类来创建该子类。

创建单例类

python 2.x写法

class Singleton(type):

   def __init__(cls, class_name, base_classes, attr_dict):
       cls.__instance = None
       # super(Singleton, cls).__init__(class_name, base_classes, attr_dict)

   def __call__(cls, *args, **kwargs):
       if cls.__instance is None:
           cls.__instance = super(Singleton, cls).__call__(*args, **kwargs)
           return cls.__instance
       else:
           return cls.__instance


class Segger(object):

   __metaclass__ = Singleton

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

if __name__ == '__main__':
   inst1 = Segger('a')
   inst2 = Segger('b')
   print inst1 is inst2
   print inst1.name
   print inst2.name

<True
<a 
<a  # 由于单例只在第一次实例化时候调用call并实现赋值
# Singleton类中的new 和 init 在代码执行到__metaclass__ = Singleton时已经执行,而且只执行一次,不是在segger实例化时候执行的

工厂模式的简单实现

class Fruit(object):
    def __init__(self):
        pass

    def print_color(self):
        pass

class Apple(Fruit):
    def __init__(self):
        pass

    def print_color(self):
        print("apple is in red")

class Orange(Fruit):
    def __init__(self):
        pass

    def print_color(self):
        print("orange is in orange")

class FruitFactory(object):
    fruits = {"apple": Apple, "orange": Orange}

    def __new__(cls, name):
        if name in cls.fruits.keys():
            return cls.fruits[name]()
        else:
            return Fruit()

fruit1 = FruitFactory("apple")
fruit2 = FruitFactory("orange")
fruit1.print_color()    
fruit2.print_color()    

输出

apple is in red
orange is in orange

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值