Python 抽象篇:面向對象之類的方法與屬性


概覽:
類成員之字段:

-普通字段,保存在對象中,執行職能通過對象訪問
-靜態字段,保存在類中,執行可以通過對象訪問,也可以通過類訪問
類成員之方法:
-普通方法,保存在類中,由對象來調用,self->對象
-靜態方法,保存在類中,由類直接調用
-類方法,保存在類中,由類直接調用,cl->s當前類
應用場景:
如果對象中需要保存一些值,執行某功能時,需要使用對象中的值-->普通方法

不需要任何對象中的值-->靜態方法
類成員之屬性:property
1.類成員之字段
class Province:
    country = '中國'#靜態字段,屬於類,跟對象沒有關系,從上之下執行
    def __init__(self,name):
        self.name=name#普通字段,屬於對象,通過對象訪問
        # sef.country='中國'

henna=Province('河南')
hebei=Province('河北')
print(hebei.country) #中國
print(Province.country) #中國
print(hebei.name) #河北

靜態字段在內存中只保存一份

普通字段在每個對象中都要保存一份

應用場景: 通過類創建對象時,如果每個對象都具有相同的字段,那么就使用靜態字段

2.方法

class Bar:
    def __init__(self,name,age):#self=z,name=greg,age=84
        self.n=name
        self.a=age
    def foo(self):
        print(self.n,self.a)
z=Bar('greg',25)
print(z.a)
z.foo()

創建方法

    構造方法,__init__(self,arg)

        obj = 類('a1')

  普通方法

        obj = 類(‘xxx’)

        obj.普通方法名()

     構造方法不同於其它方法之處在於:當一個對象被創建時,會立即調用構造方法,而且可以繼承。

# -*- coding: utf-8 -*-
# 2017/12/3 13:50
class Foo:
    def bar(self):#self是對象
        print('bar')
        print(self)#<__main__.Foo object at 0x000001E82A4D13C8>
    @staticmethod
    def sta():
        print('123')

    @staticmethod
    def stas(a1,a2):#靜態方法self不必須
        print(a1,a2)

    @classmethod
    def classmd(cls):#cls是類名
        print('classmd')
        print(cls) #<class '__main__.Foo'>
#普通方法
obj=Foo()
obj.bar() #bar
Foo.bar(obj ) #bar
#靜態方法
obj.sta() #123
obj.classmd()
Foo.sta() #123
Foo.stas(1,2) #1,2
Foo.classmd() 
"""
bar
<__main__.Foo object at 0x000001C83C765390>
bar
<__main__.Foo object at 0x000001C83C765390>
123
classmd
<class '__main__.Foo'>
123
1 2
classmd
<class '__main__.Foo'>
"""

普通方法:可以在實例化后直接調用,由對象調用;至少一個self參數;執行普通方法時,自動將調用該方法的對象賦值給self,self.調用實例變量或類變量

類方法:由類調用; 實例也可調用,至少一個cls參數;執行類方法時,自動將調用該方法的類復制給cls;類方法和普通方法的區別是, 類方法只能訪問類變量,不能訪問實例變量

靜態方法:由類調用;實例也可調用,無默認參數;不可以訪問實例變量或類變量的,一個不能訪問實例變量和類變量的方法,其實相當於跟類本身已經沒什么關系了,它與類唯一的關聯就是需要通過類名來調用這個方法

類變量定義在類的定義之后,實例變量則是以為self.開頭,實例也能夠訪問類變量

class Foo(object):
    val = 0
    valu=2
    def __init__(self):
        self.val = 1

if __name__ == '__main__':
    foo = Foo()
    print(foo.val)#1
    print(foo.valu)#2
    print( Foo.val)#0

沒有init方式時

class Foo(object):
    val = 0
    def __init__(self):
        pass
if __name__ == '__main__':
    foo = Foo()
    print(foo.val)#0
    print( Foo.val)#0

還可以通過以下方式訪問類變量

class Foo(object):
    val = 3
    def __init__(self):
        print(self.__class__.val)
if __name__ == '__main__':
    foo = Foo() #3

類方法可以訪問類變量

class Foo(object):
    val = 3
    def __init__(self):
        pass

    @classmethod
    def echo(cls):
        print(cls.val)
if __name__ == '__main__':
    Foo.echo()#3

3.屬性

新式類中的屬性有三種訪問方式,並分別對應了三個被@property、@方法名.setter、@方法名.deleter修飾的方法

分別將三個方法定義為對同一個屬性:獲取、修改、刪除

class Foo:
    def __init__(self):
        self.name='a'
        self.name_list=['greg']

    def bar(self):
        print('bar')

    @property #屬性
    def per(self):
        # print('124')
        del self.name_list[0]
        print(self.name_list)
        return 123

    @per.setter
    def per(self,val):
        print(val)

    @per.deleter
    def per(self):
        print(666)

obj=Foo()
obj.bar() #bar
r=obj.per #[]
print(r) #123
obj.per=345 #345
del obj.per #666

 

property的構造方法中有個四個參數,分別叫做:fget,fset,fdel ,doc

如果沒有參數,產生的屬性既不可讀,也不可寫

如果有一個參數,說明是取值方法,產生的屬性是只讀的。

第一個參數是方法名,調用 對象.屬性 時自動觸發執行方法

第二個參數是方法名,調用 對象.屬性 = XXX 時自動觸發執行方法

第三個參數是方法名,調用 del 對象.屬性 時自動觸發執行方法,用於刪除特性的方法

第四個參數是字符串,調用 對象.屬性.__doc__ ,此參數是該屬性的描述信息,即文檔字符串

class Foo:
    def f1(self):
        return 123

    def f2(self,v):
        print(v)

    def f3(self):
        print('del')

    # per=property(fget=f1)#等同於下面三句
    # @property
    # def per(self):
    #     return 123

    per = property(fget=f1,fset=f2,fdel=f3,doc='f4')
obj=Foo()
ret=obj.per
print(ret)
obj.per=12345
del obj.per
# print(obj.per.__doc__)

4.類的私有(private)特性

為了讓方法或者特性變為 私有(從外部無法訪問),只要在它的名字前面加上雙下划線即可。

  • 公有成員,在任何地方都能訪問
  • 私有成員,只有在類的內部才能方法
class Secretive:
    def __inaccessible(self):
        print("你看不到我")

    def accessible(self):
        print("密碼是:")
        self.__inaccessible()

s=Secretive()
# s.__inaccessible() #AttributeError: 'Secretive' object has no attribute '__inaccessible'
s.accessible()
# 密碼是:
# 你看不到我

非要訪問私有屬性的話,可以通過 對象._類__屬性名,比如Secretive._Secretive.__inaccessible

特殊成員

__init__()  構造方法  類()自動執行

__call__() 對象()    類()()自動執行

構造方法的執行是由創建對象觸發的,即:對象 = 類名() ;而對於 __call__ 方法的執行是由對象后加括號觸發的,即:對象() 或者 類()()

class Foo:
    def __init__(self):
        print('__init__')

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

obj = Foo()  # 執行 __init__
obj()  # 執行 __call__

__str__             str()

class Foo:
    def __init__(self,n,a):
        self.name=n
        self.age=a
    def __str__(self):
        return '%s-%s'%(self.name,self.age)
obj=Foo('greg',89)
print(obj) #print(str(obj)) str(obj)

__int__             int(對象)

class Foo:
    def __init__(self):
        pass
    def __int__(self):
        return 1111
    def __str__(self):
        return 'greg'
obj=Foo()
print(obj,type(obj))
#int,對象,自動執行對象的__init__方法,並將返回值賦值給int對象

r=int(obj)
print(r)
i=str(obj)
print(i)

__add__

class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __add__(self, other):
        self=obj1
        other=obj2
        # return self.age+other.age#37 <class 'int'>
        return Foo('tt',99)#<__main__.Foo object at 0x0000017B7E2FC9B0> <class '__main__.Foo'>

obj1=Foo('greg',19)
obj2=Foo('gregory',18)
r=obj1+obj2#兩個對象相加時,自動執行第一個對象的__add__,
# 並且將第二個對象當做參數傳遞
print(r,type(r))

__dict__ 將對象中封裝的所有內容通過字典的形式返回

class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def show(self):
        return "%s-%s"%(self.name,self.age)

obj=Foo('greg',18)
print(obj.name) #greg
b="name"
print(obj.__dict__) #{'name': 'greg', 'age': 18}
print(obj.__dict__['name'])#greg
print(obj.__dict__[b])#greg

__getitem__切片(slice類型)或者索引,返回與所給鍵對應的值

__setitem__,按一定的方式存儲於key相關的value

__delitem__,刪除和key相關的鍵

class Foo(object):
    def __getitem__(self, key):
        print('__getitem__', key)

    def __setitem__(self, key, value):
        print('__setitem__', key, value)

    def __delitem__(self, key):
        print('__delitem__', key)

obj = Foo()
result = obj['k1']  # 自動觸發執行 __getitem__,輸出__getitem__ k1
obj['k2'] = 'greg'  # 自動觸發執行 __setitem__,輸出__setitem__ k2 greg
del obj['k1']  # 自動觸發執行 __delitem__,輸出__delitem__ k1

__iter__

 # 如果類中有 __iter__ 方法,對象=》可迭代對象

                # 對象.__iter__() 的返回值: 迭代器

                # for 循環,迭代器,next

                # for 循環,可迭代對象,對象.__iter__(),迭代器,next

                # 1、執行li對象的類F類中的 __iter__方法,並獲取其返回值

                # 2、循環上一步中返回的對象

class Foo:
    def __init__(self,name,age):
        self.name=name
        self.age=age
    def __iter__(self):
        return iter([11,22,33])

li=Foo('greg',18)

#如果類中由__iter__方法,對象—》可迭代對象
#執行li對象的類Foo類中的__iter__方法
#循環上一步中的返回的對象

for i in li:
    print(i)

__doc__

class Foo:
    '描述'
    """ 描述類信息 """
    def func(self):
        pass
print(Foo.__doc__)
#輸出:描述

__module__ 和  __class__ 

  __module__ 表示當前操作的對象在那個模塊

  __class__     表示當前操作的對象的類是什么

from A.B import C

obj = C()
print obj.__module__  # 輸出A.B,即:輸出模塊
print obj.__class__      # 輸出 A.B.C,即:輸出類

__new__ 和 __metaclass__

class Foo:
    def func(self):
        print(123)
        return 1

def function(self):
    print(123)

obj=Foo()
print(type(obj))#<class '__main__.Foo'>
print(type(Foo))#<class 'type'>
#obj對象是Foo類的一個實例,Foo類對象是 type 類的一個實例,即:Foo類對象 是通過type類的構造方法創建

Foo2=type('Foo2',(object,),{'func2':function})#聲明一個類
obj2=Foo2()
obj2.func2()
#type第一個參數:類名,type第二個參數:當前類的基類,type第三個參數:類的成員
 1 def func(self):
 2     print("hello %s"%self.name)
 3 
 4 def __init__(self,name,age):
 5     self.name = name
 6     self.age = age
 7 Foo = type('Foo',(object,),{'func':func,'__init__':__init__})
 8 
 9 f = Foo("jack",22)
10 f.func()
加上構造方法

 類 是由 type 類實例化產生

那么問題來了,類默認是由 type 類實例化產生,type類中如何實現的創建類?類又是如何創建對象?

答:類中有一個屬性 __metaclass__,其用來表示該類由 誰 來實例化創建,所以,我們可以為 __metaclass__ 設置一個type類的派生類,從而查看 類 創建的過程。

class MyType(type):
    def __init__(self,*args,**kwargs):
        #self=Foo類 self永遠是類名
        print(123)
        pass

    def __call__(self, *args, **kwargs):
        #self=Foo
        print(456)
  

class Foo(object,metaclass=MyType):#Foo是MyType的對象
    def __init__(self):
        print('Foo')
        pass

    def __new__(cls, *args, **kwargs):
        x=cls
        return x

    def func(self):
        print("hello world")

obj=Foo() #加()是執行MyType的call方法,Foo里面要執行,要用call中的方法
#call不會調用Foo中init方法
結果:123
   456

單下划線、雙下划線、頭尾雙下划線說明:

  • __foo__: 定義的是特列方法,類似 __init__() 之類的。

  • _foo: 以單下划線開頭的表示的是 protected 類型的變量,即保護類型只能允許其本身與子類進行訪問,不能用於 from module import *

  • __foo: 雙下划線的表示的是私有類型(private)的變量, 只能是允許這個類本身進行訪問了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM