python基礎七

  • 2019 年 10 月 6 日
  • 筆記

無論是風裡,還是在雨里,我都在這裡守候著你~

對於封裝更正

私有方法,和私有屬性,靜態私有屬性

class Person:

__person = '人類'

def __init__(self,name,age):

self.name = name

self.__age = age

def get_age(self):

return self.__age

def set_age(self,newage):

if newage>15:

self.__age = newage

else:

print('年齡需要大於15')

zhangsan = Person('張三',18)

# print(zhangsan.__age) #這樣是調用不到這個屬性的

print(zhangsan.get_age()) # 這樣才是正確的調用方式

__person表示靜態私有屬性,在外部同樣獲取不到。在屬性前加上__表示封裝變成私有屬性,在外部是不能調用的。只能在內部使用,我們再在Person中添加一個方法,用這個方法獲取就可以了。

set_age:我們如果想要修改,如果想要對age有一個約束條件就可以這樣寫。

同樣,我們在Person中的方法名加上一個__,就變成了私有方法,外部無法調用。在子類中也無法去調用。

將調用方法看上去像調用一個屬性

class Person:

def __init__(self,name):

self.__name = name

@property

def get_name(self):

return self.__name

p = Person('張三')

print(p.get_name)

@property:內置裝飾器,實現如上效果。

但是get_name不能去傳參數,如果我想要去修改呢?

如下:

class Person:

def __init__(self,name):

self.__name = name

@property

def get_name(self):

return self.__name

@get_name.setter

def get_name(self,newname):

self.__name = newname

p = Person('張三')

print(p.get_name)

p.get_name = '李四'

print(p.get_name)

把get_name 當成屬性去修改它即可。

刪除一個屬性:

class Person:

def __init__(self,name):

self.__name = name

@property

def get_name(self):

return self.__name

p = Person('張三')

print(p.get_name)

del p.get_name

會被錯,會提示can't delete attribute,不能刪除。

那怎麼樣才能刪除呢:

class Person:

def __init__(self,name):

self.__name = name

@property

def get_name(self):

return self.__name

@get_name.deleter

def get_name(self):

print('刪除我')

p = Person('張三')

print(p.get_name)

del p.get_name

print(p.get_name)

執行會輸出:

張三

刪除我

張三

顯然,沒有報錯,但是卻沒有刪除,但是其中執行了刪除我這個方法,也就是說我們在外面del一個屬性(方法)實際上是調用了這個方法,那麼我們將輸出刪除我這個方法修改成:

@get_name.deleter

def get_name(self):

del self.__name

即可。 第二次輸出會報錯:沒有這個屬性。

其他:

1、判斷一個類是不是另一個類的子類:

class A:

pass

class B(A):

pass

print(issubclass(B,A)) # True

是返回True,不是返回False

2、判斷一個對象是否是一個類的對象

class A:pass

a = A()

print(isinstance(a,A)) # True

是返回True ,不是返回False

定義類的規範

當我們想要定義一個類的規範的時候,比如支付寶和衛星都有支付功能,我想寫一個方法,可以調用支付寶和微信的支付功能。

class Wechat:

def pay(self,money):

print('微信支付了%s元'%money)

class Alipay:

def pay(self,money):

print('阿里支付了%s元'%money)

def payzhifu(pay_nei,money):

pay_nei.pay(money)

wechat = Wechat()

p = payzhifu(wechat,100)

輸出:微信支付了100元

看來是沒有毛病的,但是如果再來一個百度支付,而百度的支付方法不是pay,那樣就會報錯,

所以我們需要寫一個類的規範。讓支付類都必須有pay方法。

這樣:

from abc import abstractmethod,ABCMeta

class PayAncestors(metaclass = ABCMeta):

@abstractmethod

def pay(self,money):

pass

class Wechat(PayAncestors):

def pay(self,money):

print('微信支付了%s元'%money)

class Alipay(PayAncestors):

def pay(self,money):

print('阿里支付了%s元'%money)

def payzhifu(pay_nei,money):

pay_nei.pay(money)

wechat = Wechat()

p = payzhifu(wechat,100)

metaclass:指定元類

@abstractmethod:給他一個裝飾器,表示要寫一個類的規範了。

這樣就定義了一個規範,他的子類都必須有pay方法,如果沒有,就會報錯,並提醒沒有pay方法。

報錯提示:Can't instantiate abstract class Wechat with abstract methods pay

我們稱它為介面類。(在python中實際是沒有介面類一說,在別的語言中有,python也可以實現,但是在python里沒有介面類一說。只是模擬了介面類)他也可以叫做抽象類。(在python類中有抽象類,實實在在存在)

介面隔離原則:我們在定義以一個規範的時候,不要使用單一的總介面,也就是說,一個類中不要有多個方法,單一點。

總結:無論是抽象類還是介面類,都是面向對象的開發規範,並且都不能實例化,一般都是單繼承,由於java中沒有多繼承,所以介面類是從java中引來的,java利用創捷介面來規範多繼承。python中不存在介面類一說,只是在python中模擬了一下寫法,但是在python中有抽象類,寫法和上面是一樣的

類方法

class Person:

__person = '人類'

def __init__(self,name):

self.name = name

def get_person(self,newperson):

Person.__person = newperson

return Person.__person

zhangsan = Person('張三')

print(zhangsan.get_person('動物類'))

如上我們可以發現,當把靜態屬性改為私有,修改的時候我們大概會這樣寫,每次都需要需要Person.xxx來調用和修改,這樣就出來了一個類方法,也就是將self替換成自己這個類對象。於是修改成:

class Person:

__person = '人類'

def __init__(self,name):

self.name = name

@classmethod

def get_person(cls,newperson):

cls.__person = newperson

return Person.__person

zhangsan = Person('張三')

print(zhangsan.get_person('動物類'))

@classmethod:加一個裝飾器表示類方法,不需要去實例化了。

cls:代表這個類本身。

當我們只修改,只需要靜態屬性的時候我們就需要這樣做。

靜態方法

當我們類中的方法沒有用到類中的參數時候,我們可以不需要實例化類,來直接調用。

實例:

class Person:

def __init__(self,name,age)

self.name =name

self.age = age

@staticmethod

def getwrite():

name = input('name:')

age = input('age:')

Person(name,age)

在以前,我們調用需要先這樣:

p = Person('張三'.18)

但是現在我們用@staticmethod聲明他是一個靜態方法之後,我們只需要這樣:

Person.getwrite()即可。

讓我們沒有用到類中的任何參數,就可以這樣定義。

反射

以字元串的形式去獲取變數並操作。和eval相似,但是比eval強大。

class Person:

list = ['星期一','星期二','星期三','星期四']

def fun_one(self):

print('我是第一個方法')

def fun_two(self):

print('我是第二個方法')

如果我們想要拿到list列表,可以這樣:

li = getattr(Person,'list')

輸出:['星期一', '星期二', '星期三', '星期四']

直接輸出一個列表。假如在Person中沒有這個list那不就會報錯了?是的

所以:

if hasattr(Person,'list'):

li = getattr(Person,'list')

hasattr():如果存在會返回True,否則返回False。二者搭配使用即可。

如果想要調用方法:同樣的使用方式,但是獲取到的只是一個記憶體地址,需要加上括弧後執行

class Person:

list = ['星期一','星期二','星期三','星期四']

def fun_one(self):

print('我是第一個方法')

def fun_two(self):

print('我是第二個方法')

p = Person()

func = getattr(p,'fun_one')

func()

反射模組屬性

getattr(模組名,'屬性名')

反射模組方法

ret = getattr(模組名,'方法名')

ret()

總結:什麼是可以反射的?

凡是xxx.qqq格式能獲取到的的都可以,xxx寫在getattr()方法的第一個參數,qqq寫在getattr()的第二個參數。

反射當前頁面的值:

import sys

name = '張三'

print(getattr(sys.modules[__name__],'name'))即可。

方法也就大同小異了。

反射修改

class A:

pass

a = A()

setattr(a,'name','張三')

反射刪除變數

class A:

name = 'lisi'

delattr(A,name)