1. 程式人生 > 實用技巧 >純css高斯背景模糊(毛玻璃,偽元素)

純css高斯背景模糊(毛玻璃,偽元素)

目錄

一:繼承介紹

1:什麼是繼承?

繼承就是建立了一個新的類,在Python中,新建立的類可以繼承一個或者多個父類(現實社會有點難)新建的類就是子類,圍著派生類,父類稱之為基類或者超類(累)

2:為什麼要有繼承?

繼承可以減少程式碼冗餘

3:如何使用繼承?
class P1:
	pass

class P2:
    pass

class sub1(P1): # 繼承了P1類
    pass

class sub2(P1,P2): # 繼承了P1,P2類
    pass

通過類內的__bases__可以檢視類繼承的所有的父類

print(sub1.__bases__) # (<class '__main__.P1'>,)
print(sub2.__bases__) # (<class '__main__.P1'>, <class '__main__.P2'>)

示列一(繼承)
class School:
    scholl = '東京校區'
    
class Student(School):
    
    def __init__(self,name,age,gender,suid,course):
        self.name = name
        self.age = age
        self.gender = gender
        self.suid = suid
        self.course = course
    
    def choose(self):
        print(f"{self.name}正在選課")
    
     
class Teacher(School):
    
    def __init__(self,name,age,gender,salary,level):
        self.name = name
        self.age = age
        self.gender = gender
        self.salary = salary
        self.level = level
        
    def score(self,student,num):
        student.num = num
        
s1 = Student('alen',66,'male',10001,'python開發')
t1 = Teacher('eg',18,'male',2000,10)

print(t1.scholl)    # 東京校區
print(s1.__dict__)  # {'name': 'alen', 'age': 66, 'gender': 'male', 'suid': 10001, 'course': 'python開發'}
print(t1.__dict__)  # {'name': 'eg', 'age': 18, 'gender': 'male', 'salary': 2000, 'level': 10}

二:如何在子類中派生新方法重用父類的功能

方式一:指名道姓地呼叫某一個類的函式

特點:可以不以依賴繼承關係

示列

class School:
    scholl = '東京校區'
    
    def __init__(self,name,age,gender):
        self.name = name
        self.age = age
        self.gender = gender
    
    
    def t1(self):
        print("這是一個測試繼承的函式")
    
class Student(School):
    
    def __init__(self,name,age,gender,suid,course):
        School.__init__(self,name,age,gender)
        self.suid = suid
        self.course = course
    
    def choose(self):
        print(f"{self.name}正在選課")
    
     
class Teacher(School):
    
    def __init__(self,name,age,gender,salary,level):
     	School.__init__(self,name,age,gender)
        self.salary = salary
        self.level = level
        
    def score(self,student,num):
        School.t1(self)
        student.num = num
        
s1 = Student('alen',66,'male',10001,'python開發')
t1 = Teacher('eg',18,'male',2000,10)
print(s1.__dict__)   # {'name': 'alen', 'age': 66, 'gender': 'male', 'suid': 10001, 'course': 'python開發'}
print(t1.__dict__)  # {'name': 'eg', 'age': 18, 'gender': 'male', 'salary': 2000, 'level': 10}

三:屬性查詢

在python中如果物件內部沒有屬性,就去類裡去找,如果類裡沒有就去父類找(如果沒有有繼承,就找不到報錯)

在python3中會去object裡去找,(如果沒有預設繼承,預設就是繼承object類),在python2中,存在兩種類(新式類和經典類),兩種類的查詢循序有點區別

示列

class  Foo:
    
    def f2(self):
        print("from foo.f2")
    
    def f1(self):
        print("from foo.f1")
        self.f2()
        
class Bar(Foo):
    def f2(self):
        print("from Bar.f2")

t = Bar()
t.f1() 
"""
from foo.f1
from Bar.f2
"""

父類如果不想讓子類覆蓋自己的方法,可以在方法名前加__,讓其成為私有屬性

class  Foo:
    
    def __f2(self):
        print("from foo.f2")
    
    def f1(self):
        print("from foo.f1")
        self.__f2()
        
class Bar(Foo):
    def __f2(self):
        print("from Bar.f2")

obj = Bar()
obj.f1()
​```
from foo.f1
from foo.f2
​```

四:繼承的原理

基礎知識

新式類:凡是繼承了object的子類,以該子類子子孫孫類都稱之為新式類

經典類:沒有繼承object的子類,以該子類子子孫孫類都稱之為經典類

在python3中全都是新式類,python2中有經典類

在python3中沒有繼承任何類,預設基礎obj類

在py3中
class Foo:
	pass

print(Foo.__bases__) # (<class 'object'>,)
在py2中
class Foo:
	pass
print(Foo.__bases__) # 為空

繼承的實現原理

1:菱形問題

大多數面嚮物件語言都不支援多繼承,在python中,一個子類是可以同時繼承多個父類的,這個可以讓一個子類,可以對多個不同父類加以重用的好處,但是也有可能引發著名的菱形問題(或稱死亡鑽石問題)

如圖

A類在頂部,B類和C類分別位於其下方,D類在底部將兩者連線在一起形成菱形。

這個圖展示的就是菱形繼承

如果A中有一個方法,B或者C都重寫了該方法,而D沒有重寫,那麼D繼承的是哪個版本的方法:是B或者是C?看下面

在py3中
class A:
    def test(self):
        print('from A')
    
class B(A):
    def test(self):
	print('from B')
    
class C(A):
    def test(self):
	print('from C')

class D(B,C):
    pass
                                    
obj = D
obj.test()  # 結果為from B

要想知道obj.test()是如何找到方法test的,需要了解Python的繼承實現原理--

2繼承原理

MRO

Python是如何實現繼承的呢?

對於你定義的每一個類,python都會計算出方法解析順(mro)列表,該mro列表就是一個簡單的所有基類的線性順序列表,如下

print(D.mro())
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

python會在mro列表上從左到右開始查詢基類,直到找到一個第一匹配這個屬性的類為止

這個mro列表的構造是通過一個C3線性演算法來實現的。

這個演算法實際上就是合併所有父類的mro列表並遵循如下原則

1:子類會先於父類查詢
2:多個父類會根據它們所在列表中的順序被檢查
3:如果對下一個類存在兩個合法的選擇,選擇第一個父類

屬性查詢

1:由物件發起的屬性查詢,會從物件自身的屬性裡檢索,沒有則會按照物件的類的mro列表規定的順序依次找下去
2:由類發起的屬性查詢,會按照當前類.mro規定的順序依次找下去

示列

#【test1】

class A(object):
    def test(self):
        print('from A')

class B(A):
    def test(self):
        print('from B')


class C(A):
    def test(self):
        print('from C')

class D(C,B):
    def test(self):
        print('from D')

print(D.mro())  # 類D以及類D的物件訪問屬性都是參照該類的mro列表
# 輸出結果:
# [<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
obj1 = D()
obj1.test()   # 輸出結果:from D
print(D.test)  # 輸出結果:<function D.test at 0x0000012EA27FA4C0>


print(C.mro()) # 類C以及類C的物件訪問屬性都是參照該類的mro列表
# 輸出結果:[<class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
obj2 = C()
obj2.test()  # 輸出結果:from C
print(C.test) # 輸出結果: <function C.test at 0x0000022FA7D0A3A0>

# 【test2】
class A(object):
    # def test(self):
    #     print('from A')
    pass

class B(A):
    def test(self):
        print('from B')

class C(A):
    # def test(self):
    #     print('from C')
    pass
class D(C,B):
    # def test(self):
    #     print('from D')
    pass

print(D.mro())  # 類D以及類D的物件訪問屬性都是參照該類的mro列表
# 輸出結果:
# [<class '__main__.D'>, <class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
obj1 = D()
obj1.test()   # 輸出結果:from B
print(D.test)  # 輸出結果:<function B.test at 0x00000246D6F3A310>

# 總結:類相關的屬性查詢(類名.屬性,該類的物件.屬性),都是參照該類的mro

3:深度優先和廣度優先

1:非菱形繼承

如果多繼承是非菱形繼承,經典類與新式類的屬性查詢順序一樣:都是一個分支一個分支地找下去,然後找object類

示列如下

程式碼演示

class E:
    # def test(self):
    #     print('from E')
    pass

class F:
    def test(self):
        print('from F')


class B(E):
    # def test(self):
    #     print('from B')
    pass

class C(F):
    # def test(self):
    #     print('from C')
    pass

class D:
    def test(self):
        print('from D')


class A(B, C, D):
    # def test(self):
    #     print('from A')
    pass

# 新式類
print(A.mro())  
# A->B->E->C->F->D->object 
# [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, 
# <class '__main__.C'>, <class '__main__.F'>, <class '__main__.D'>, <class 'object'>]

obj = A()
obj.test()  # 結果為:from F

2:菱形繼承

如果多繼承是菱形繼承,經典類與新式類的屬性查詢順序不一樣

經典類:深度優先,會在在檢索第一個分支的時候就直接一天道走到黑,即會檢索(共同的父類)

新式類:廣度優先,會在檢索最後一條分支的時候檢索共同的父類

class A(object):
    def test(self):
        print('from A')


class B(A):
    def test(self):
        print('from B')


class C(A):
    def test(self):
        print('from C')


class D(B,C):
    pass


obj = D()
obj.test() # 結果為:from B
# 如果B沒有去找C,c沒有然後找A
python到底是如何實現繼承的呢? 對於你定義的每一個類,Python都會計算出一個方法解析順序(MRO)列表,該MRO列表就是一個簡單的所有基類的線性順序列表,如下
print(d.mro) # [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
class G:   # 在python2中,未繼承object的類及其子類,都是經典類
    # def test(self):
    #     print('from G')
    pass

class E(G):
    # def test(self):
    #     print('from E')
    pass

class F(G):
    def test(self):
        print('from F')

class B(E):
    # def test(self):
    #     print('from B')
    pass

class C(F):
    def test(self):
        print('from C')

class D(G):
    def test(self):
        print('from D')

class A(B,C,D):
    # def test(self):
    #     print('from A')
    pass

# # 新式類
print(A.mro())
# # A->B->E->C->F->D->G->object
# # [<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.F'>,
# # <class '__main__.D'>, <class '__main__.G'>, <class 'object'>]
obj = A()
obj.test()  # 輸出結果:from C


# 經典類:A->B->E->G->C->F->D
print(A.mro())
obj = A()
obj.test()  # 輸出結果:from C

3:總結

多繼承到底要不要用?
python既然提供了,那麼就要用,但是要規避問題
1:繼承結構儘量不要過於複雜
2:推薦使用mixins機制:在多繼承的背景下滿足繼承是什麼關係

五:python Mixins機制

用來解決多繼承所帶來的問題的,將原本的混亂的繼承清晰的變成’is-a‘的關係

# 民航飛機、直升飛機、汽車都是交通工具,但是飛機會飛,汽車不會,
# 這個時候我們將飛這個功能放到交通工具中就顯得不合適
class Vehicle:  # 交通工具
    def fly(self):
        '''
        飛行功能相應的程式碼        
        '''
        print("I am flying")


class CivilAircraft(Vehicle):  # 民航飛機
    pass


class Helicopter(Vehicle):  # 直升飛機
    pass


class Car(Vehicle):  # 汽車並不會飛,但按照上述繼承關係,汽車也能飛了
    pass

# 針對上面的問題,就引入Mixin機制
# Mixin機制指的就是子類混合不同類的功能,然後將其用統一的命名規範來標識該類只是用來混合功能的
# 從而來遵守多繼承下的“is-a”關係,Mixin機制本質仍是多繼承
class Vehicle:  # 交通工具
	pass

class FlyMixin:
    def fly(self):
        '''
        飛行功能相應的程式碼        
        '''
        print("I am flying")


class CivilAircraft(FlyMixin,Vehicle):  # 民航飛機
    pass


class Helicopter(FlyMixin,Vehicle):  # 直升飛機
    pass


class Car(Vehicle):  # 汽車並不會飛,但按照上述繼承關係,汽車也能飛了
    pass

'''
使用Mixin類實現多重繼承要非常小心
1、它必須表示某一種功能,而非物品,python 對於mixin類的命名方式一般以 Mixin, able, ible 為字尾
2、它必須責任單一,如果有多個功能,那就寫多個Mixin類,一個類可以繼承多個Mixin,為了保證遵循繼承
   的“is-a”原則,只能繼承一個標識其歸屬含義的父類
3、然後,它不依賴於子類的實現
4、最後,子類即便沒有繼承這個Mixin類,也照樣可以工作,就是缺少了某個功能。
  (比如飛機照樣可以載客,就是不能飛了)
'''

六:派生與方法重用

  • 子類中衍生出的新東西

    1. 子類獨有,父類沒有
    2. 子類有,父類也有,子類是完全覆蓋父類
    3. 子類有,父類也有,子類在父類的基礎上進行擴充套件
    
    

class People:
... school='清華大學'
...
... def init(self,name,sex,age):
... self.name=name
... self.sex=sex
... self.age=age
...

class Teacher(People):
... def init(self,name,sex,age,title): # 派生
... self.name=name
... self.sex=sex
... self.age=age
... self.title=title
... def teach(self):
... print('%s is teaching' %self.name)

```
  • 想在子類派生出的方法內重用父類的功能,有兩種實現方式

    # 方法一:“指名道姓”地呼叫某一個類的函式=》不依賴於繼承
    >>> class Teacher(People):
    ...     def __init__(self,name,sex,age,title):
    ...         People.__init__(self,name,age,sex) #呼叫的是函式,因而需要傳入self
    ...         self.title=title
    ...     def teach(self):
    ...         print('%s is teaching' %self.name)
    
    # 方法二:super()呼叫父類提供給自己的方法=》嚴格依賴繼承關係
    # 呼叫super()會得到一個特殊的物件,該物件會按照發起屬性查詢的類的mro去當前類的父類中找屬性
    >>> class Teacher(People):
    ...     def __init__(self,name,sex,age,title):
    ...         super().__init__(name,age,sex) #呼叫的是繫結方法,自動傳入self
    ...         self.title=title
    ...     def teach(self):
    ...         print('%s is teaching' %self.name)
    
    
    >>> #A沒有繼承B
    ... class A:
    ...     def test(self):
    ...         super().test()
    ... 
    >>> class B:
    ...     def test(self):
    ...         print('from B')
    ... 
    >>> class C(A,B):
    ...     pass
    ... 
    >>> C.mro() # 在程式碼層面A並不是B的子類,但從MRO列表來看,屬性查詢時,就是按照順序C->A->B->object,B就相當於A的“父類”
    [<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>,<class ‘object'>]
    >>> obj=C()
    >>> obj.test() # 屬性查詢的發起者是類C的物件obj,所以中途發生的屬性查詢都是參照C.mro()
    from B
    

    六:組合

    什麼是組合?

    • 一個類中以另外一個類的物件作為資料屬性,作為類的組合
    # 組合與繼承都是用來解決程式碼的重用性問題。
    # 二者的區別在於
    '''
    繼承:強調‘是’的關係,例如老師是人、學生是人,當類之間有很多相同的之處,應該使用繼承
    組合:強調‘有’的關係,例如老師有多門課程,老師有給學生打分,當類之間有顯著不同,並且較小的類是較大的類所需
    要的元件時,應該使用組合
    '''
    class Course:
        def __init__(self,name,period,price):
            self.name=name
            self.period=period
            self.price=price
        def tell_info(self):
            print('<%s %s %s>' %(self.name,self.period,self.price))
    
    class Date:
        def __init__(self,year,mon,day):
            self.year=year
            self.mon=mon
            self.day=day
        def tell_birth(self):
           print('<%s-%s-%s>' %(self.year,self.mon,self.day))
    
    class People:
        school='清華大學'
        def __init__(self,name,sex,age):
            self.name=name
            self.sex=sex
            self.age=age
    
    #Teacher類基於繼承來重用People的程式碼,基於組合來重用Date類和Course類的程式碼
    class Teacher(People): #老師是人
        def __init__(self,name,sex,age,title,year,mon,day):
            super().__init__(name,age,sex)
            self.birth=Date(year,mon,day) #老師有生日
            self.courses=[] #老師有課程,可以在例項化後,往該列表中新增Course類的物件
        def teach(self):
            print('%s is teaching' %self.name)
    
    
    python=Course('python','3mons',3000.0)
    linux=Course('linux','5mons',5000.0)
    teacher1=Teacher('lili','female',28,'博士生導師',1990,3,23)
    
    # teacher1有兩門課程
    teacher1.courses.append(python)
    teacher1.courses.append(linux)
    
    # 重用Date類的功能
    teacher1.birth.tell_birth()
    
    # 重用Course類的功能
    for obj in teacher1.courses: 
        obj.tell_info()
    

參考

https://zhuanlan.zhihu.com/p/109331525

https://www.cnblogs.com/linhaifeng/articles/7340153.html