今日内容概要
- 面向对象的魔法方法
- 基于魔法方法的笔试题
- 元类简介
- 创建类的两种方式
- 元类定制类的产生行为
- 元类定制对象的产生行为
- 魔法之__new__方法
- 设计模式简介及单例模式
面向对象的魔法方法
魔术方法的特征:
1.魔术方法都是双下划线开头,双下划线结尾的方法
2.魔术方法都是 python 内部事先定义的,是对象相关行为的底层实现方法
3.魔术方法都是在特定的情况下自动化触发的,一般不会直接去调用。
常用的魔法方法有哪些:
1.__init__
对象添加独有数据的时候自动触发
2.___str__
对象被执行打印操作的时候自动触发 该方法返回什么,就打印什么,并且该方法必须返回一个字符串类型
3.__call__ 即:对象() 或者 类()()
对象加括号调用的时候自动触发,该方法返回什么,对象调用之后的返回值就是什么
4.__getattr__
对象点不存在的名字的时候自动触发 该方法返回点不存在的名字就可以得到什么
5.__getattribute__
对象点名字就会自动触发 有它的存在就不会执行上面的__getattr__ (不管点的名字是否存在都会触发)
6.__setattr__
给对象添加或者修改数据的时候自动触发 ( 对象.名字 = 值)
7.__enter__
当对象被当做with上下文管理操作的开始自动触发 并且该方法返回什么 as后面的变量名就会接收到什么
8.__exit__
with上下文管理语法运行完毕之后自动触发(子代码结束)
基于魔法方法的笔试题
1.补全下列代码使得运行不报错即可
class Context:
pass
with Context() as f:
f.do_something()
class Context:
def do_something(self):
pass
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Context() as f:
f.do_something()
# 定义字典类型并让字典能够通过句点符的方式操作键值对
class MyDict(dict):
def __setattr__(self, key, value):
self[key] = value
def __getattr__(self,item):
return self.get(item)
obj = MyDict()
obj.name = '水水'
obj.age = 100
obj.pwd = 'momo'
# print(obj) # {'name': '水水', 'age': 100, 'pwd': 'momo'}
# print(obj.age) #100
# print(obj.name) # 水水
# print(obj.pwd) #momo
# print(obj) # 字典存储的数据{'name': '水水', 'age': 100, 'pwd': 'momo'}
print(obj.__dict__) #{}字典对象名称空间
print(type(obj)) #<class '__main__.MyDict'>
元类简介
1.在python中一切皆为对象。让我们先定义一个类,然后逐步分析
"""推导步骤1:如何查看数据的数据类型"""
# s1 = 'hello world' # str()
# l1 = [11, 22, 33, 44] # list()
# d1 = {'name': 'jason', 'pwd': 123} # dict()
# print(type(s1)) # <class 'str'>
# print(type(l1)) # <class 'list'>
# print(type(d1)) # <class 'dict'>
"""推导步骤2:其实type方法是用来查看产生对象的类名"""
# class Student:
# pass
# obj = Student()
# print(type(obj)) # <class '__main__.Student'>
"""推导步骤3:python中一切皆对象 我们好奇type查看类名显示的是什么"""
class Student:
pass
obj = Student()
print(type(obj)) # <class '__main__.Student'>
print(type(Student)) # <class 'type'>
所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象obj是调用类Student得到的
理解元类:
1.元类的含义:Meta类就是元类——类的类,在Python中定义类的关键字class也是一个对象,那么实例化class对象的类就是元类。元类的目的就是为了控制类的创建行为。
2.元类的生成:type作为Python的内建元类,是用来控制类的生成的,class对象就是type实例化生成的。
3.Python中类的创建方法:因此,Python中创建类的方法其实有两种:(1)使用class关键字;(2)通过type关键字
"""结论:如果一切皆为对象,那么类Student本质也是一个对象,既然所有的对象都是调用类得到的
那么Student必然也是调用了一个类得到的,这个类称为元类(type) 产生类的类"""
创建类的两种方式
1.方式一:class 关键字
用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type
class C1:
user_name = '默默'
def func(self): pass
print(C1) #<class '__main__.C1'>
print(C1.user_name) #默默
2.方式2:利用元类type type(类名,类的父类,类的名称空间)
StanfordTeache = type( class_name, class_bases, class_dict )
cls = type('c1',(object,),{'name':'水水'})
print(cls) #<class '__main__.c1'>
print(cls.__dict__) # 对象名称空间
"""
了解知识:名称空间的产生
1.手动写键值对
针对绑定方法不好定义
2.内置方法exec
能够运行字符串类型的代码并产生名称空间
"""
元类定制类的产生行为
"""
推导:
对象是由类名加括号产生的 __init__
类是由元类加括号产生的 __init__
"""
自定义一个元类
1.一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,这样我们用 class 关键字生成的元类使用的就是我们自定义的元类
class 类名( 继承的类名, … , metaclass = 自定义的元类名(默认为 type) )
步骤分析:
1、需求分析-----People类,满足类名首字母必须大写,否则无法产生;
2、首先需要自定义元类 Mymetaclass, 这样 class 类名(metaclass=MyMetaClass)就会对metaclass就会对类名首字母判断
3、使用 class 关键字创建类,相当于 类名 = Mymeta ( ‘类名’ , (需要继承的基类们,) , { 类体代码执行后的名称空间 } )
4、调用 Mymetaclass 类—发生"三件事":
生成一个空对象,调用__init__方法初始化对象,这个对象当做返回
5、由于 Mymetaclass 类传入了三个参数,所以需要__init__方法,要传入这三个参数以及空对象
6、在 __init__ 方法中 对传入的参数进行 需求的自定义
# 自定义一个元类:继承type的类也称为元类
class MyMetaClass(type):
def __init__(cls,what,bases=None,dict=None):
# print('what',what)
# print('bases',bases)
# print('dict',dict)
if not what.istitle():
raise TypeError('类的首字母应该都需要大写')
super().__init__(what,bases,dict) # 重用父类的功能
# 指定类的元类:利用关键字Metaclass指定类的元类
# class myclass(metaclass=MyMetaClass):
# desc = '元类其实很有趣的,就是有点费脑子'
class Student(metaclass=MyMetaClass):
info = '老老实实的命名类的名字'
print(Student) # <class '__main__.Student'>
print(Student.__dict__) #对象名称空间
元类定制对象的产生行为
"""
推导
对象加括号会执行产生该对象类里面的 __call__
类加括号会执行产生该类的类里面的 __call__
"""
"""给对象添加独有数据的时候 必须采用关键字参数传参"""
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
# print(args) #()
# print(kwargs)# {'name': '水水', 'age': 100, 'gender': 'male'}
if args:
raise TypeError("这里要求对象独有数据必须按照关键字参数传参!!")
return super().__call__(*args, **kwargs) # 重用父类
class Student(metaclass=MyMetaClass):
def __init__(self, name, age, gender):
print("__init__")
self.name = name
self.age = age
self.gender = gender
# obj = Student('水水', 100, 'male') #这里要求对象独有数据必须按照关键字参数传参!!")
obj = Student(name='水水',age=100, gender='male') #{'name': '水水', 'age': 100, 'gender': 'male'}
print(obj.__dict__)
魔法之__new__方法
概念
触发时机: 在实例化对时触发
参数:至少一个cls 接收当前类
返回值:必须返回一个对象实例
作用:实例化对象
注意:实例化对象是Object类底层实现,其他类继承了Object的__new__才能够实现实例化对象。
没事别碰这个魔术方法,先触发__new__才会触发__init__
1.在调用类的时候,会首先自动触发 _ _ new _ _方法,执行里面的代码,在触发 init 方法
2.
例子:
class MyMetaClass(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __call__(self, *args, **kwargs):
#1. 产生一个空对象(类似于人的骨架)
obj = self.__new__(self)
# 2.d调用__init__给对象添加独有的数据(类似于人添加了血肉)
self.__init__(obj,*args,**kwargs)
# 3.返回创建好的对象
# 如果想让一个 对象 可以加括号 调用,那么需要在该对象的类中加入 call 方法,这个对象调用后的返回值就是 call 方法的返回值
return obj
class Student(metaclass=MyMetaClass):
def __init__(self,name):
self.name = name
obj = Student('水水')
print(obj.name) # 水水
'__new__可以产生空对象'
设计模式简介及单例模式
1.设计模式
前人通过大量的验证创建出来解决一些问题的固定高效的方法
2.IT行业
23种:
创建型
结构型
行为型
3.单列模式
定义:确保一个类最多只有一个实例,并提供一个全局访问点(无论类加括号执行多少次,只会产生一个对象)
目的:
当类中有很多非常强大的方法,我们在程序中很多地方都需要使用
1.优点
1.1.单例模式可以保证内存里只有一个实例,减少了内存的开销。
1.2.可以避免对资源的多重占用。
1.3.单例模式设置全局访问点,可以优化和共享资源的访问。
2.缺点
2.1.单例模式一般没有接口,扩展困难。
2.2.单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则
标签:__,python,元类,面向对象,对象,print,type,class,之元类
From: https://www.cnblogs.com/qiguanfusu/p/16870612.html