1. 程式人生 > 程式設計 >Python 使用元類type建立類物件常見應用詳解

Python 使用元類type建立類物件常見應用詳解

本文例項講述了Python 使用元類type建立類物件。分享給大家供大家參考,具體如下:

type("123") 可以檢視變數的型別;同時 type("類名",(父類),{類屬性:值,類屬性2:值}) 可以建立一個類。

在Python中不建議一個函式具有不同的功能(過載);type()具有不同的功能是為了相容之前的版本。

類可以建立例項物件,類物件是由元類建立的。 (元類建立類,類建立例項物件)

type就是元類(type本質上就是一個類)

demo.py(用元類type建立類):

# 通過class關鍵字建立類
class MyClass1(object):
  name = "張三" # 類屬性 (所有例項物件共用)
  age = 23
# 通過type建立類。 type()返回的是建立的類物件的引用。
Test2 = type("MyClass2",(object,),{"name":"張三","age":23}) # Test2是MyClass2類的引用,一般變數名和類名保持一致。
print(Test2()) # <__main__.MyClass2 object at 0x7fa05a4ca9e8>

demo.py(用type建立帶有方法的類):

# 例項方法
def print_b(self):
  print(self.num)
# 靜態方法
@staticmethod
def print_static():
  print("----haha-----")
# 類方法
@classmethod
def print_class(cls):
  print(cls.num)
# 用type建立類
B = type("B",{"num":100,"print_b": print_b,"print_static": print_static,"print_class": print_class})
b = B()
b.print_b()   # 100
b.print_static() # ----haha-----
b.print_class()  # 100

元類的應用

在定義一個類的時候可以為其指定__metaclass__屬性(指定建立該類的元類),預設使用type元類建立類物件。

通過指定自定義的元類,可以對類的建立進行攔截。可以對類名、繼承的父類、屬性(方法)做一些預處理。

例如:將類名大寫,預設繼承object類,新增、修改屬性(方法)名(私有屬性的偽私有化就是通過修改屬性名實現的)。

裝飾器是對函式進行功能擴充套件(不用修改原始碼),而元類可以對類進行功能擴充套件(新增額外的屬性/方法)。

demo.py(用函式指定__metaclass__屬性):

#-*- coding:utf-8 -*-
def upper_attr(class_name,class_parents,class_attr):
  # class_name 會儲存類的名字 Foo
  # class_parents 會儲存類的父類 object
  # class_attr 會以字典的方式儲存所有的類屬性/方法
  # 遍歷屬性字典,把不是__開頭的屬性名字變為大寫
  new_attr = {}
  for name,value in class_attr.items():
    if not name.startswith("__"):
      new_attr[name.upper()] = value
  # 呼叫type來建立一個類
  return type(class_name,new_attr)
class Foo(object,metaclass=upper_attr): # python3的方式
  # python2.x的方式。
  # __metaclass__ = upper_attr # 設定Foo類的元類為upper_attr
  bar = 'bip'
print(hasattr(Foo,'bar'))
print(hasattr(Foo,'BAR'))
f = Foo()
print(f.BAR)

demo.py(用類指定__metaclass__屬性):

class UpperAttrMetaClass(type):
  # __new__ 是在__init__之前被呼叫的特殊方法
  # __new__是用來建立物件並返回之的方法
  # 而__init__只是用來將傳入的引數初始化給物件
  # 你很少用到__new__,除非你希望能夠控制物件的建立
  # 這裡,建立的物件是類,我們希望能夠自定義它,所以我們這裡改寫__new__
  # 如果你希望的話,你也可以在__init__中做些事情
  # 還有一些高階的用法會涉及到改寫__call__特殊方法,但是我們這裡不用
  def __new__(cls,class_name,class_attr):
    # 遍歷屬性字典,把不是__開頭的屬性名字變為大寫
    new_attr = {}
    for name,value in class_attr.items():
      if not name.startswith("__"):
        new_attr[name.upper()] = value
    # 方法1:通過'type'來做類物件的建立
    return type(class_name,new_attr)
    # 方法2:複用type.__new__方法
    # 這就是基本的OOP程式設計,沒什麼魔法
    # return type.__new__(cls,new_attr)
# python3的用法
class Foo(object,metaclass=UpperAttrMetaClass):
  bar = 'bip'
# python2的用法
# class Foo(object):
#   __metaclass__ = UpperAttrMetaClass
#   bar = 'bip'
print(hasattr(Foo,'bar'))
# 輸出: False
print(hasattr(Foo,'BAR'))
# 輸出:True
f = Foo()
print(f.BAR)
# 輸出:'bip'

更多關於Python相關內容感興趣的讀者可檢視本站專題:《Python面向物件程式設計入門與進階教程》、《Python資料結構與演算法教程》、《Python函式使用技巧總結》、《Python字串操作技巧彙總》、《Python編碼操作技巧總結》及《Python入門與進階經典教程》

希望本文所述對大家Python程式設計有所幫助。