1. 程式人生 > >類的成員-反射-雙下方法

類的成員-反射-雙下方法

text 需求 inpu 第一個 實例 user tro div 關系

類的私有成員:

私有成員只是做了一個簡單是變相加密,直接訪問不了

1.私有靜態屬性

在變量名前加 __ 可以在本類的內部訪問,在類的外部和派生類中無法訪問

class A:
    country = 中國
    __country = 加拿大 # 私有靜態屬性

    def func(self):
        print(A.country)
        print(A.__country)

class B(A):

    def func1(self):
        print(super().country)

obj = A()

# 在類的內部訪問: 可以 obj.func() # 類的外部訪問: 不可以 print(A.__country) obj.__country # 在派生類訪問: 不可以 obj1 = B() obj1.func1()

2.私有方法

可以在本類的內部訪問,在類的外部和派生類中無法訪問

class A:
    def __f1(self):
        print(in A f1)

    def func(self):
        self.__f1()

class B(A):
    def f1(self):
        super().__f1()

obj 
= A() # 類內部可以訪問 obj.func() # 類外部不可以訪問 obj.__f1() # 類的派生類: 不可以訪問 b = B() b.f1()

3.私有對象屬性

class A:

    def __init__(self,name,age):
        self.name = name
        self.__age = age

    def func(self):
        print(self.__age)

obj = A(靜哥,24)

#類內部可以訪問:
obj.func()
#類的外部不能訪問:
print(obj.__age)
#派生類也不能訪問

什麽時候使用私有成員:

密碼,年齡,個人信息,只是類內部使用的方法等,需要設置私有成員

類的其他成員

1)類方法:

@classmethod

通過類名調用的方法,第一個參數主動接收類名,為了區分,參數名為cls

對象也可以調用類方法,傳給cls的參數也是類空間(一般不這麽用)

主動接收類名,與類的靜態屬性相關的需求,與對象無關的功能需要類方法

class Student:
    stu_num = 0
    def __init__(self,name,age):
        self.name = name
        self.__age = age
        Student.calc_num()    # 應該放在__new__裏面

    @classmethod
    def calc_num(cls):
        cls.stu_num += 1

    @classmethod
    def get_num(cls):
        return cls.stu_num

denge = Student(鄧哥,18)
jinge = Student(靜哥,18)
print(Student.get_num())

結果:
2

2)靜態方法

@staticmethod

不依賴與類以及對象的方法,是函數

靜態方法雖然不依賴與對象,類,但是為了保持代碼的整體性和一致性,才將其設置為靜態方法,而不是放在類外面當普通函數用

class A:
    def __init__(self,name,age):   # 雙下方法 特殊方法
        self.name = name
        self.__age = age

    def func(self):              # 實例方法:通常是通過對象去調用的方法,主動將對象傳給self
        print(in func)

    @classmethod
    def func1(cls):             # 類方法: 是通過類名調用的方法,第一個參數主動接受類名
        print(類方法)

    @staticmethod             # 靜態方法:不依賴於類以及對象的方法,是函數.
    def func2():
        pass

3)屬性

@property

將方法偽裝成屬性,雖然在代碼邏輯上沒有提升,但是看起來更合理

class Bmi:
    def __init__(self,name,weight,height):
        self.name = name
        self.__weight = weight
        self.height = height
    @property
    def bmi(self):
        return self.__weight/(self.height**2)

obj = Bmi(hu,75,1.75)
print(obj.bmi)      #bmi本身是一個方法,通過@property裝飾器之後,直接用調用屬性的方式進行打印就可以

另外有更改和刪除的方法:

class A:
    @property
    def AAA(self):
        print(調用屬性)

    @AAA.setter
    def AAA(self,new):           #更改屬性時要傳參
        print(更改屬性)

    @AAA.deleter
    def AAA(self):
        print(刪除屬性)

obj = A()
# obj.AAA               #調用
# obj.AAA = 111      #更改
# del obj.AAA           #刪除

####練習:
class Goods:
    def __init__(self,name,money,sale):
        self.name = name
        self.money = money
        self.sale = sale

    @property
    def price(self):
        return self.money*self.sale
    @price.setter
    def price(self,new):
        self.money = new / self.sale

apple = Goods(蘋果,5,0.9)
#計算現價
# print(apple.price)
#要求改過之後的價格為10
apple.price = 10
print(apple.price)

源碼見的最多的是 property

對象自己的屬性 如果與類的偽裝的屬性重名時,對對象屬性進行修改時,則只會執行@setter方法

為了避免這個坑,給對象設置的屬性名,不要與property偽裝的屬性名重名

4)isinstance issubclass

isinstance(o,a) 判斷o是否是a或者a的派生類的對象

class A:
    pass

class B(A):
    pass

obj = B()
print(isinstance(obj,B))      #True
print(isinstance(obj,A))      #True

issubclass(a,b) 判斷a是否是b的子類或孫類

class A:
    pass

class B(A):
    pass

class C(B):
    pass
print(issubclass(B,A))        #True
print(issubclass(C,A))        #True

list str等這些可叠代對象與 Iterable是什麽關系?

from collections import Iterable
l1 = [1,2,3]
print(isinstance(l1,Iterable))     # l1是Iterable(派生類)的實例的對象

list類與Iterable類是什麽關系?

print(issubclass(list,Iterable))       # list是Iterable的派生類

元類

python 一切皆對象原則

類也是對象

type 元類,也叫構建類,產出了python中大量的內置類(str,list...)以及自建類

反射

通過字符串對對象進行相應的操作(對象:實例化對象 類 其他模塊 本模塊)

hasattr() 判斷有沒有

getattr() 取值

setattr() 設置(增)

delattr() 刪除

class A:
    country = 中國
    def __init__(self,name,age):
        self.name = name
        self.age = age
    def func(self):
        print(in A func)

obj = A(棍哥,20)
print(hasattr(obj,name))   #判斷有沒有‘name‘屬性
print(getattr(obj,name))   #取‘name‘的值
setattr(obj,height,180)    #增加‘height‘
print(obj.__dict__)
delattr(obj,age)           #刪除‘age‘
print(obj.__dict__)

註意事項:

反射只能用在都可以通過 . 去操作的對象

class User:
    def login(self):
        print(歡迎來到登錄頁面)

    def register(self):
        print(歡迎來到註冊頁面)

    def save(self):
        print(歡迎來到存儲頁面)

while 1:
    choose = input(請輸入).strip()
    obj = User()
    if hasattr(obj,choose):
        getattr(obj,choose)()

判斷函數與方法:

def func():
    pass

class A:
    def func1(self):
        pass
#1.通過打印名字的方式判斷
print(func)         #函數
print(A.func1)     #函數
obj = A()
print(obj.func1)   #方法
#2.通過引用模塊
from types import FunctionType   函數 
from types import Methodtype     方法
print(isinstance(func,FunctionType))         # True
print(isinstance(A.func1,FunctionType))      # True
print(isinstance(obj.func1,FunctionType))    # Flase
print(isinstance(obj.func1,MethodType))      # True

之前學的函數就是函數

通過類名調用,就是函數

通過實例調用,就是方法

類中的靜態方法是函數

類中的類方法,是方法

函數與方法的區別:

函數是顯性傳參,不依賴於對象

方法是隱形傳參(默認接收對象空間或者類空間),依賴對象,類

特殊的雙下方法

解釋器提供的,由__方法名__的具有特殊意義的方法,主要是python源碼程序員使用的元編程,開發中盡量不使用

__init__ 類名()觸發

1)len ****

一個實例能否使用len操作,完全取決於它的類中有沒有__len__方法

class A:
    def __init__(self,name,age,sex,weight):
        self.name = name
        self.age = age
        self.sex = sex
        self.weight = weight
    def __len__(self):
        print(666)
        return len(self.__dict__)
obj = A(劉姐,18, ,100)
len(obj)            # 只要對對象len() 就會觸發對象從屬於的類中的 __len__  
print(len(obj))

結果:
666
666
4

2)__hash__

class A:
    def __init__(self):
        pass
    def __hash__(self):
        return 666
obj = A()
print(hash(obj))       #觸發__hash__方法

3)__str__

class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age

    def __str__(self):
        return str(self.__dict__)

obj = A(alex,73)
print(obj)

結果:
{name: alex, age: 73}

4)__repr__

class A:
    def __repr__(self):
        return alex
obj = A()
print(repr(obj))    

結果:
alex


5)_call__: 對象() 執行 __call__方法 *****

class A:

    def __init__(self):
        print(111)

    def __call__(self, *args, **kwargs):
        print(666)

obj = A()    #觸發__init__方法
obj()        #觸發__call__方法

6)__eq__

class A:
    def __init__(self):
        self.a = 1
        self.b = 2

    def __eq__(self,obj):
        print(666)

a = A()
b = A()
print(a == b)  # 同一個類的兩個實例進行比較就會觸發類中 __eq__方法

結果:
666
None

6)__del__ 析構方法

class A:
    def __del__(self):
        print(666)
obj = A()

結果:
666

7)__new__ 構造方法 ***

類名() 調用__new__方法

class A:
    def __init__(self,name,age):
        self.name = name
        self.age = age
        print(111)

    def __new__(cls, *args, **kwargs):
        print(222)
        return object.__new__(cls)

obj = A(barry,18)

結果:
222
111

單例模式 規定一個類只能實例化一個對象(面試題)

class A:
    pass
ret = A()
print(ret)
ret = A()
print(ret)
ret = A()
print(ret)
#以上三個ret內存地址是不同的
class A:
    __instance = None
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            obj = object.__new__(cls)
            cls.__instance = obj
        return cls.__instance

ret = A()
print(ret)
ret = A()
print(ret)
ret = A()
print(ret)
#以上三個ret內存地址是一樣的

8)__item__: *****

對對象進行類似於字典的操作的時候,就會觸發相應的方法.

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

    def __getitem__(self, item):
        return self.__dict__[item]

    def __setitem__(self, key, value):
        # print(key,value)
        self.__dict__[key]=value
    def __delitem__(self, key):
        print(key)
        print(del obj[key]時,我執行)
        self.__dict__.pop(key)

    def __delattr__(self, item):
        print(del obj.key時,我執行)
        self.__dict__.pop(item)

f = Foo(alexsb)
print(f[name])
print(f.__dict__)
f[name] = sb  # 觸發 __setitem__方法
print(f.__dict__)
del f[name]

結果:
alexsb
{name: alexsb}
{name: sb}
name
del obj[key]時,我執行


9)上下文管理

class A:

    def __init__(self, text):
        self.text = text
    def __enter__(self):    # 開啟上下文管理器對象時觸發此方法
        self.text = self.text + 您來啦
        return self        # 將實例化的對象返回f1
    def __exit__(self, exc_type, exc_val, exc_tb):  # 執行完上下文管理器對象f1時觸發此方法
        self.text = self.text + 這就走啦

f1 = A(大爺)
# print(f1.text)
with A(大爺) as f1:
    print(f1.text)
print(f1.text)   


結果:
大爺您來啦
大爺您來啦這就走啦

類的成員-反射-雙下方法