寫這篇博文時十分忐忑~ 且談一下我的認識,有錯的歡迎留言指正,
明確幾點
Python中一切皆物件
所有的類 都繼承自 object,也就是說 object 是所有類的基類(超類)
type 也繼承自 object 原始碼中type 的定義:class type(object):
type 是 objcet 的型別 同時 object 是 type 的超類
明確繼承具有傳遞性, 雞 繼承了 家禽 , 家禽 又繼承了 禽類 ,因此雞也屬于禽類,就是這樣的關系,
類和實體關系,類也是物件,在兩個物件中,一個是另一個的實體,例如雞是一個類 叫小紅的雞是雞的實體,
在Python3中,類和型別已經是一種東西了,
在Python3 中只有類和非類兩種物件,型別是"<class 'type'>" 那么它是類否則它是非類,聽起來很繞,英文原文:There are only two kinds of objects in Python: to be unambiguous let's call these types and non-types. Non-types could be called instances, but that term could also refer to a type, since a type is always an instance of another type. Types could also be called classes, and I do call them classes from time to time.
class Chicken(object): # 雞類 他不僅僅是類 也是一個物件,它是 type 的物件
pass
xiaohong = Chicken() # 它是雞類 這個類的物件
Python一切皆物件
1 在Python中 我們常說的 類 也是 物件 ,而它們的類是 元類 : type 簡單點易于理解稱為 類的類
2 內建的類(型別),object、list、tuple、dict,
3 自定義的類 MyClass 等等任何你喜歡的名字,
4 由 自定義的類 和 內建的類 實體化的物件就是我們常說的 物件 了,也叫物件的實體,
兩種關系
在面向物件的世界里有兩種關系,這與語言本身沒有關系,只要是面向物件的語言都擁有這樣的兩種屬性,型別實體關系和繼承關系,
型別實體關系
即該類由誰創建
str('abc') 類 str 創建了實體 abc,
class Person(object):
""" A simple Person class. """
monkey = Person()
# monkey 和 Person 就是 型別和實體的關系 type(monkey) --> <class '__main__.Person'>
繼承關系
即類繼承自誰
class MyList(list):
""" A custom list class , it's a subclass of `list`. """
# MyList 就是 list 的子類, 它和list 就是 繼承關系
type 和 object的關系
# 這是Python 原始碼中對type 的定義
class type(object):
"""
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
"""
...
# 由此 可見 type 是 object 的子類 也就是 繼承關系 <1> type 繼承自 object
>>> type(object)
<class 'type'>
>>> type(type)
<class 'type'>
# 上面兩行代碼的輸出很清晰 type 和 object 以及 type 與 type 存在 型別實體關系
# <2> type 是 object 的型別
# <3> type 是 type 的型別
一個類/物件的誕生程序
類和物件的創建十分相似,類 本身也是物件~,他們由元類創建,
創建類的方法
class 關鍵字
關于這種方式無需贅述,如果下面的代碼看不懂,那也沒必要繼續向下閱讀了,
class MyClass(object):
"""This is a simple class for display how to create a class. """
name = 'NewClass'
def func(self):
print('Hello class, my name is %s' % self.name)
new_obj = MyClass()
print(new_obj.func)
# <bound method MyClass.func of <__main__.MyClass object at 0x103b3b2e8>>
# Hello class, my name is NewClass
type函式
type 這個函式有點傻屌,它依據引數的不同擁有兩種完全不同的行為,在程式設計中是很另類的,似乎也不符合Python的設計哲學,按照Python的 Style 他應該是兩個函式才對,但是這是為了更好的向后兼容,
type 接受三個引數 第一個引數為類的名字, 第二個引數為繼承串列, 第三個引數為屬性字典(屬性和方法)
def func(self):
""" A simple function to bound NewClass. """
print('Hello type, my name is %s' % self.name)
TypeClass = type('TypeClass', (object,), {'name': 'NewClass', 'func': func})
type_obj = TypeClass()
print(type_obj.func)
type_obj.func()
# <bound method func of <__main__.NewClass object at 0x100d2f128>>
# Hello type, my name is TypeClass
看看創建的細節
到這里我認為你已經對元類 type 有了一定的了解:
type就是Python在背后用來創建所有類的元類,包括字典 元組 字串 類 甚至函式等等 都是由type創建,甚至你查看object 的型別也會告訴你他是 type 但是 type又繼承自object 原始碼中寫的很清晰,實質上他們都由虛擬機創建,同時object的type屬性是其子類type而type又繼承object 不要問先有雞還是先有蛋~ 你可以抽相處一個型別物件的概念,這個東西 型別是type 父類是object 當然僅僅是概念,不要在這里糾結~ 好吧~ !
類的創建會呼叫兩個方法, __new__ 和 __init__,__new__ 用來從類實體化 物件 __init__ 負責實體化這個物件,
舉個不恰當的例子,__new__ 方法就相當于 生孩子,__init__ 方法就相當于給這個孩子起名,上戶口這樣子,沒有 __new__ 就沒法__new__ 因此 __new__ 方法一定在 __init__ 之前 而__init__ 需要 __new__ 方法的結果 就是被實體化的物件(就生的那個孩子 沒孩子 一切白搭) !
__call__ 是個神奇的方法, 它允許用戶像使用函式那樣使用類或物件,也就是使用() 就回來呼叫__all__,
_call_
物件通過提供 __call(slef, *args ,**kwargs)__方法可以模擬函式的行為,即允許以類/物件() 的形式來呼叫,
元類的__call__方法在繼承的類進行實體化時呼叫(此時實體化出的是個類,而不是物件)
_new_
將自身實體化時,也就是創建物件時呼叫的方法,該方法是一個靜態方法,第一個引數為類本身,回傳值為為該物件分配的空間,也就是被創建的這個物件,__new__方法至少需要一個cls 引數,表示的是將要被實體化的類本身,需要注意的是該方法必須回傳一個空間,也就是回傳實體化后的物件 return super().\__new__() 或者 object.__new__()
_init_
拿到__new__方法回傳的物件,對這個新創建出來的物件進行一些初始化操作,
優雅的控制類和物件
使用上述的一些方法我們可以優雅的控制類的創建和使用,例如 我們可以自定義元類來設計優雅的API, 雖然元類的設計麻煩,但是使用其創建的類 使用起來將會非常舒服~ 例如Django 中的model的使用~ 真香~!
改寫類來控制創建的物件
實作一個配置類,該類需要保證全域只有一個實體,并且需要保證同一時間 配置是一致的,也就是需要保證執行緒安全,下面是代碼,通過控制 __new__ 方法來實作單例,
import threading
def synchronized(bar):
""" threading lock for Config"""
bar.__lock__ = threading.Lock() # get lock
def lock_func(*args, **kwargs):
with bar.__lock__:
return bar(*args, **kwargs)
return lock_func
class Config(object):
""" Singleton `Config` ."""
_instance = None
@synchronized
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
改寫元類來控制創建的類
元類所創建的類會擁有元類擁有的方法,
通常的自定義的元類會重寫 __new__ 、__call__ 、 __init__,此時他們的第一個引數不再是物件,而是將要創建的類,__new__ 回傳的也將是類, 而 __init__ 是添加類屬性而不是實體屬性,
假設上一步的操作中需要將配置類中所有的屬性都變為大寫的,以 _ 開頭的屬性除外,要怎么做呢?
將函式作為元類
假設上一步的操作中需要將配置類中所有的屬性都變為大寫的,以 _ 開頭的屬性除外,要怎么做呢?
import threading
def synchronized(bar):
""" threading lock for Config"""
bar.__lock__ = threading.Lock() # get lock
def lock_func(*args, **kwargs):
with bar.__lock__:
return bar(*args, **kwargs)
return lock_func
def filter_config(cls_name, cls_mro, cls_attr):
cls_attr = {k.upper(): v for k, v in cls_attr.items() if not k.startswith('_')}
return type(cls_name, cls_mro, cls_attr) # 回傳一個類
class Config(metaclass=filter_config): # 指定元類
""" Singleton `Config` ."""
_instance = None
@synchronized
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
number = 100
config = Config()
print(config.NUMBER) # 100
將類作為元類
import threading
def synchronized(bar):
""" threading lock for Config"""
bar.__lock__ = threading.Lock() # get lock
def lock_func(*args, **kwargs):
with bar.__lock__:
return bar(*args, **kwargs)
return lock_func
class Filter_config(type):
def __new__(cls, cls_name, cls_mro, cls_attr):
cls_attr = {k.upper(): v for k, v in cls_attr.items() if not k.startswith('_')}
return super(Filter_config, cls).__new__(cls, cls_name, cls_mro, cls_attr)
class Config(metaclass=Filter_config): # 指定元類
""" Singleton `Config` ."""
_instance = None
@synchronized
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = object.__new__(cls, *args, **kwargs)
return cls._instance
number = 100
config = Config()
print(config.NUMBER) # 100
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/119156.html
標籤:Python
上一篇:關于動態創建控制元件的幾個問題
下一篇:單例模式
