python元类单例_python面向对象和元类的理解

1 python类对象与实例对象

python中一切皆对象(广义上的对象),类也不例外,我们可以称类为类对象。python中内建函数type()可以返回对象的类型,例如type(int)会得到返回值,而int为类型工厂函数,是内置的类对象。如果对自定义的类使用type()也会返回相同的值。

从上述我们可以总结出:python中type为一般类对象的类(除非子类化type,用type子类创建类对象),即type类可以实例化得到类对象,再由类对象实例化得到实例对象。创建类的类被称为元类

1.1 类属性&实例属性

1.1.1 类属性

类属性是一个类对象的数据或函数元素,类属性包括数据属性和方法。

数据属性 是仅属于类的变量,与任何实例无关,这与C++和Java中静态成员变量相似。

方法 是定义在类中的函数,根据用法,可以分为绑定方法与非绑定方法。绑定方法必须实例化后才能调用,需要与实例绑定;非绑定方法则可以分为静态方法和类方法,可以使用装饰器@staticmethod和@classmethod实现。虽然绑定方法需要实例化后才能调用,但其定义在类中,因此其也属于类的属性。

class P():

version = 1.0 #类的静态数据

@classmethod

def show(cls): #类方法

print(cls.version)

def __init__(self, name, address): #绑定方法,self代表实例

self.name = name

self.address = address

def display(self):

print(self.name)

print(self.address)

def __call__(self):

print(self.name)

def fn():

print('hello,python')

if __name__ == '__main__':

p = P('jay','american')

p1 = P('h','china')

p1.fn = fn

print(P.__dict__)

print(p1.__dict__)

以上是创建类对象的一个例子,__dict__为对象的特殊属性,其值为对象属性构成的字典(并非所有类或实例都有该属性,若定义了__slots__属性则会取代__dict__属性),

运行结果如下:

>>

{'__module__': '__main__', 'version': '1.0',

'show': , '__init__': , 'display': , '__call__': , '__dict__': , '__weakref__': , '__doc__': None}

{'name': 'h', 'address': 'china', 'fn': }

运行结果同时也验证了上述说法,类中定义的绑定方法:__init__, display, __call__,和非绑定方法:show,都是属于类的属性;而fn,name,address则属于实例属性。

1.1.2 实例属性

实例属性是只属于实例对象的方法和数据属性。不同于静态语言,python能动态地创建实例属性,上述代码中的fn即为动态创建的实例属性。

但这样特性的缺陷是如果实例属性在条件语句中创建,若该条件语句并未执行,该属性也就不存在,而后面的代码试着访问这些属性,就会发生错误。

解决办法是避免中途创建实例属性,尽量在__init__方法中初始化实例属性。

1.1.3 类属性VS实例属性

类属性也能通过实例访问,但前提是该实例中没有同名的属性。任何对实例属性的赋值都会新建一个实例属性并对其赋值,但如果类属性中存在同名的属性,则不会对类属性产生影响,若要改变类属性需要使用类名,而不是实例名。

class P():

version = 1

>>p1 = P()

>>p1.version

1

>>p1.version = 2

>>p1.version

2

>>P.version

1

>>P.version = 2

>>P.version

2

1.2 类的特殊方法(魔术方法)

__init__:初始化方法,属于类的绑定方法,第一个参数必须为self(代表实例对象),且无返回值,在__new__返回实例对象后才能调用。

__new__:真正的构造方法,用于创建实例对象,属于静态方法,第一个参数为cls(代表类对象),其返回值为实例对象。

__call__:将对象设置为可调用对象(可以向函数一样用()调用),元类type中实现了该函数,因此类对象为可调用对象,实例化时就是通过调用类来创建实例对象的,覆盖时需要调用父类方法,即super().__call__()

关键知识:覆盖上述特殊函数时,需要特别注意,元类中自定义__call__(self, *args, **kwargs),类对象中若自定义__init__(self, *args, **kwargs), 则自定义__new__(cls, *args, **kwargs),原因如下:

p1 = P(*args, **kwargs)

'''执行顺序:'''

P.__call__(*args, **kwargs):

super().__call__(*args, **kwargs)

goto↓

p1 = object().__new__(P)

p1.__init__(*args, **kwargs)

return p1

2 Metaclass元类

2.1 自定义元类

元类是用来创建其他的类,它的实例就是其他的类。

执行类定义时,解释器会先寻找类属性__metaclass__,如果此属性中未定义,则向上查找其父类中的__metaclass__

type的__init__函数有三个位置参数,分别为:类名称,父类名称元祖,类属性字典;可直接使用type()快速创建类对象:

People = type('People',(object,),dict(show = fn, setage = fn1, age = None))

也可子类化type类后,创建元类,再创建类对象:

from time import ctime

class MetaC(type):

def __init__(self, *args):

super().__init__(*args)

print('调用类的init')

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

print('调用类的call')

_instance = super().__call__(*args, **kwargs)

print('call return %s' %_instance)

return _instance

class Foo(metaclass=MetaC):

# __metaclass__ = MetaC

def __init__(self, version=None):

print('调用对象的init')

def __new__(cls, *args, **kwargs):

print('调用对象的new')

_instance = super().__new__(cls)

print('new return %s' %_instance)

return _instance

foo = Foo('hello')

运行结果:

>>

调用类的init

调用类的call

调用对象的new

new return <__main__.foo object at>

调用对象的init

call return <__main__.foo object at>

2.2 单例模式的实现

下面是几种单例模式的实现方法,有些会用到上述的元类知识。

2.2.1 装饰器实现单例

import weakref

def single_obj(cls):

#实例缓存为弱引用,实例不被使用时会释放该实例

_spam_cache = weakref.WeakValueDictionary()

@wraps(cls)

def wrapper(*args, **kwargs):

if cls not in _spam_cache :

_instance = cls(*args, **kwargs)

_spam_cache [cls] = _instance

return _instance

else:

return _spam_cache [cls]

return wrapper

@single_obj

class A():

def __init__(self, version):

self.version = version

print(self.version)

a1 = A(1.3)

a2 = A(1.2)

print('a1 id:',id(a1))

print('a2 id:',id(a2))

2.2.2 利用元类,类的__call__方法实现单例

class Singleton(type):

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

self._instance = None

super().__init__(*args, **kwargs)

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

if self._instance is None:

self._instance = super().__call__(*args, **kwargs)

return self._instance

else:

return self._instance

class B(metaclass=Singleton):

def __init__(self, name):

self.name = name

print(name)

b1 = B('what')

b2 = B('hell')

print(b2.name)

print('b1 id:',id(b1))

print('b2 id:',id(b2))

2.2.3 通过__new__实现单例(此方法不可行)

class C(object):

_instance = None

def __init__(self, name):

self.name = name

print(name)

def __new__(cls, *args, **kwargs):

if cls._instance is None:

cls._instance = super().__new__(cls)

return cls._instance

c1 = C('dsfsfd')

c2 = C('java')

print('c1 id:',id(c1))

print('c2 id:',id(c2))

若采用上述方法,无论类是否实例化,__init__都会被调用,实例对象会被修改;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/350252.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java命令行界面(第7部分):JCommander

这是我系列的第七篇文章&#xff0c;简要介绍了用于处理Java命令行参数的各种库。 这篇文章回到了基于注释的库的覆盖范围&#xff0c;该库似乎是在Java中可用于处理命令行参数的众多可用库中知名度最高和最受欢迎的库之一&#xff1a; JCommander 。 JCommander的网页上指出&…

Pytorch 加载部分预训练模型并冻结某些层

目录 1 pytorch的版本&#xff1a; 2 数据下载地址&#xff1a; 3 原始版本代码下载&#xff1a; 4 直接上代码&#xff1a; 1 pytorch的版本&#xff1a; 2 数据下载地址&#xff1a; <https://download.pytorch.org/tutorial/hymenoptera_data.zip> 3 原始…

INT类型知多少

前言&#xff1a; 整型是MySQL中最常用的字段类型之一&#xff0c;通常用于存储整数&#xff0c;其中int是整型中最常用的&#xff0c;对于int类型你是否真正了解呢&#xff1f;本文会带你熟悉int类型相关知识&#xff0c;也会介绍其他整型字段的使用。 1.整型分类及存储范围 整…

altera fpga 型号说明_A/X家FPGA架构及资源评估

欢迎FPGA工程师加入官方微信技术群点击蓝字关注我们FPGA之家-中国最好最大的FPGA纯工程师社群评估对比xilinx以及altera两家FPGA芯片逻辑资源。首先要说明&#xff0c;现今FPGA除了常规逻辑资源&#xff0c;还具有很多其他片内资源比如块RAM、DSP单元、高速串行收发器、PLL、AD…

guava api_使用Google Guava的订购API

guava api我们在Google的Guava库中玩的更多&#xff0c;这真是一个了不起的库&#xff01; 我们用于它的最新内容是为我们的域对象整理比较器。 这是如何做。 使用Apache Isis的JDO Objectstore &#xff0c;使您的类实现java.lang.Comparable &#xff0c;并对集合使用SortedS…

Pytorch 加载和保存模型

目录 保存和加载模型 1. 什么是状态字典&#xff1a;state_dict? 2.保存和加载推理模型 2.1 保存/加载 state_dict &#xff08;推荐使用&#xff09; 2.2 保存/加载完整模型 3. 保存和加载 Checkpoint 用于推理/继续训练 4. 在一个文件中保存多个模型 5. 使用在不同…

02-CSS基础与进阶-day9_2018-09-12-20-29-40

定位 静态定位 position: static 相对定位 position: relative 绝对定位 position: absolute 脱标 参考点 子绝父相 让绝对定位的盒子水平居中和垂直居中 固定定位 position: fixed 参考点 浏览器左上角 固定定位的元素脱标不占有位置 兼容性 ie6低版本不支持固定定位 02绝对…

activity直接销毁_Android -- Activity的销毁和重建

两种销毁第一种是正常的销毁&#xff0c;比如用户按下Back按钮或者是activity自己调用了finish()方法&#xff1b;另一种是由于activity处于stopped状态&#xff0c;并且它长期未被使用&#xff0c;或者前台的activity需要更多的资源&#xff0c;这些情况下系统就会关闭后台的进…

Storm和Kafka集成的重要生产错误和修复

我将在此处描述Storm和Kafka集成模块的一些细节&#xff0c;一些您应该意识到的重要错误以及如何克服其中的一些错误&#xff08;尤其是对于生产安装&#xff09;。 我在生产安装中大量使用Apache Storm&#xff0c;并将Kafka作为主要输入源&#xff08;Spout&#xff09;。 …

博客园背景设置CSS代码

/配色参考->>->>>//https://zh.spycolor.com/color-index,a*/ #home { margin: 0 auto; width: 90%;/原始65/ min-width: 980px;/页面顶部的宽度/ background-color:rgba(233,214,107,0.3);/博客主页主体框的颜色/ padding: 30px; margin-top: 25px; margin-bot…

matplotlib 画多条折线图且x轴下标非数值

直接上python代码&#xff1a; # -*- coding: utf-8 -*- import matplotlib.pyplot as plt names [GFK, SA, DA-NBNN, DLID, DaNN, Ours] x range(len(names))y_1 [0.464, 0.45, 0.528, 0.519, 0.536, 0.841] y_2 [0.613, 0.648, 0.766, 0.782, 0.712, 0.954] y_3 [0.663…

julia常用矩阵函数_Julia系列教程3 数学运算 矩阵运算

数学运算https://www.zhihu.com/video/1113554595376295936数学运算比Matlab更直观的数学表达方式x 102x>>20但这就导致了可能会出现语法的冲突十六进制整数文本表达式 0xff 可以被解析为数值文本 0 乘以变量 xff浮点数文本表达式 1e10 可以被解析为数值文本 1 乘以变量…

Mysql 模糊查询 转义字符

MySQL的转义字符“\”\0 一个ASCII 0 (NUL)字符。 \n 一个新行符。 \t 一个定位符。 \r 一个回车符。 \b 一个退格符。 \ 一个单引号(“”)符。 \ " 一个双引号(“ "”)符。 \\ 一个反斜线(“\”)符。 \% 一个…

Pytorch LSTM初识(详解LSTM+torch.nn.LSTM()实现)1

pytorch LSTM1初识 目录 pytorch LSTM1初识 ​​​​​​​​​​​​​​​​​​​​​ 一、LSTM简介1

Java命令行界面(第8部分):Argparse4j

Argparse4j是“ Java命令行参数解析器库”&#xff0c;其主页描述为“基于Python的argparse模块的Java命令行参数解析器库”。 在本文中&#xff0c;我将简要介绍如何使用Argparse4j 0.7.0处理命令行参数&#xff0c;该参数与本系列中的前七篇有关Java命令行处理的文章中所解析…

MvvmLight框架使用入门(三)

MvvmLight框架使用入门&#xff08;三&#xff09; 本篇是MvvmLight框架使用入门的第三篇。从本篇开始&#xff0c;所有代码将通过Windows 10的Universal App来演示。我们将创建一个Universal App并应用MvvmLight框架。 首先通过VS2015创建一个名为UniversalApp的空工程&#x…

Pytorch LSTM实例2

对Pytorch中LSTM实例稍作修改,这是一个词性标注的实例 #导入相应的包 import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optimtorch.manual_seed(1)#准备数据的阶段 def prepare_sequence(seq, to_ix):idxs = [to_ix[w] for w in …

java更好的语言_Java,如果这是一个更好的世界

java更好的语言只是梦想着有一个更好的世界&#xff0c;在该世界中&#xff0c;Java平台中的一些旧错误已得到纠正&#xff0c;而某些令人敬畏的缺失功能也已实现。 不要误会我的意思。 我认为Java很棒。 但是它仍然存在一些问题&#xff0c;就像其他平台一样。 我没有任何特定…

anaconda安装成功测试_学习笔记120—Win10 成功安装Anaconda 【亲测有效,需注意几点!!!】...

Win10 下安装 Anaconda一、下载安装 Anaconda(勾选 PATH)&#xff1a;Anaconda 是专注于数据分析的 Python 发行版本&#xff0c;包含了 conda、Python 等 190 多个科学包及其依赖项。使用 Anaconda 的好处在于可以省去很多配置环境的步 骤&#xff0c;省时省心又便于分析。下载…

Pytorch 词嵌入word_embedding1初识

torch.nn.Embedding(num_embeddings, embedding_dim, padding_idx=None, max_norm=None, norm_type=2, scale_grad_by_freq=False, sparse=False)参数所表示的含义: num_embeddings (int) :嵌入字典的大小 embedding_dim (int) :每个嵌入向量的大小 padding_idx (int, optio…