面向對象

面向過程 VS 面向對象 

面向過程的程序設計的核心是過程(流水線式思惟),過程即解決問題的步驟,面向過程的設計就比如精心設計好一條流水線,考慮周全何時處理什麼東西。java

優勢是:極大的下降了寫程序的複雜度,只須要順着要執行的步驟,堆疊代碼便可。python

缺點是:一套流水線或者流程就是用來解決一個問題,代碼牽一髮而動全身。linux

面向對象初識

面向對象編程:是一類類似功能函數的集合,使你的代碼更清晰化,更合理化。算法

面向對象,要擁有上帝的視角看問題,類其實就是一個公共模板,對象就從具體的模板實例化出來。編程

 

初識類和對象

 python中一切皆爲對象,類型的本質就是類微信

在python中,用變量表示特徵,用函數表示技能,於是具備相同特徵和技能的一類事物就是‘類’,對象是則是這一類事物中具體的一個。app

初識類

def functionName(args):
     '函數文檔字符串'
      函數體 
函數

 類ide

'''
class 類名:
    '類的文檔字符串'
    類體
'''

#建立一個類
class Data:
    pass

class Person:   #定義一我的類
    role = 'person'  #人的角色屬性都是人
    def walk(self):  #人均可以走路,也就是有一個走路方法,也叫動態屬性
        print("person is walking...")

 查看一個類函數

class Dog:
    name = '小黑'
    kind = '哈士奇'
# 查看類當中的變量,方法一
print(Dog.__dict__)          #{'__module__': '__main__', 'name': '小黑', 'kind': '哈士奇', '__dict__': <attribute '__dict__' of 'Dog' objects>, '__weakref__': <attribute '__weakref__' of 'Dog' objects>, '__doc__': None}
print(Dog.__dict__['name'])  #小黑
print(Dog.__dict__['kind'])  #哈士奇
#方法二
class Dog:
    name = '小黑'
    kind = '哈士奇'
print(Dog.name)  #小黑
print(Dog.kind)  #哈士奇

 

 以人狗大戰爲例 來講明類的相關:微信支付

class Dog:
    hp = 300   #靜態變量
    def __init__(self,name,hp,ad,kind):  # 初始化方法  設置狗的參數:名字,血量,攻擊,種類
        self.name = name   # 實例變量   對象屬性
        self.hp = hp
        self.ad = ad
        self.type = kind

    def bite(self, person):     # 動態變量 定義 狗咬人 的方法
        person.hp -= self.ad    # 人的血量減去狗的攻擊就是人新的血量
        print('%s咬了%s,%s掉了%s點血' % (self.name, person.name, person.name, self.ad))

class Person:
    def __init__(self,name,hp,ad,sex):  # 初始化方法    設置人的參數:名字,血量,攻擊,性別
        self.name = name        # 實例變量   對象屬性
        self.hp = hp
        self.ad = ad
        self.sex = sex

    def fight(self,dog):  # 動態變量  方法   人打狗
        # 狗掉血,就是人的攻擊力
        dog.hp -= self.ad
        print('%s攻擊了%s,%s掉了%s點血'%(self.name,dog.name,dog.name,self.ad))

hei = Dog('小黑',300,20,'哈士奇')   # 小黑 對象 實例
alex = Person('alex',100,10,'male')  # alex 對象 實例

print(hei.hp)    # 300
print(alex.hp)   # 100

hei.bite(alex)   # 小黑咬了alex,alex掉了20點血
alex.fight(hei)  # alex攻擊了小黑,小黑掉了10點血

print(hei.hp)    # 290
print(alex.hp)   # 80

實例化:類名加括號就是實例化,會自動觸發__init__函數的運行,能夠用它來爲每一個實例定製本身的特徵

實例化的過程 :

    1.開闢了一塊空間,創造了一個self變量來指向這塊空間

    2.調用init,自動傳self參數,其餘的參數都是按照順序傳進來的

    3.執行init

    4.將self自動返回給調用者

1.類名能夠調用全部定義在類中的名字

     變量

     函數名

2.對象名 能夠調用全部定義在對象中的屬性

     在init函數中和self相關的

     調用函數的,且調用函數的時候,會把當前的對象當作第一個參數傳遞給self

 

類的加載順序

     1.類內部一個縮進的全部代碼都是在py文件從上到下解釋的時候就已經被執行了

     2.類中的代碼永遠是從上到下依次執行的

class A:
    country = 'China'
    def __init__(self):
        print('執行我了')

    def func(self):
        print('1111111')

    def func(self):
        print('2222222')
A.country = 'English'
a = A()   #執行我了
a.func()  #2222222

 

類 和 對象 的命名空間

class Student:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    a = 1
    b = 2
    def func(self):
        pass

yang = Student('楊鵬',20,'male')
View Code

 

# 類 和 對象 存儲在兩塊命名空間裏的
class Student:
    country = 'China'
    def __init__(self,name,country):
        self.name = name
        self.country = country

zhang = Student('張堯','日本人')
zou = Student('鄒路','法國人')
print(Student.country)   #China
print(zou.country)       #法國人
print(zhang.country)     #日本人
# 對象去找類空間中的名字的前提 : 在本身的空間中沒有這個名字

class Student:
    country = 'China'
    def __init__(self,name):
        self.name = name

zhang = Student('張堯')
zou = Student('鄒路')
print(zhang.country)       #China
Student.country = '法國人'
print(zhang.country)       #法國人
zhang.country = '日本人'   # 給一個對象添加了一個屬性
print(zou.country)         #法國人
print(zhang.country)       #日本人
# 在操做靜態變量的時候應該儘可能的使用類名來操做而不是使用對象名
 

 

# 練習 :寫一個類,可以自動的統計這個類有多少個對象
class A:
    Count = 0
    def __init__(self,name):
        self.name = name
        A.Count += 1

a = A('alex')   # 建立了一個新對象
a2 = A('alex2')
print(A.Count)   #2

 

class B:
    l = [0]
    def __init__(self,name):
        self.name = name

b1 = B('顏海清')
b2 = B('孫晶晶')
print(B.l)     #[0]
print(b1.l)    #[0]
print(b2.l)    #[0]
b1.l[0] += 1   
print(b2.l[0]) #1
b1.l = [123]   
print(b2.l)    #[1]

 

只要是對一個對象.名字直接賦值,那麼就是在這個對象的空間內建立了新的屬性

只要是對一個可變的數據類型內部的變化,那麼仍然是全部的對象和類共享這個改變的成果

 

全部的靜態變量都是用類名來操做,這樣修改就能被全部的對象感知到

若是是對於可變數據類型的靜態變量 操做的是這個數據內部的內容,也可使用對象來調用

 

面向對象的三大特性 :繼承  多態  封裝

(一)繼承   

 繼承是一種建立新類的方式,在python中,新建的類能夠繼承一個或多個父類,父類又可稱爲基類或超類,新建的類稱爲派生類或子類

 

#單繼承
class Parent:
    pass

class Son(Parent):
    pass

print(Son.__bases__)

 

# 多繼承
class Parent1:
    pass
class Parent2:
    pass

class Son(Parent1,Parent2):
    pass

print(Son.__bases__)  #(<class '__main__.Parent1'>, <class '__main__.Parent2'>)
 #__base__只查看從左到右繼承的第一個子類,__bases__則是查看全部繼承的父類

 

 單繼承

class Animal(object):
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color
        Animal.__init__(self,name,kind)   # 在子類和父類有同名方法的時候,默認只執行子類的方法
        # 若是想要執行父類的方法,能夠在子類的方法中再 指名道姓 的調用父類的方法

class Dog(Animal):pass


hua = Cat('小花','橘貓','藍色')
print(hua.__dict__)   # {'eyes_color': '藍色', 'name': '小花', 'kind': '橘貓'}
# 當Cat本身擁有__init__的時候,就再也不調用父類的了

 

class Animal:
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color
        # super(Cat,self).__init__(name,kind)
        # super().__init__(name,kind)   # 至關於執行父類的init方法
        # Animal.__init(self,name,kind)

class Dog(Animal):pass


hua = Cat('小花','橘貓','藍色')
print(hua.__dict__)  #{'eyes_color': '藍色'}

 

class Animal(object):
    def __init__(self,name,kind):
        self.name = name
        self.kind = kind

    def eat(self,food):
        print('%s eat %s'%(self.name,food))

    def drink(self):
        print('%s drink water'%(self.name))

    def catch(self):
        print('%s catch mouse'%(self.name))
class Cat(Animal):
    def __init__(self,name,kind,eyes_color):
        self.eyes_color = eyes_color  # 派生屬性
        # super(Cat,self).__init__(name,kind)
        super().__init__(name,kind)   # 至關於執行父類的init方法
        # Animal.__init(self,name,kind)

    def climb(self):              # 派生方法
        print('%s climb tree'%self.name)

class Dog(Animal):
    def chai(self):
        print('%s cha'%(self.name))


hua = Cat('小花','橘貓','藍色')
hua.eat('小魚乾')
hua.climb()
class Animal(object):
    def __init__(self,name,blood,ad):
        self.name = name
        self.hp = blood
        self.ad = ad
class Dog(Animal):
    def __init__(self,name,blood,ad,kind):
        super().__init__(name,blood,ad)
        self.kind = kind

    def bite(self,person):
        person.hp -= self.ad
        print('%s攻擊了%s,%s掉了%s點血' % (self.name, person.name, person.name, self.ad))

class Person(Animal):
    def __init__(self,name,hp,ad,sex):
        super().__init__(name,hp,ad)
        self.sex = sex

    def fight(self,dog):
        dog.hp -= self.ad
        print('%s攻擊了%s,%s掉了%s點血'%(self.name,dog.name,dog.name,self.ad))

hei = Dog('小黑',300,20,'哈士奇')
alex = Person('alex',20,1,'不詳')
alex.fight(hei)
print(hei.hp)
hei.bite(alex)
print(alex.hp)
人狗大戰(繼承)

 

 子類 父類

 子類的對象

 想要使用某一個名字

     若是本身有 就用本身的

     若是本身沒有 就用父類的

   # 若是父類也沒有 就報錯

 若是想要使用的名字父類子類都有

     既想使用子類的,也想使用父類的,那就在子類的方法中使用

        1. 父類名.方法名(self,參數1,參數2)

        2. super().方法名(參數1,參數2)

在python3當中,全部的類都繼承object類,全部的類都是新式類

父類是object的類 —— 新式類

class A(object):
    pass

a = A()   # 老是要調用init的,若是咱們不寫,實際上就調用父類object的__init__方法了

 

多繼承

多繼承 是python語言中特有的繼承方式

java語言中不支持多繼承的,C#也不支持多繼承

C++支持多繼承

 

 多繼承和單繼承是同樣的

     若是對象使用名字

     是子類中有的,那麼必定用子類的

     子類沒有,能夠到多個父類中去尋找

 

鑽石繼承

# 鑽石繼承問題
class A(object):
    def func(self):
        print('a')

class B(A):
    pass
    # def func(self):
    #     print('b')

class C(A):
    pass
    # def func(self):
    #     print('c')

class D(B,C):
    pass
    # def func(self):
    #     print('d')

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

 

# 烏龜繼承問題
class A(object):
    def func(self):
        print('a')

class B(A):
    pass
    # def func(self):
    #     print('b')

class C(A):
    pass
    # def func(self):
    #     print('c')

class D(B):
    pass
    # def func(self):
    #     print('d')

class E(C):
    pass
    # def func(self):
    #     print('e')

class F(D,E):
    pass
    # def func(self):
    #     print('f')
print(F.mro())  #[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

 

 

#python3中統一都是新式類 #pyhon2中才分新式類與經典類
.__mro__ #只有新式纔有這個屬性能夠查看線性列表,經典類沒有這個屬性

   在多繼承中,super就只和mro順序有關係,和父類子類沒有關係了

    C3算法


L(G)=L(G(o))=[G,o]
L(E)=L(E(G(o)))
    =E +merge(L(G(o)))
    =E+[G,o]=[E,G,o]
L(D)=L(D(o))=[D,o]
L(F)=L(F(o))=[F,o]
L(B)=L(B(D,E))=B+merge(L(D),L(E),DE)
             =B+merge(Do,EGo,DE) #D 合格
              =B +D +merge(o,EGo,E) # E合格
              =B +D + E +merge(G,o,)= [B,D,E,G,o]
L(C)=L(C(D,F))=C+merge(L(D),L(F),DF)
             =C+merge(Do,Fo,DF) #D 合法
              =C+D+merge(o,Fo,F)  # F合法
              =C+D+F+merge(o)=[C,D,F,o]
L(A)=L(A(B,C))=A+merge(L(B),L(C),BC) =A +merge(BDEGo,CDFo,BC)  #B合法
                                     =A + B+merge(DEGo,CDFo,C)  # D不合法,看第二元素C合格
                                  =A + B+C+merge(DEGo,DFo,) #D合格
                                   =A + B+C+D+merge(EGo,Fo,)# E合格
                                    =A + B+C+D+E+merge(Go,Fo,)
                                      =A + B+C+D+E+G+F+o=[A,B,C,D,E,G,F,o]

運算代碼

 

type 與class
class Course:
    def __init__(self,name,price):
        self.name = name
        self.price = price

python = Course('python',20000)
print(type(python))      #<class '__main__.Course'>

# type一個對象的時候,結果老是這個對象所屬的類
# 類是什麼類型???全部的類的類型都是type
print(type(Course))    #<class '__main__.Course'>
print(type(int))          #<class 'type'>
print(type(str))          #<class 'type'>
 

對象是被創造出來 被類實例化出來的

類也是被創造出來的 特殊的方式來創造類

     常規創造的類 老是有幾個特性

         可以實例化

         能有屬性

         能有方法

    元類 可以幫助你創造不一樣尋常的類

         特殊的需求一 : 不能實例化

         特殊的需求二 : 只能有一個實例

類 = type(對象)

type = type(類)

全部的類型 說的都是這個對象是屬於哪個類的

全部的用class常規語法創造出來的類 都是type類型

 

進階

元類 :是可以幫助咱們創造一些有特殊要求的類

 

抽象類  

什麼是抽象類

    與java同樣,python也有抽象類的概念可是一樣須要藉助模塊實現,抽象類是一個特殊的類,它的特殊之處在於只能被繼承,不能被實例化

爲何要有抽象類

    若是說類是從一堆對象中抽取相同的內容而來的,那麼抽象類是從一堆中抽取相同的內容而來的,內容包括數據屬性和函數屬性。

from abc import ABCMeta, abstractmethod

class Payment(metaclass=ABCMeta):       # 抽象類
    def __init__(self, name, money):
        self.name = name
        self.money = money

    @abstractmethod                    # 若是我必需要實現pay方法,那麼我須要給pay加一個裝飾器
    def pay(self):                     # # 建立的這個pay並無內容,
        pass                             # 之因此寫一個pay是爲了提醒全部子類你必定要實現一個pay方法
       
    @abstractmethod
    def back(self):
        pass

class WechatPay(Payment):
    def pay(self):
        print('%s經過微信支付了%s元' % (self.name, self.money))

    def back(self):
        print('退款')

class AliPay(Payment):
    def pay(self):
        print('%s經過支付寶支付了%s元' % (self.name, self.money))

    def back(self):
        print('退款')

class ApplePay(Payment):
    def pay(self):
        print('%s經過apple pay支付了%s元' % (self.name, self.money))

    def back(self):
        print('退款')

def pay(person):
    person.pay()

def back(person):
    person.back()

apple = ApplePay('alex', 20000)
pay(apple)    #alex經過apple pay支付了20000元
back(apple)   #退款

抽象類 :Payment這個類是一個抽象類

抽象類作什麼事兒 : 約束全部的子類 必須實現被abstractmethod裝飾的方法名給咱們的代碼指定規範

特色 : 抽象類不能實例化,只是做爲具體的類的規範

抽象類長什麼樣

    class 類名(metaclass = 'ABCMeta'):

         

 @abstractmethod

         def 規定的方法名(self):pass

 

         @abstractmethod

         def 規定的方法名(self):pass

 

         @abstractmethod

         def 規定的方法名(self):pass

1.抽象類的意義是?或者說爲何要有抽象類?
抽象類是對多個類中共同方法的抽取,可是子類又有不一樣的實現,父類只能抽取出方法的名字,而不明確方法的具體實現.
這種只規定子類擁有哪些方法,而不明確具體實現的父類,就應該定義爲抽象類.
抽象類只用來規範子類應該具備哪些行爲,而不明確具體的動做.

2.抽象類的特色是?
抽象類和普通類的最主要區別在於:
1.抽象類繼承的()中寫的是metaclass=ABCMeta
2.在類體中有用@abstractmethod修飾的方法(須要子類重寫的方法)

3.抽象類中是否能夠有非抽象方法?
能夠.

4.抽象類中的抽象方法是否能夠有方法體?
能夠.

5.抽象類中是否能夠有__init__方法?爲何?
能夠,由於抽象類中也能夠有實例屬性供子類繼承.
而實例屬性必須在父類中初始化,子類對象才能繼承.

抽象類的__init__方法不能手動調用,只能是子類建立對象時自動調用的.
有關問題

 

 接口類

類只能單繼承,因此抽象類 只能是全部的子類只有一個規範

java 當中沒有多繼承的類

     接口 接口能夠多繼承

python裏沒有接口的專用語法

 

     咱們只是經過類的多繼承 模仿接口的效果 

from abc import ABCMeta,abstractmethod
class NormalAnnimal(metaclass=ABCMeta):
    @abstractmethod
    def eat(self):pass

    @abstractmethod
    def drink(self):pass
class FlyAnimal(metaclass=ABCMeta):
    @abstractmethod
    def fly(self):pass

class SwimAnimal(metaclass=ABCMeta):
    @abstractmethod
    def swim(self):pass

class WalkAnimal(metaclass=ABCMeta):
    @abstractmethod
    def walk(self):pass


class Frog(NormalAnnimal,SwimAnimal,WalkAnimal):
    def eat(self):
        pass


class Tiger(NormalAnnimal,SwimAnimal,WalkAnimal):pass
class Swan(NormalAnnimal,FlyAnimal,SwimAnimal,WalkAnimal):pass
class Parrot(NormalAnnimal,FlyAnimal,WalkAnimal):
    def talk(self):
        pass

 

抽象類 是單繼承的規範

接口類 是多繼承的規範

java

    接口裏面定義的全部的方法 都不能寫具體的實現 pass

    抽象類裏面定義的全部的抽象方法 內部是能夠完成一些簡單的代碼 

 

(二)多態  

在python當中 到處是多態,一切皆對象

廣義的多態       一個類能表現出的多種形態

 
#在java 中  在python中報錯
class Payment:pass

class Alipay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s經過支付寶支付了%s元'%(self.name,self.money))

class ApplePay(Payment):
    def __init__(self,name,money):
        self.name = name
        self.money = money
    def pay(self):
        print('%s經過apple pay支付了%s元' % (self.name, self.money))

# 歸一化設計
def pay(Payment person):
    person.pay()

# 支付有多種形態 : 支付寶 微信支付 apple支付
 
鴨子類型
#兩者都像鴨子,兩者看起來都像文件,於是就能夠當文件同樣去用
class TxtFile:
    def read(self):
        pass

    def write(self):
        pass

class DiskFile:
    def read(self):
        pass
    def write(self):
        pass
示例  

鴨子類型

     python當中寫程序的一種特殊的狀況

     其餘語言中 正常的咱們說一個數據類型具備某個特色,一般是經過繼承來實現

        繼承迭代器類,來證實本身自己是個迭代器

        繼承可哈希的類,來證實本身本事是可哈希的

     可是全部的這些都不是經過繼承來完成的

         咱們只是經過一種潛規則的約定,若是具備__iter__,__next__就是迭代器

         若是具備__hash__方法就是可哈希

         若是具備__len__就是能夠計算長度的

     這樣數據類型之間的關係並不只僅是經過繼承來約束的    而是經過約定俗成的關係來確認的

多態

     在傳遞參數的時候,若是要傳遞的對象有多是多個類的對象

            咱們又必須在語言中清楚的描述出究竟是那一個類型的對象

            咱們就可使用繼承的形式,有一個父類做爲這些全部可能被傳遞進來的對象的基類

            基礎類型就能夠寫成這個父類

            因而全部子類的對象都是屬於這個父類的

     在python當中,由於要傳遞的對象的類型在定義階段不須要明確,因此咱們在python中到處都是多態

           數據的類型不須要經過繼承來維護統一

 

namedtuple (例如撲克牌)
 
from collections import namedtuple

Course = namedtuple('Course',['name','price','period'])
python = Course('python',20000,'6 month')
print(python.name)    #python
print(python.price)   #20000
print(python.period)  #6 month
print(type(python))   #<class '__main__.Course'>

#屬性不可修改,而且沒有方法 

pickle 類 (寫入,讀取文件)
 
import pickle
class Course:
    def __init__(self,name,price,period):
        self.name = name
        self.price = price
        self.period = period

# python = Course('python',20000,'6 months')
# linux = Course('linux',15800,'5 months')
# import pickle
# with open('pickle_file','ab') as f:
#     pickle.dump(python,f)
#     pickle.dump(linux,f)

import pickle
with open('pickle_file','rb') as f:
    # obj1 = pickle.load(f)
    # obj2 = pickle.load(f)
    while True:
        try:
            obj = pickle.load(f)
            print(obj.__dict__)
        except EOFError:
            break
 

 

(三)封裝

 廣義上的封裝 : 把方法和屬性根據根據類別裝到類中

 狹義上的封裝 : 私有化的方法和屬性

 方法\靜態變量\實例變量(對象屬性)均可以私有化

 所謂的私有化 : 就是隻能在類的內部可見,類的外部是不能訪問或者查看的

私有變量和私有方法

在python中用雙下劃線開頭的方式將屬性隱藏起來(設置成私有的)

class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price    # 私有屬性

    def get_price(self):
        print(self.__price)

apple= Goods('蘋果',5)
print(apple.name)
apple.get_price()
# print(apple.__price)   #報錯
 
#私有的靜態變量
class Role:
    __Country='China'   # 靜態變量的私有化
    def func(self):
        print(self.__Country)
print(Role.__Country)  # 報錯 : 由於不能再類的外部引用變量
Role().func()
# 私有的方法
import hashlib
class Auth:
    def __init__(self,user,pwd):
        self.username = user
        self.password = pwd

    def __md5_code(self):
        md5 = hashlib.md5(self.username.encode('utf-8'))
        md5.update(self.password.encode('utf-8'))
        return md5.hexdigest()

    def login(self):
        if self.username == 'alex' and 'ee838c58e5bb3c9e687065edd0ec454f' == self.__md5_code():  # pwd = alex3714
            return True

user = input('>>>')
pwd = input('>>>')
obj = Auth(user,pwd)
# obj.__md5_code()   # 報錯的,私有的方法不能在類的外部被使用
obj._Auth__md5_code()   # 不報錯的
ret = obj.login()
if ret:
    print('登錄成功')
    
#>>>alex
#>>>alex3714
#登錄成功
# 私有化是怎麼完成的?
class Goods:
    def __init__(self,name,price):
        self.name = name
        self.__price = price    # 私有屬性

    def get_price(self):
        print(self.__price)

    def set_num(self):
        self.__num = 20

apple = Goods('蘋果',5)
print(apple.__dict__)        #{'name': '蘋果', '_Goods__price': 5}
print(apple._Goods__price)   # 私有的造成
# 全部的私有的變化都是在類的[內部]定義的時候完成的
apple.__num = 10
print(apple.__dict__)       #{'name': '蘋果', '_Goods__price': 5, '__num': 10}
apple.set_num()
print(apple.__dict__)       #{'name': '蘋果', '_Goods__price': 5, '__num': 10, '_Goods__num': 20}
class Foo:
    def __init__(self):
        self.func()

    def func(self):
        print('in foo')

class Son(Foo):
    def func(self):
        print('in son')

Son()
#  in son
繼承
# 私有的屬性能夠被繼承麼?
class Foo:
    def __init__(self):
        self.__func()

    def __func(self):
        print('in foo')

class Son(Foo):
    def __func(self):
        print('in son')

Son()
#in foo

私有的全部內容 :實例變量(對象屬性),靜態變量(類變量),方法都不能被子類繼承

 公有的 public  在類的內部外部隨便用 

 私有的 private 只能在類的內部使用  既不能被繼承 也不能在類的外部使用

 

property
class Circle:
    def __init__(self,r):
        self.r = r

    def area(self):
        return 3.14*self.r**2

    def perimeter(self):
        return 2*3.14*self.r

c1 = Circle(5)
c1.r=10 
print(c1.area())      #調用方法
print(c1.perimeter()) #須要加()
View Code
class Circle:
    def __init__(self,r):
        self.r = r

    @property  # 把裝飾的一個方法假裝成一個屬性
    def area(self):
        return 3.14*self.r**2

    @property
    def perimeter(self):
        return 2*3.14*self.r

c1 = Circle(5)
c1.r=10
print(c1.area)     #相似調用屬性
print(c1.perimeter)
import time
class Person:
    def __init__(self,name,birth):
        self.name = name
        self.birth = birth

    @property
    def age(self):
        struct_t = time.localtime()
        age = struct_t.tm_year - int(self.birth.split('-')[0])
        return age

alex = Person('alex','1965-5-12')
print(alex.age)

 

property與私有
class Goods:
    discount = 0.8   # 靜態變量  (表明打折)
    def __init__(self,name,price):
        self.name = name
        self.__price = price   #價格設置私有

    def price(self):
        return self.__price * self.discount

apple = Goods('蘋果',5)
banana = Goods('香蕉',10)
print(apple.name)       #蘋果
print(apple.price())    #4.0
print(banana.price())   #8.0
Goods.discount = 1      
print(apple.price())    #5
print(banana.price())   #10
class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property
    def price(self):
        p =  self.__price * self.discount
        return p

apple = Goods('蘋果', 5)
banana = Goods('香蕉', 10)
print(apple.name)
print(apple.price)
print(banana.price)
Goods.discount = 1
print(apple.price)
print(banana.price)
class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property    # 只支持obj.price的方式查看這個結果,不支持修改,也不支持刪除
    def price(self):
        p =  self.__price * self.discount
        return p

    @price.setter
    def price(self,value):
        if type(value) is int or type(value) is float:
            self.__price = value

apple = Goods('蘋果', 5)
banana = Goods('香蕉', 10)
apple.price = 16   # 對應的調用的是被setter裝飾的price方法
print(apple.price)  # 對應調用的是被property裝飾的price方法

 

若是咱們定義的是普通的變量或者屬性

     那麼這個屬性能夠從外部直接訪問

     能夠任意的修改 obj.attr = 123

     甚至能夠刪除 del obj.attr

 私有化

     把一個屬性加上雙下劃線 __屬性名

     這個屬性就連在外面看都看不見了

     咱們實際上有些場景容許別人看,不準改

          __屬性

         @property裝飾的屬性名

         def 屬性():

 

     咱們容許別人看,也容許別人改,可是不能瞎改,有一些要求:數據類型 範圍

         __屬性

         @property裝飾的屬性名

         def 屬性():return __屬性

 

         @屬性.setter

         def 屬性(self,value):

             加點兒條件

             修改__屬性

class Goods:
    discount = 0.8

    def __init__(self, name, price):
        self.name = name
        self.__price = price

    @property    # 只支持obj.price的方式查看這個結果,不支持修改,也不支持刪除
    def price(self):
        p =  self.__price * self.discount
        return p

    @price.setter
    def price(self,value):
        if type(value) is int or type(value) is float:
            self.__price = value

    @price.deleter
    def price(self):
        del self.__price

# 想刪除一個屬性
apple = Goods('蘋果', 5)
del apple.price
print(apple.__dict__)
apple.price        # 'Goods' object has no attribute '_Goods__price'
apple.price = 9
 
classmethod
class Fruits:
    __discount = 0.8    #將類中靜態變量變爲私有

    def __init__(self, name, price):
        print('init',self)
        self.name = name
        self.__price = price

    @classmethod      # 把一個方法從對象方法,變成一個類方法
    def change_discount(cls,value):
        cls.__discount = value   # cls究竟是誰??? Fruits

    @classmethod
    def get_discount(cls):
        return cls.__discount

print(Fruits.get_discount())
Fruits.change_discount(1)
print(Fruits.get_discount())

# 類方法
    # 1. 有些時候咱們要修改的是類中的靜態變量/類變量
    # 此時根本不會和self有任何的操做關聯
    # 這時傳一個self參數對咱們來講徹底沒有用
    # 咱們但願接受的是當前咱們所在的類

apple = Fruits('apple',8)
apple.change_discount(0.5)
print(Fruits.get_discount())

# 類方法推薦使用類名調用而不是使用對象名調用
 
staticmethod 
class A:
    @staticmethod  # 聲明這個方法只是一個普通的不會使用任何和這個類中的變量相關的方法
    def func():    # 此時 func是一個靜態方法
        print('既不操做和self相關的內容')
        print('也不操做和類名相關的內容')

A.func()


# login 登陸

class Student:
    def __init__(self,name):
        self.name = name

    @staticmethod
    def login():
        pass

# 先獲取這個學生的用戶名和密碼
# 判斷他登陸成功以後進行實例化
# Student.login()
# stu = Student('alex')
 

 

面向對象的反射

 

class Student:
    def __init__(self,name):
        self.name = name

    def show_courses(self):         #查看課程
        print('調用了 show courses')

    def select_course(self):        #選擇課程
        print('調用了 select course')

    def show_selected_course(self): #查看所選課程
        print('調用了 show_selected_course')

    def quit(self):                 #退出
        print('調用了 quit')
wu = Student('吳彪')
# print(wu.name)
# wu.show_courses()
# wu 'name'
# 反射 經過字符串屬性名 獲得真正的這個字符串的名字對應的對象的屬性值
# ret = getattr(wu,'name')   # 內置函數
# print(ret)
# wu.show_courses()
# print(getattr(wu,'show_courses'))  # wu.show_courses
# getattr(wu,'show_courses')()
# getattr(wu,'select_course')()

while True:
    name = input('>>>')
    if hasattr(wu,name):
        func_attr = getattr(wu,name)
        if callable(func_attr):
            func_attr()
        else:
            print(func_attr)
相關文章
相關標籤/搜索