面向对象的魔法方法与元类
面向对象的魔法方法
魔法方法就是在类中定义的双下方法,它不需要人为调用,在特定的条件下会自动触发运行
1. __init__ 对象添加独有数据的时候会自动触发
class A:
def __init__(self, name):
print(name)
obj = A('zyg') # zyg
2. __str__ 对象被执行打印操作的时候会自动触发
class A:
def __init__(self, name):
print(name)
def __str__(self):
print('__str__')
obj = A('zyg') # zyg
print(obj) # __str__
3. __call__ 对象加括号调用的时候自动触发
class A:
def __init__(self, name):
print(name)
def __call__(self, *args, **kwargs):
print('__call__')
obj = A('zyg') # zyg
obj() # __call__
4. __getattr__ 对象点不存在的名字时自动触发
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('__getattr__')
obj = A('zyg') # zyg
obj.age # __getattr__
5. __getattribute__ 对象点名字就会触发,无论名字是否存在,与__getattr__同时存在时只会执行他自己
class A:
def __init__(self, name):
self.name = name
def __getattr__(self, item):
print('__getattr__')
def __getattribute__(self, item):
print('__getattribute__')
obj = A('zyg') # zyg
obj.name # __getattribute__
obj.age # __getattribute__
6. __setattr__ 给对象添加或者修改数据的时候自动触发
class A:
def __init__(self, name):
self.name = name
def __setattr__(self, key, value):
print('__setattr__')
obj = A('zyg') # __setattr__
obj.name = 'json' # __setattr__
7. __enter__
当对象被当做with上下文管理操作的开始自动触发 并且该方法返回什么 as后面的变量名就会接收到什么
__exit__ with上下文管理语法运行完毕之后自动触发(子代码结束)
# __enter__与__exit__必须一起使用,单独使用会报错
class A:
def __init__(self, name):
self.name = name
def __enter__(self):
return '__enter__'
def __exit__(self, exc_type, exc_val, exc_tb):
print('__exit__')
obj = A('zyg')
with obj as f:
print(f)
# __enter__
# __exit__
魔法方法笔试题
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: # Context() 产生对象 f获得__enter__方法的返回值,即f等同于Context()产生的对象
f.do_something() # 对象点方法,增加一个方法即可
2.自定义字典类型并让字典能够通过句点符的方式操作键值对
class MyDict(dict): # 定义子类继承字典,该类产生的对象是一个空字典,如果对象直接使用点名字的方法来添加数据,添加的是对象的名称空间,字典内没有数据
def __setattr__(self, key, value): # 对象调用时self传入的值为对象,key为对象点的名字,value为具体的值
self[key] = value # 字典新增数据的操作
def __getattr__(self, item): # 从字典内取值
return self.get(item)
obj = MyDict()
obj.name = 'jason'
obj.pwd = 18
obj.hobby = 'read'
print(obj) # {'name': 'jason', 'pwd': 18, 'hobby': 'read'}
print(obj.name)
print(obj.pwd)
print(obj.hobby)
print(type(obj)) # <class '__main__.MyDict'>
元类简介
元类简单来说就是产生类的类
python中一切皆对象,我们在查看字符串str、列表list、字典dict、元组tuple的数据类型时用的都是type,那么我们可以测试一下type也是查看产生对象的类名的
class A:
pass
obj = A()
print(type(obj)) # <class '__main__.A'>
由此可见type可以查看产生对象的类名,那能不能查看类
class A:
pass
print(A) # <class 'type'>
用type查看type会发生什么?
print(type(type)) # <class 'type'>
由此我们可以得出结论:我们定义的类都是有type类产生的,也就是说type为元类
创建类的两种方式
方式一:使用关键字class
方式二:使用元类type type(类名,父类,类的名称空间)
obj = type('A', (object,), {'name': 'jason'})
print(obj) # <class '__main__.A'>
print(obj.__dict__) # {'name': 'jason', '__module__': '__main__', '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '__doc__': None}
元类定制类的产生行为
类是由元类产生的,那么我们可以在元类产生类的时候做一些条件限制,这种类就叫做元类定制类
eg:规定所有的类名都必须首字母大写,否则无法产生、
第一步:自定义元类,能继承type的类也称之为元类
class MyMetaClass(type):
def __init__(self, what, bases=None, dict=None):
print('what', what) # 传入参数为类名
print('bases', bases) # ()元组
print('dict', dict) # 字典 名称空间
if not what.istitle():
raise TypeError('你是不是python程序员 懂不懂规矩 类名首字母应该大写啊!!!')
super().__init__(what, bases, dict)
第二步:指定类的元类,利用关键字metaclass指定类的元类
class myclass(metaclass=MyMetaClass): # 类名全小写,会抛出异常
desc = '元类其实很有趣 就是有点绕'
class Student(metaclass=MyMetaClass): # 类名首字母大写,正常执行
info = '我是学生 我很听话'
print(Student)
print(Student.__dict__)
元类定制对象的产生行为
通过元类定制类产生的对象
eg:给对象添加独有数据的时候 必须采用关键字参数传参
class MyMetaClass(type):
def __call__(self, *args, **kwargs): # args接收位置参数,kwargs接收关键字参数
# 1.产生一个空对象(骨架)
# 2.调用__init__给对象添加独有的数据(血肉)
# 3.返回创建好的对象
# print(args) # ('jason', 18, 'male')
# print(kwargs) # {}
if args: # 只需要判断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('jason', 18, 'male') # 报错
obj = Student(name='jason',age= 18,gender= 'male')
print(obj.__dict__)
魔法方法值双下new
class MyMetaClass(type):
def __call__(self, *args, **kwargs):
# 1.产生一个空对象(骨架)
obj = self.__new__(self)
# 2.调用__init__给对象添加独有的数据(血肉)
self.__init__(obj,*args, **kwargs)
# 3.返回创建好的对象
return obj
class Student(metaclass=MyMetaClass):
def __init__(self, name):
self.name = name
obj = Student('jason')
print(obj.name)
"""
__new__可以产生空对象
"""
标签:__,obj,name,self,魔法,元类,面向对象,print,def
From: https://www.cnblogs.com/zyg111/p/16870910.html