面向对象高级C(元类补充及单例模式)
元类有关知识点补充
#类的名称空间
类的名称空间不能用类似字典的方法修改,例如School类里面有name属性xxx,那么我用School.__dict__[‘name’] = ‘yyy’就会报错“TypeError: 'mappingproxy' object does not support item assignment”原因是类的名称空间和对象的名称空间不一样,后者是一个`a plain dict`,就是普通的字典,而后者是一个`mappingproxy`,不可映射类型,是不含__setattr__方法的
#class底层原理的实现
Person = type('Person', (object,), {})
def __init__(self, name, age):
self.name = name
self.age = age
p = type('Person', (object, ), {'x': 1, '__init__': __init__})
p1 = p('ljy', 19)
class Person:
x = 1
def __init__(self, name, age):
self.name = name
self.age = age
p = Person
q = p('ljy', 18)
print(p.__dict__)
print(q.__dict__)
# exec : 执行字符串的代码,当成python解释器
ss = '''
global x #全局变量要加在最前面
x = 1
y = 2
z = 3
print(y)
'''
g = {}
l = dict()
exec(
ss, g, l
)
print(print(1)) #会打印出1,和None,因为print的返回值是None
print(l) # 先把y=2打印出来,然后再打印局部变量的字典
print(g) #打印全部变量的字典,里面包含x:2,在字典的末尾
# 自定义元类,继承type
class Mymeta(type):
def __init__(self, name, bases, dic):
#self 是Person这个类(对象)
#在这个位置,其实self也就是Person这个类,
#内部已经有东西了,名称空间里面的东西在__new__
#可以通过过dic来判断名称空间,也可以直接通过
#self.__dict__/self.属性 来判断
a = dic.get('name')
if not a:
raise Exception('没有name属性,不能创建')
def __call__(self, *args, **kwargs):
pass
# class Person(metaclass = Mymeta):
'''
Person = Mymeta('Person', (object,), {...})
Mymete类实例化,会把三个参数传到Mymeta的__init__方法中
'''
class PersonException(metaclass=Mymeta):
name = 'lae'#加上这句话,类的名称空间里面就有name属性了
def __init__(self,name,age):
self.name = name
self.age = age
#通过元类控制类的调用过程,实例化产生对象的过程
p1 = PersonException(18)
#因为类中没有name属性,所以会抛异常‘没有name属性,不能创建’
class Person():
def __init__(self, name):
self.name = name
raise Exception('就不让你创建')
p = Person('nick')
# 自动触发Person类__init__的执行,
# 抛异常:就不让你创建
# 总结:可以通过自定义元类,重写__init__方法来控制类的产生
class Mymeta(type):
def __init__(self, name, bases, dic):
if 'name' not in dic.keys():
raise Exception('没有name属性,不能创建')
else:
self.__dict__['name'] = 'nick'
'''
会报错TypeError: 'mappingproxy'
object does not support item assignment
也就是类的名称空间是一个字典,但是不能对里面的值进行修改
(错误详情见下一篇博客整理)
'''
class Person(metaclass=Mymeta):
name = 'ljy'
def __init__(self, name, age):
self.name = name
self.age = age
p = Person('ljy', 19)
print(p.name)
print(Person.name)
class Mymeta(type):
def __call__(self, *args, **kwargs):
#该方法必须返回一个对象(类对象),
# 这个地方返回什么, p=Person('lqz')
#p就是什么
#返回一个真正的Person类的对象
#第一步:产生一个空对象
# object.__new__(self)
# 传一个参数,传类,就会产生一个该类的空对象
#obj是Person类的空对象
obj = object.__new__(self)
# print(self.__new__ is object.__new__)
#打印结果是True,说明
# self.__new__就是object.__new__
#第二步:初始化该对象,把初始值放到对象中
#obj是Person类的空对象,obj.__init__ 调
# 用自己的绑定方法,也就是说Person类中写的
# __init__方法
obj.__init__(*args, **kwargs)
#还可以类来调用
Person.__init__(obj, *args, **kwargs)
self.__init__(obj, *args, **kwargs)
print(obj.name) #打印出来lqz
#第三步:把该对象返回
return obj
class Person(metaclass=Mymeta):
def __init__(self, name):
self.name = name
def __call__(self, *args, **kwargs):
print('XXXX')
p = Person('lqz')
print(p.name)
print(p)
单例模式
一共有23中设计模式,单例模式是指整个过程中只有一个实例,所有生成的实例都指向同一快内存空间
PORT = '192.384.28.2'
HOST = 2728
#方式一:通过类的绑定方法
#当用户不输入端口和地址,每次拿到的对象都是同一个。
class Sql:
_instance = None
def __init__(self, port, host):
self.port = port
self.host = host
@classmethod
def singleton(cls):
if not cls._instance:
cls._instance = cls(PORT, HOST)
return cls._instance
p1 = Sql.singleton()
p2 = Sql.singleton()
p3 = Sql('33306','192.168.1.1')#当用户输入端口和地址,实例化产生新对象
print(p1)
print(P2)
print(p3)
'''
<__main__.Sql object at 0x00000225BDBABFD0>
<__main__.Sql object at 0x00000225BDBABFD0>
<__main__.Sql object at 0x00000225BDBABF98>
'''
##方式二:通过装饰器
#不传参,实例化对象内存地址相同
def get_singleton(cls):
_instance = None
def inner(*args, **kwargs):
if len(args)!=0 or len(kwargs)!=0:
res = cls(*args, **kwargs)
return res
else:
nonlocal _instance
if not _instance:
_instance = cls(PORT, HOST)
return _instance
return inner
@get_singleton
class Sql:
def __init__(self, port, host):
self.port = port
self.host = host
s1=Sql()
s2=Sql()
s3=Sql('33306','192.168.1.1') #传参,实例化对象地址不同
print(s1)
print(s2)
print(s3)
'''
<__main__.Sql object at 0x00000185E9601978>
<__main__.Sql object at 0x00000185E9601978>
<__main__.Sql object at 0x00000185F04CE2B0>
'''
#方法三:用自定义元类
#不传参,实例化对象内存地址相同
class Mymeta(type):
def __init__(cls, name, bases, dic):
cls._instance = cls(PORT, HOST)
def __call__(cls, *args, **kwargs):
if len(args)!=0 or len(kwargs)!=0:
obj = object.__new__(cls)
obj.__init__(*args, **kwargs)
return obj
else:
return cls._instance
class Sql(metaclass=Mymeta):
def __init__(self, port, host):
self.port = port
self.host = host
p1 = Sql()
p2 = Sql()
p3 = Sql(8001, '178.23.4.53')#传参,实例化对象地址不同
print(p1)
print(p2)
print(p3)
"""
<__main__.Sql object at 0x000002469196E320>
<__main__.Sql object at 0x000002469196E320>
<__main__.Sql object at 0x000002469196E438>
"""
#方法四:导入模块
#singleton.py
class Sql():
def __init__(self, port, host):
self.port = port
self.host = host
s1 = Sql(PORT, HOST)
#test.py
def test1():
from singleton import s1
print(s1)
def test2():
from singleton import s1
print(s1)
test1()
test2()
from singleton import s1
from singleton import Sql
s2 = Sql(477, '182.22.2.2')
print(s1)
print(s2)
'''
<sigonleton.Sql object at 0x000001B0456F53C8>
<sigonleton.Sql object at 0x000001B0456F53C8>
<sigonleton.Sql object at 0x000001B0456F53C8>
<sigonleton.Sql object at 0x000001B045B3F080>
'''
面向对象高级C(元类补充及单例模式)的更多相关文章
- CSIC_716_20191129【面向对象高级----反射、类的内置方法(魔法方法)、单例模式】
反射 反射是通过'字符串'对 对象的属性进行操作,反射有四个内置的方法. hasattr 通过字符串 判断对象的属性或者方法是否存在 getattr 通过字符串 获取对象的属性或者方法 ...
- python 面向对象进阶之元类metaclass
一:知识储备 exec exec:三个参数 参数一:字符串形式的命令 参数二:全局作用域(字典形式),如果不指定,默认为globals() 参数三:局部作用域(字典形式),如果不指定,默认为local ...
- Python面向对象篇之元类,附Django Model核心原理
关于元类,我写过一篇,如果你只是了解元类,看下面这一篇就足够了. Python面向对象之类的方法和属性 本篇是深度解剖,如果你觉得元类用不到,呵呵,那是因为你不了解Django. 在Python中有一 ...
- C++面向对象高级编程(五)类与类之间的关系
技术在于交流.沟通,转载请注明出处并保持作品的完整性. 本节主要介绍一下类与类之间的关系,也就是面向对象编程先介绍两个术语 Object Oriented Programming OOP面向对象编 ...
- 【转】python面向对象中的元类
type() 动态语言和静态语言最大的不同,就是函数和类的定义,不是编译时定义的,而是运行时动态创建的. 比方说我们要定义一个Hello的class,就写一个hello.py模块: class Hel ...
- exec , 元类,__new__, __call__ , 单例模式 , 异常
1,类也是对象 ''' 动态语言 可以在运行期间 动态生成类 修改对象属性 静态语言 ''''' ''' type(object_or_name, bases, dict) type(object) ...
- [Python之路] 元类(引申 单例模式)
一.类也是对象 当我们定义一个变量或者函数的时候,我们可以在globals()的返回值字典中找到响应的映射: def A(): print("This is function A" ...
- python 面向对象编程 之 元类
元类是类的类,使我们自定义的类,即我们用class定义类本质就是元类,是类的模板 四步走: 一:控制class定义类的过程 1.先拿到类名 2.在拿到基类 3.执行类体代码,得到名称空间的dict 4 ...
- python 面向对象十二 元类
一.类也是对象 只要使用关键字class,Python解释器在执行的时候就会创建一个对象.下面的代码段: class ObjectCreator(object): pass 将在内存中创建一个对象,名 ...
随机推荐
- mod35云掩膜产品用法
在网上一直没找到一个明确说怎么用MOD35产品的,都是说去看用户手册,第一次看了过一段时间我又忘记怎么搞了,赶紧记下来. 而且现在才发现第一次自己搞的都弄错了. 简单的判断是否是云,只要读取mod35 ...
- Python爬取豆瓣电影top
Python爬取豆瓣电影top250 下面以四种方法去解析数据,前面三种以插件库来解析,第四种以正则表达式去解析. xpath pyquery beaufifulsoup re 爬取信息:名称 评分 ...
- pgsql_pg的数据类型
PostgreSQL 提供了丰富的数据类型.用户可以使用 CREATE TYPE 命令在数据库中创建新的数据类型.PostgreSQL 的数据类型被分为四种,分别是基本数据类型.复合数据类型.域和伪类 ...
- linux 安装jdk 和tomcat
#创建用户是为了区分操作权限,如果不区分的话可以直接用root用户执行文件目录为 /usr/lcdc #创建lcdc用户, #其中-d和-m选项用来为登录名lcdc, /usr/lcdc(/usr为默 ...
- 【Struts】Struts框架配置详解
1.首先将所必须的Jar包放到项目的WebRoot/WEB-INF/lib目录下. 如果你没有这些Jar文件,你可以到Struts官网上下载:http://struts.apache.org/.因为经 ...
- tmp/ccdLyHub.o:(.eh_frame+0x12): undefined reference to `__gxx_personality_v0' collect2: ld returned 1 exit status
其实就是一个问题,gcc只能编译.c文件,你如果取名为.cpp,那么gcc编译就会就会出现这个错误. 这种情况下: 1.用g++编译(.c 或.c++都可以编译) 2.仍用gcc编译,但是文件后缀改为 ...
- 以Integer类型传参值不变来理解Java值传参
最近在写代码的时候出了一个错误,由于对值引用理解的不深,将Integer传入方法中修改,以为传入后直接修改Integer中的值就不用写返回值接收了,虽然很快发现了问题,但还是来总结一下 首先是代码: ...
- centos7.x下环境搭建(四)—redis安装
redis介绍 redis是用C语言开发的一个开源的高性能键值对(key-value)数据库.它通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止redis支持的键值数据类型如下字符串.列表 ...
- 浅析libuv源码-node事件轮询解析(1)
好久没写东西了,过了一段咸鱼生活,无意中想起了脉脉上面一句话: 始终保持自己的竞争力.所以,继续开写! 一般的JavaScript源码看的已经没啥意思了,我也不会写什么xx入门新手教程,最终决定还是啃 ...
- Ubuntu Nginx https 配置
#配置http跳转到https 80跳转443server { listen ; server_name www.***.com www.***.cn; https://$server_name$re ...