面向对象高级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 将在内存中创建一个对象,名 ...
随机推荐
- java web开发入门六(spring mvc)基于intellig idea
spring mvc ssm=spring mvc+spring +mybatis spring mvc工作流程 1A)客户端发出http请求,只要请求形式符合web.xml文件中配置的*.actio ...
- java web开发入门八(ssm整合)基于intellig idea
ssm整合 一.导入相关包 二.开发流程 1.写entity package com.eggtwo.euq.entity; import java.io.Serializable; import ja ...
- 程序员Y先生投保案例分享
大家好,我是闲鱼君.我在2018年底搞了个副业,做了保险经纪人.保险经纪人是为用户服务的第三方机构,找经纪人买保险省钱.省力.保险一次就买对,而且还能提供后续理赔服务,具体可以看我的文章<201 ...
- SpringBoot集成Spring Security(1)——入门程序
因为项目需要,第一次接触 Spring Security,早就听闻 Spring Security 功能强大但上手困难,学习了几天出入门道,特整理这篇文章希望能让后来者少踩一点坑(本文附带实例程序,请 ...
- lower_case_table_names与表格名称大小写的问题
1 简介 在MySQL中,数据库对应数据目录中的目录.数据库中的每个表至少对应数据库目录中的一个文件(也可能是多个,取决于存储引擎).因此,所使用操作系统的大小写敏感性决定了数据库名和表名的大小写敏感 ...
- Java for循环每次都通过list.size()和 string.length()获取大小是否消耗性能?
前言 有人说在for循环之前用一个局部变量先获取到list.size().str.length(),然后在for循环的判断条件里通过这个局部变量替换list.size().str.length()会节 ...
- 深入V8引擎-写在前面
这一篇不打算讲技术,聊点别的吧,写这个的原因主要是看到了我博客园的签名,开始这个最终源码系列前想说点什么. 转行前端(达成) 入行1年vue源码(达成).webpack源码(半达成) 入行2年争取读通 ...
- winform子窗口与父窗口的交互-使用委托与事件
实现子窗口与父窗口的交互,通过父窗口调用并控制子窗口,子窗口也能控制父窗口,使用委托和事件的方法,可以实现. 1.父窗口调用子窗口,并通过子窗口控制父窗口 新建工程,创建两个窗体 显示子窗体的代 ...
- css权重等级
1.问题起因(在一次偶然编写css发现的,.div2 p>.div1 p>.p1,然后做了测试并找查相关资料) 2.解决方案 首先看哪一级的权重高 1.!important,加在样式属性值 ...
- Asp.Net页面刷新防止跳转到其他浏览器或新的选项卡
前端页面js代码: <head> <script> window.name = "PremaritalCheckup_ManSocietyAgreeForm" ...