全國哪個餐飲品牌的網(wǎng)站做的好處百度關(guān)鍵詞屏蔽
文章目錄
- 前情知識補充
- hasattr 函數(shù)
- setattr函數(shù)
- getattr函數(shù)
- join 函數(shù)
- 元類技術(shù)
- 使用type創(chuàng)建類
- 什么是元類(概念總結(jié))
- \_\_metaclass\_\_屬性
- 使用metaclass 的函數(shù)方式進行創(chuàng)建類
- 使用metaclass 的類方式進行創(chuàng)建類
- 自定義元類
- 元類實現(xiàn)ORM
- 接口類與抽象類
- 抽象類
- 接口類
- 注意點
前情知識補充
hasattr 函數(shù)
class ObjectCreator(object):passmy_object = ObjectCreator()# hasattr用來判斷一個對象是否有某個屬性,有就是True,沒有就是false
print(hasattr(ObjectCreator, 'new_attribute'))ObjectCreator.new_attribute = 'foo' # 你可以為類增加屬性print(hasattr(ObjectCreator, 'new_attribute'))
輸出:
setattr函數(shù)
這個函數(shù)是用來給對象賦屬性以及對應(yīng)的值的
使用的方式:
setattr(object 對象, name 字符串 對象屬性, value 屬性的值)
>>>class A(object):
... bar = 1
...
>>> a = A()
>>> getattr(a, 'bar') # 獲取屬性 bar 值
1
>>> setattr(a, 'bar', 5) # 設(shè)置屬性 bar 值
>>> a.bar
5
getattr函數(shù)
參考鏈接
基本使用方式
getattr(object 對象, name 對象屬性, default 如果不存在則返回的值)
一般用于由用戶或者程序自動決定想要訪問的屬性名時,采用這種方法,并且省去try的異常檢測,直接自定義返回值。
樣例:
from typing import NamedTupleclass Person(NamedTuple):'''人類'''name: strage: intjob: strweight: floatheight: floatalex = Person('Alex', 32, 'actor', 60, 178)# 把用戶輸入的字符串賦值給變量attribute_name
attribute_name = input('''What do you want to know about Alex?
Enter an attribute name>>>''')
# 注意,上述字符串被傳進了這個函數(shù)作為第二個參數(shù)
# 第三個參數(shù)是屬性不存在時返回的字符串
print(getattr(alex,attribute_name, 'Sorry, this attribute does not exist.'))
join 函數(shù)
參考鏈接鏈接
這邊只介紹元組:
tuple1 = ('a','b','c') #定義元組tuple1
'、'.join(tuple1)
輸出: a、b、ctuple2 = ('hello','peace','world') #定義元組tuple2
' '.join(tuple2)
輸出:hello peace world
元類技術(shù)
先介紹方法,再去介紹相關(guān)的概念,感覺比較好理解
使用type創(chuàng)建類
先是關(guān)于type的基礎(chǔ)介紹:
創(chuàng)建出來的類名稱 = type("創(chuàng)建出來的類名稱", (元組內(nèi)部放想要繼承的類,), {"print_b": print_b, 字典放類函數(shù)})
樣例見下:
class A(object):num = 100def print_b(self):print(self.num)@staticmethod
def print_static():print("----haha-----")@classmethod
def print_class(cls):print(cls.num)B = type("B", (A,), {"print_b": print_b, "print_static": print_static,"print_class": print_class})
b = B()
b.print_b()
b.print_static()
b.print_class()
什么是元類(概念總結(jié))
這是因為函數(shù) type 實際上是一個元類。type 就是 Python 在背后用來創(chuàng)建所有類的元類。跟int 一樣之所以type全是小寫,就是根據(jù)于此,int是用來創(chuàng)建整形的變量,type就是用來創(chuàng)建類的類。
__metaclass__屬性
python在創(chuàng)建類的時候會經(jīng)過下面的步驟:
- 類 中有__metaclass__這個屬性嗎?如果是,Python 會通過__metaclass__創(chuàng)建
- 如果 Python 沒有找到__metaclass__,它會繼續(xù)在 父類中尋找
__metaclass__屬性,并嘗試做和前面同樣的操作。 - 如果 Python 在任何父類中都找不到__metaclass__,它就會在模塊層次中去尋找__metaclass__,并嘗試做同樣的操作。
- 如果還是找不到__metaclass__,Python 就會用內(nèi)置的 type 來創(chuàng)建這個類對象
使用metaclass 的函數(shù)方式進行創(chuàng)建類
def upper_class(class_name, class_parent, class_function: dict):"""這邊實現(xiàn)的就是將類元素全部變成大寫的"""new_dict = dict()for key, function in class_function.items():if not key.startswith('__'):new_dict[key.upper()] = functionreturn type(class_name, class_parent, new_dict)class Test(object, metaclass=upper_class):a = 1print(Test.a)
print(Test.A)
輸出的結(jié)果:
使用metaclass 的類方式進行創(chuàng)建類
class UpperAttrMetaClass(type):# __new__ 是在__init__之前被調(diào)用的特殊方法# __new__是用來創(chuàng)建對象并返回之的方法# 而__init__只是用來將傳入的參數(shù)初始化給對象# 你很少用到__new__,除非你希望能夠控制對象的創(chuàng)建# 這里,創(chuàng)建的對象是類,我們希望能夠自定義它,所以我們這里改寫__new__# 如果你希望的話,你也可以在__init__中做些事情# 還有一些高級的用法會涉及到改寫__call__特殊方法,但是我們這里不用def __new__(cls, class_name, class_parents, class_attr):# 遍歷屬性字典,把不是__開頭的屬性名字變?yōu)榇髮?/span>new_attr = {}for name, value in class_attr.items():if not name.startswith("__"):new_attr[name.upper()] = value# 值得關(guān)注的是需要用這種形式type.__new__而不是使用 type()return type.__new__(cls, class_name, class_parents, new_attr)# python3的用法
class Foo(object, metaclass=UpperAttrMetaClass):bar = 'bip'print(Foo.BAR)
使用type.__new__而不使用type的原因:鏈接
自定義元類
正常人不需要,只有在想要看懂框架,特別是深度學習的時候需要搞懂這門技術(shù),自己也不需要這么寫OxO
“元類就是深度的魔法,99%的用戶應(yīng)該根本不必為此操心。如果你想搞清楚究竟是否需要用到元類,那么你就不需要它。那些實際用到元類的人都非常清楚地知道他們需要做什么,而且根本不需要解釋為什么要用元類。” —— Python 界的領(lǐng)袖 Tim Peter”
元類實現(xiàn)ORM
class ModelMetaclass(type):def __new__(cls, name, bases, attrs):mappings = dict()# 判斷是否需要保存for k, v in attrs.items():# 判斷是否是指定的StringField或者IntegerField的實例對象if isinstance(v, tuple):print('Found mapping: %s ==> %s' % (k, v))mappings[k] = v# 刪除這些已經(jīng)在字典中存儲的屬性for k in mappings.keys():attrs.pop(k)# if name == 'User':# attrs.pop('hello')# 將之前的uid/name/email/password以及對應(yīng)的對象引用、類名字attrs['__mappings__'] = mappings # 保存屬性和列的映射關(guān)系attrs['__table__'] = name # 假設(shè)表名和類名一致return super().__new__(cls, name, bases, attrs)class Model(object, metaclass=ModelMetaclass):def __init__(self, **kwargs):for name, value in kwargs.items():setattr(self, name, value)def save(self):fields = []args = []for k, v in self.__mappings__.items():fields.append(v[0])args.append(getattr(self, k, None))args_temp = list()for temp in args:# 判斷入如果是數(shù)字類型if isinstance(temp, int):args_temp.append(str(temp))elif isinstance(temp, str):args_temp.append("""'%s'""" % temp)sql = 'insert into %s (%s) values (%s)' % (self.__table__, ','.join(fields), ','.join(args_temp))print('SQL: %s' % sql)class User(Model):uid = ('uid', "int unsigned")name = ('username', "varchar(30)")email = ('email', "varchar(30)")password = ('password', "varchar(30)")u = User(uid=12345, name='Michael', email='test@orm.org', password='my-pwd')
print(u.__dict__)
u.save()
建議一步一步調(diào)試看看函數(shù)的執(zhí)行流程。
接口類與抽象類
抽象類的定義就是:作為微信支付寶的父類,定義了一個具有支付功能的設(shè)計類,但是又沒有具體實現(xiàn),需要子類去實現(xiàn)具體的功能的一種類。
接口類的定義就是:一個接口就是一個類,在這個類當中,我們盡量希望有少 或者 僅有一個方法,也即方法即類,在后面使用的時候,我們使用一個子類去繼承一個個接口類,并且都將其實例化到各個類代碼當中。
二者使用的場景不同:抽象類希望的是本身具有越多的屬性越好,然后子類繼承,實例化即可,而接口類希望的是本身方法越少越好,最好自己就是一個行為。
抽象類
同樣也需要用到元類技術(shù)metaclass,以及需要額外導(dǎo)入一個包:
“from abc import abstractmethod, ABCMeta” 使用內(nèi)部的裝飾器@abstractmethod即可創(chuàng)建出一個抽象屬性(意思就是子類需要將其定義其功能,而自己只需要寫個名字)
from abc import abstractmethod, ABCMeta# 使用了抽象方法的類,就是抽象類,Payment就是一個抽象類
class Payment(metaclass=ABCMeta):@abstractmethoddef pay(self, money):passclass Alipay(Payment):def pay(self, money): # 這里類的方法不是一致的pay,導(dǎo)致后面調(diào)用的時候找不到payprint('支付寶支付了')# 如果子類中沒有實現(xiàn)抽象方法,實例化對象時,就會報錯
p = Alipay()
接口類
from abc import abstractmethod, ABCMetaclass WalkAnimal(metaclass=ABCMeta):@abstractmethoddef walk(self):passclass SwimAnimal(metaclass=ABCMeta):@abstractmethoddef swim(self):passclass FlyAnimal(metaclass=ABCMeta):@abstractmethoddef fly(self):pass# 如果正常一個老虎有跑和跑的方法的話,我們會這么做
class Tiger(WalkAnimal, SwimAnimal):def walk(self): passdef swim(self): passt = Tiger()
如上,就不進行解釋了。
注意點
注意點:
- 抽象類是一個介于類和接口之間的一個概念,同時具備類和接口的部分特性,可以用來實現(xiàn)歸一化設(shè)計。
- 在繼承抽象類的過程中,我們應(yīng)該盡量避免多繼承;
- 而在繼承接口的時候,我們反而鼓勵你來多繼承接口, 一般情況下 單繼承 能實現(xiàn)的功能都是一樣的,所以在父類中可以有一些簡單的基礎(chǔ)實現(xiàn),多繼承的情況 由于功能比較復(fù)雜,所以不容易抽象出相同的功能的具體實現(xiàn)寫在父類中。