초간단원팬요리♥소고기스팸에그 [만개의레시피] 재생수3,201 |
등록2018.05.24. 신고 좋아요 댓글 0 나중에 보기

元类允许我们拦截并扩展类创建—-提供了一个API以插入在一条class语句结束时运行的二维逻辑,尽管是以与装饰器不同的方式。

“나중에 보기”에 저장되었습니다.

类是类型的实例
<li>在Python3.0中,用户定义的类对象是名为type的对象的实例,type本身是一个类
<li>类型由派生自type的类定义
<li>用户定义的类是类型类的实例
<li>用户定义的类产生他们自己的实例的类型

퍼가기

1、元类是Type的子类
2、type是产生用户定义的类的一个类
3、类对象是type类的一个实例,或一个子类
4、实例对象产生自一个类

  • #소고기스팸에그
  • #스팸에그후라이
  • #캠핑
  • #락앤락
  • #백종원후라이팬
  • #만개의레시피

Class语句协议
当Python遇到一条class语句,它会运行其嵌套的代码块以创建其属性—-所有在嵌套代码块的顶层分配的名称都产生结果类对象中的属性。在一条class语句的末尾,并且在运行了一个命名空间词典中的所有嵌套代码之后,它调用type对象来创建class对象

펼침

class = type(classname,superclass,attrbutedict)

캠핑갈때 무겁게 갈꾸야…? 。가볍게 해먹는 맛있는 캠핑요리! 예쁜
소고기스팸에그 꽃이 피었습니다! 소고기스팸에그 Spam & Egg필수 재료스팸
1/2캔 Spam, 달걀 5개 Egg, 소금 약간 Salt, 후추 약간 Black Pepper선택
재료대파 약간 Green Onion, 파마산 치즈가루 약간 Parmesan Cheese, 소고기
60g Beef1.스팸을 넓게 잘라 대각선으로 자르고 대파는 송송 썰어
준비한다.2.예열된 팬에 기름을 조금 두르고 스팸 5조각을 돌려가며 올리고
한쪽면을 익힌다.3.한쪽면이 익으면 뒤집어서 빈공간에 달걀을 1개씩
올린다.4.달걀 위에 소금, 후추로 간을 하고 대파, 파마산 치즈가루를 뿌린
후 뚜껑을 닫아 약불에서 익힌다.5.기호에 따라 볶은 소고기나 다른 재료를
올려 완성한다.세상의 모든 레시피 만개의레시피

type对象反过来定义一个_call_运算符重载方法,当调用type对象的时候,该方法运行两个其他的方法:

  • 소고기스팸에그 레시피 보기
  • 락앤락 프라이팬 구매하기
  • 만개의레시피 바로가기
  • 만개의레시피 facebook
  • 만개의레시피 youtube

type.__new__(typeclass,classname,superclasses,attributedict)
type.__init__(class,classname,superclasses,attributedict)
__new__方法创建并返回一个新的class对象,并且随后__init__方法初始化了新创建的对象

例如
<pre>
class Spam(Eggs):
data = 1
def meth(self,arg):
pass
Python将会从内部运行嵌套的代码来创建该类的两个属性(data和meth),然后在class语句的末尾调用type对象,产生class对象:
spam =
type(‘Spam’,(Eggs,),{‘data’:1,’meth’:meth,’__module__’:’__main__’})
</pre>

声明元类
<pre>
class Spam(metaclass=Meta):
pass
当以这种方式声明的时候,创建类对象的调用在class语句的底部运行,修改为调用元类而不是默认的type:
class = Meta(classname,superclass,attributedict)
由于元类是type的一个子类,所以type类的__call__把创建和初始化新的类对象的调用委托给元类
Meta.__new__(Meta,classname,superclass,attributedict)
Meta.__init__(class,classname,superclass,attributedict)


class Spam(Eggs,metaclass = Meta):
data = 1
def meth(self,arg):
pass
“””
这条class语句的末尾,Python内部运行如下的代码来创建class对象
Spam =
Meta(‘Spam’,(Eggs,),{‘data’:1,’meth’:meth,’__module__’:’__main__’})
“””
</pre>

基本元类
<pre>

-coding:UTF-8-

class MetaOne(type):
def __new__(meta,classname,supers,classdict):
print(‘In MetaOne.new’,classname,supers,classdict,sep=’\n..’)
return type.__new__(meta,classname,supers,classdict)
def __init__(Class,classname,supers,classdict):
print(‘In MetaOne init’,classname,supers,classdict,sep=’\n…’)
print(list(Class.__dict__.keys()))
class Eggs:
pass
print(‘making class’)
class Spam(Eggs,metaclass = MetaOne):
data = 1
def meth(self,arg):
pass
if __name__ == ‘main‘:
print(‘making instance’)
X = Spam()
print(‘data:’,X.data)

making class
In MetaOne.new #元类处理类
..Spam
..(<class ‘__main__.Eggs’>,)
..{‘__qualname__’: ‘Spam’, ‘meth’: <function Spam.meth at
0x0060A150>, ‘__module__’: ‘__main__’, ‘data’: 1}
In MetaOne init
…Spam
…(<class ‘main.Eggs’>,)
…{‘_qualname’: ‘Spam’, ‘meth’: <function Spam.meth at
0x0060A150>, ‘__module’: ‘__main’, ‘data’: 1}
[‘meth’, ‘__module
_’, ‘doc‘, ‘data’]
making instance #类用来处理实例
data: 1

Spam继承自Eggs并且是MetaOne的一个实例,在我们真正创建一个实例之前—元类用来处理类,并且类用来处理实例。通常__new__创建并返回了类对象,__init__初始化了已经创建了类。
</pre>


其他元类编程技巧
1>使用简单的工厂函数
实际上任何可调用对象都可以用作一个元类,只要它接收传递的参数并且返回与目标兼容的一个对象。

<pre>
def MetaFunc(classname,supers,classdict):
print(‘In MetaFunc: ‘,classname,supers,classdict,sep=’\n…’)
return type(classname,supers,classdict)
class Eggs:
pass
print(‘making class’)
class Spam(Eggs,metaclass = MetaFunc):
data = 1
def meth(self,arg):
pass
if __name__ == ‘__main__’:
print(‘making instance’)
X = Spam()
print(‘data:’,X.data)

当在声明Spam类时,在class语句的末尾,即
metaclass = MetaFunc
即调用
class = MetaFunc(classname,supers,classdict)
传递
MetaFunc(‘Spam’,(Eggs,),{‘data’:1,’meth’:meth,’__module__’:’__main__’})
</pre>

2>用元类重载类创建调用

<pre>

-coding:UTF-8-

“””
一个元类的元类
“””
class SuperMeta(type):
def __call__(meta,classname,supers,classdict):
print(‘In SuperMeta.call:’,classname,supers,classdict,sep=’\n..’)
return type.__call__(meta,classname,supers,classdict)

class SubMeta(type,metaclass=SuperMeta):
def __new__(meta,classname,supers,classdict):
print(‘In SubMeta.new: ‘,classname,supers,classdict,sep=’\n…’)
return type.__new__(meta,classname,supers,classdict)
def __init__(Class,classname,supers,classdict):
print(‘In SubMeta init: ‘,classname,supers,classdict,sep=’\n…’)
print(‘…init class object: ‘,list(Class.__dict__.keys()))

class Eggs:
pass
print(‘making class’)

class Spam(Eggs,metaclass=SubMeta):
data = 1
def meth(self,arg):
pass

if __name__ == ‘__main__’:
print(‘Makig instance’)
X = Spam()
print(‘data: ‘,X.data)

making class
In SuperMeta.call:
..Spam
..(<class ‘__main__.Eggs’>,)
..{‘__qualname__’: ‘Spam’, ‘__module__’: ‘__main__’, ‘data’:
1, ‘meth’: <function Spam.meth at 0x0061A150>}
In SubMeta.new:
…Spam
…(<class ‘__main__.Eggs’>,)
…{‘__qualname__’: ‘Spam’, ‘__module__’: ‘main‘, ‘data’: 1,
‘meth’: <function Spam.meth at 0x0061A150>}
In SubMeta init:
…Spam
…(<class ‘__main__.Eggs’>,)
…{‘__qualname__’: ‘Spam’, ‘__module__’: ‘__main__’,
‘data’: 1, ‘meth’: <function Spam.meth at 0x0061A150>}
…init class object: [‘__doc__’, ‘__module__’, ‘data’,
‘meth’]
Makig instance
data: 1

把上文中的__call__函数放在SubMeta中是不行的。
同时_\new_是一定要存在的
</pre>

3>用常规类重载类创建调用
<pre>
class SuperMeta:
def __call__(self,classname,supers,classdict):
print(‘In SuperMeta.call: ‘,classname,supers,classdict,sep=’\n…’)
Class = self.__New__(classname,supers,classdict)
self.__Init__(Class,classname,supers,classdict)
return Class

class SubMeta(SuperMeta):
def __New__(self,classname,supers,classdict):
return type(classname,supers,classdict)

def \_\_Init\_\_(self,Class,classname,supers,classdict):
    print('In SubMeta.new',classname,supers,classdict)
    print('..init class object: ',list(Class.__dict__.keys()))

class Eggs:pass

class Spam(Eggs,metaclass=SubMeta()):
data = 1
def meth(self,arg):
pass

print(‘making instance’)
if __name__ == ‘__main__’:
x = Spam()
print(x.data)
</pre>

注意2和3的不同
实例与继承的关系
<li>元类继承自type类。元类是用class语句编写的,并遵从OOP模型。元类通常重新定义type类的__new__和__init__。以定制类创建和初始化,但是,如果他们希望直接捕获类末尾的创建调用的话,也可以重新定义__call__
<li>元类声明由子类继承。在用户定义的类中,metaclass=M声明由该类的子类继承,因此,对于在超类链中继承了这一声明的每个类的构建,该元类都将运行。
<li>元类属性没有由子类实例继承。元类声明指定了一个实例关系,和继承不同。由于类是元类的实例,所以元类中定义的行为应用于类,而不是类随后的实例。实例从他们的类和超类中获取行为,而不是从元类中。实例属性查找通常搜索实例及其所有类的__dict__字典


向类中添加方法
<pre>
def eggsfunc(obj):
return obj.value * 4
def hamfunc(obj,value):
return value+’ ham’
class Extender(type):
“””
添加额外的方法。这里可以添加条件判断执行不同的方法
“””
def __new__(meta,classname,supers,classdict):
classdict[‘eggs’] = eggsfunc
classdict[‘ham’] = hamfunc
return type.__new__(meta,classname,supers,classdict)

class Client1(metaclass=Extender):
def __init__(slef,value):
slef.value = value
def spam(slef):
return slef.value * 2
if __name__ == ‘__main__’:
x = Client1(‘Ni!’)
print(x.spam())
print(x.eggs())

继承也可以为类添加相同的两个方法。然而元类结构支持更多的动态行为。可以在__new__方法中执行判断,执行不同的方法
</pre>