2018-01-22 python面向?qū)ο蠡A(chǔ)(二)

類的成員:

成員有以下:

1疏旨、字段: 可分為靜態(tài)字段 普通字段
2贝咙、方法: 可分為靜態(tài)方法 類方法 普通方法
3虑啤、特性/屬性 普通屬性

注:所有成員中鸳慈,只有普通字段的內(nèi)容保存對象中饱溢,即:根據(jù)此類創(chuàng)建了多少對象,在內(nèi)存中就有多少個普通字段走芋。而其他的成員绩郎,則都是保存在類中,即:無論對象的多少翁逞,在內(nèi)存中只創(chuàng)建一份肋杖。

一、字段

靜態(tài)字段在內(nèi)存中只保存一份挖函。
普通字段在每個對象中都要保存一份状植。

類可以直接訪問靜態(tài)字段,不能直接訪問普通字段怨喘。

二津畸、方法

方法包括:普通方法、靜態(tài)方法和類方法必怜,三種方法在內(nèi)存中都?xì)w屬于類肉拓,區(qū)別在于調(diào)用方式不同。

普通方法:由對象調(diào)用梳庆;至少一個self參數(shù)暖途;執(zhí)行普通方法時卑惜,自動將調(diào)用該方法的對象賦值給self;
類方法:由類調(diào)用丧肴; 至少一個cls參數(shù)残揉;執(zhí)行類方法時胧后,自動將調(diào)用該方法的類復(fù)制給cls芋浮;
靜態(tài)方法:由類調(diào)用;無默認(rèn)參數(shù)壳快;

三纸巷、屬性

對于屬性property的使用方法

class Foo:
    def __init__(self):
        pass

    @property
    def property_func(self):
        return 'xxx'

f = Foo()
f.property_func  ###屬性的調(diào)用  不需要加括號

注意:

屬性存在的意義是:訪問屬性時可以制造出和訪問字段完全相同的假象。

屬性用法一眶痰、

class A:


    def func(self):
        return 'xxx'

    BAR = property(func)

a = A()
res = a.BAR     #####自動調(diào)用property中的個的func方法瘤旨,并獲取返回值
print(res)

屬性的三種用法(新式類):

以下來Python源碼

        property(fget=None, fset=None, fdel=None, doc=None) -> property attribute
        
        fget is a function to be used for getting an attribute value, and likewise
        fset is a function for setting, and fdel a function for del'ing, an
        attribute.  Typical use is to define a managed attribute x:
class C(object):
    def getx(self): return self._x

    def setx(self, value): self._x = value

    def delx(self): del self._x

    x = property(getx, setx, delx, "I'm the 'x' property.")


# Decorators make defining new properties or modifying existing oneseasy:


class C(object):
    @property
    def x(self):       #####獲取屬性
        "I am the 'x' property."
        return self._x

    @x.setter
    def x(self, value):      ###設(shè)置值時,一定要有兩個參數(shù)竖伯。
        self._x = value

    @x.deleter           ##刪除屬性
    def x(self):  
        del self._x

Django 的視圖中 request.POST 就是使用的靜態(tài)字段的方式創(chuàng)建的屬性
請看以下代碼

class WSGIRequest(http.HttpRequest):
    def __init__(self, environ):
        script_name = get_script_name(environ)
        path_info = get_path_info(environ)
        if not path_info:
            # Sometimes PATH_INFO exists, but is empty (e.g. accessing
            # the SCRIPT_NAME URL without a trailing slash). We really need to
            # operate as if they'd requested '/'. Not amazingly nice to force
            # the path like this, but should be harmless.
            path_info = '/'
        self.environ = environ
        self.path_info = path_info
        # be careful to only replace the first slash in the path because of
        # http://test/something and http://test//something being different as
        # stated in http://www.ietf.org/rfc/rfc2396.txt
        self.path = '%s/%s' % (script_name.rstrip('/'),
                               path_info.replace('/', '', 1))
        self.META = environ
        self.META['PATH_INFO'] = path_info
        self.META['SCRIPT_NAME'] = script_name
        self.method = environ['REQUEST_METHOD'].upper()
        self.content_type, self.content_params = cgi.parse_header(environ.get('CONTENT_TYPE', ''))
        if 'charset' in self.content_params:
            try:
                codecs.lookup(self.content_params['charset'])
            except LookupError:
                pass
            else:
                self.encoding = self.content_params['charset']
        self._post_parse_error = False
        try:
            content_length = int(environ.get('CONTENT_LENGTH'))
        except (ValueError, TypeError):
            content_length = 0
        self._stream = LimitedStream(self.environ['wsgi.input'], content_length)
        self._read_started = False
        self.resolver_match = None

    def _get_scheme(self):
        return self.environ.get('wsgi.url_scheme')

    @cached_property
    def GET(self):
        # The WSGI spec says 'QUERY_STRING' may be absent.
        raw_query_string = get_bytes_from_wsgi(self.environ, 'QUERY_STRING', '')
        return http.QueryDict(raw_query_string, encoding=self._encoding)

    def _get_post(self):               ##############################
        if not hasattr(self, '_post'):
            self._load_post_and_files()
        return self._post

    def _set_post(self, post):       ##################################
        self._post = post

    @cached_property
    def COOKIES(self):
        raw_cookie = get_str_from_wsgi(self.environ, 'HTTP_COOKIE', '')
        return http.parse_cookie(raw_cookie)

    @property
    def FILES(self):
        if not hasattr(self, '_files'):
            self._load_post_and_files()
        return self._files

    POST = property(_get_post, _set_post)     ###########################

isinstance 和 issubclass

isinstance(obj,cls)檢查是否obj是否是類 cls 的對象

class Foo(object):
     pass
  
obj = Foo()
  
isinstance(obj, Foo)

issubclass(sub, super)檢查sub類是否是 super 類的派生類

class Foo(object):
    pass
 
class Bar(Foo):
    pass
 
issubclass(Bar, Foo)

strrepr

直接上代碼

class Foo(object):
    def __init__(self,name):

        self.name = name

    def __str__(self):
        return '%s str method in class Foo'%self.name

    def __repr__(self):
        return '%s  repr method in class Foo'%self.name

a = Foo('egon')

print('%s in Foo'%a)
print('%r in Foo'%a)

注意:
1存哲、在一個類中,如果這兩種方法都存在七婴,在執(zhí)行打印實例對象的時候?qū)?zhí)行str祟偷。
2、在語法糖的幫助下打厘,%r 將會調(diào)用repr方法修肠。

反射(自省):

class Foo:
    f = '類的靜態(tài)變量'
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say_hi(self):
        print('hi,%s'%self.name)

obj=Foo('egon',73)

#獲取屬性   getattr
print(getattr(obj,'asdf','doesn\'t exist'))     ####若對象中的屬性不存在户盯,則打印最后后面的結(jié)果嵌施。

#檢測是否含有屬性 hasattr
print(hasattr(obj,'name'))           #注意,第二個參數(shù)要是字符串莽鸭。
print(hasattr(obj,'say_hi'))

# 為對象設(shè)置屬性
setattr(obj,'sb',True)
setattr(obj,'show_name',lambda self:self.name + 'sb')
print(obj.__dict__)
print(obj.show_name(obj))

#刪除對象屬性
delattr(obj,'age')
delattr(obj,'sdf')   ###  屬性不存在則報錯

反射也適用于類

class Foo(object):
    staticField = "old boy"
    def __init__(self):
        self.name = 'wupeiqi'

    def func(self):
        return 'func'

    @staticmethod
    def bar():
        return 'bar'
print(getattr(Foo, 'staticField'))
print(getattr(Foo, 'func'))
print(getattr(Foo, 'bar'))

getitem吗伤、setitemdelitem

class Bar(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 = Bar()

result = obj['k1']       # 自動觸發(fā)執(zhí)行 __getitem__
obj['k2'] = 'parker'      # 自動觸發(fā)執(zhí)行 __setitem__
del obj['k1']               # 自動觸發(fā)執(zhí)行 __delitem__

綁定方法與非綁定方法

類中定義的函數(shù)分成兩大類

綁定方法(綁定給誰硫眨,誰來調(diào)用就自動將他本身當(dāng)作第一個參數(shù)傳入)

1牲芋、綁定到類的方法:用classmethod裝飾器裝飾的方法,為類量身定制類. bound_method(), 自動將類當(dāng)作第一個參數(shù)傳入捺球,(其實對象也能調(diào)用缸浦,但仍將類當(dāng)作第一個參數(shù)傳入)
2、綁定到對象的方法:沒有被任何裝飾器裝飾的方法氮兵。
為對象量身定制裂逐。對象.bound_method(),自動將對象當(dāng)作第一個參數(shù)傳入
(屬于類的函數(shù)泣栈,類可以調(diào)用卜高,但是必須按照函數(shù)的規(guī)則來弥姻,沒有自動傳值這么一說)

非綁定方法:用staticmethod裝飾器裝飾的方法

1、不與類或?qū)ο蠼壎ú籼危惡蛯ο蠖寄苷{(diào)用庭敦,但是沒有自動傳值這么一說,就是一個普通工具而已
注意:與綁定到對象的方法區(qū)分開薪缆,在類中直接定義的函數(shù)秧廉,沒有被任何裝飾器裝飾的,都是綁定到對象的方法拣帽,可不是普通函數(shù)疼电,對象調(diào)用方法會自動傳值,而staticmethod裝飾的方法减拭,不管誰來調(diào)用蔽豺,都沒有自動傳值一說

class

How to get the type of an object without using the type() function?

a = '111'
print(a.__class__)

slots

1.slots是什么:是一個類變量,變量值可以是列表,元祖,或者可迭代對象,也可以是一個字符串(意味著所有實例只有一個數(shù)據(jù)屬性)
2.引子:使用點來訪問屬性本質(zhì)就是在訪問類或者對象的dict屬性字典(類的字典是共享的,而每個實例的是獨立的)
3.為何使用slots:字典會占用大量內(nèi)存,如果你有一個屬性很少的類,但是有很多實例,為了節(jié)省內(nèi)存可以使用slots取代實例的dict
當(dāng)你定義slots后,slots就會為實例使用一種更加緊湊的內(nèi)部表示。實例通過一個很小的固定大小的數(shù)組來構(gòu)建,而不是為每個實例定義一個
字典,這跟元組或列表很類似拧粪。在slots中列出的屬性名在內(nèi)部被映射到這個數(shù)組的指定小標(biāo)上修陡。使用slots一個不好的地方就是我們不能再給實例添加新的屬性了,只能使用在slots中定義的那些屬性名。
4.注意事項:slots的很多特性都依賴于普通的基于字典的實現(xiàn)可霎。另外,定義了slots后的類不再 支持一些普通類特性了,比如多繼承魄鸦。大多數(shù)情況下,你應(yīng)該只在那些經(jīng)常被使用到 的用作數(shù)據(jù)結(jié)構(gòu)的類上定義slots比如在程序中需要創(chuàng)建某個類的幾百萬個實例對象 。
關(guān)于slots的一個常見誤區(qū)是它可以作為一個封裝工具來防止用戶給實例增加新的屬性啥纸。盡管使用slots可以達(dá)到這樣的目的,但是這個并不是它的初衷号杏。 更多的是用來作為一個內(nèi)存優(yōu)化工具。

class A:
    __slots__ = ['Parker','Zhang']


    def __init__(self):
        pass

a = A()

a.Parker = 1
# a.zhang = 12   ##無法給實例添加新屬性

# print(a.__dict__)   #報錯
print(a.__slots__)    ######['Parker', 'Zhang']

總結(jié): slots的好處: 節(jié)省內(nèi)存斯棒,由slots代替dict

enterexit (上下文管理器)

官網(wǎng)鏈接:
https://docs.python.org/2/library/stdtypes.html

Python’s with statement supports the concept of a runtime context defined by a context manager. This is implemented using two separate methods that allow user-defined classes to define a runtime context that is entered before the statement body is executed and exited when the statement ends.

An example of a context manager that returns itself is a file object. File objects return themselves from enter() to allow open() to be used as the context expression in a with statement.

Exit the runtime context and return a Boolean flag indicating if any exception that occurred should be suppressed. If an exception occurred while executing the body of the with statement, the arguments contain the exception type, value and traceback information. Otherwise, all three arguments are None.

Returning a true value from this method will cause the with statement to suppress the exception and continue execution with the statement immediately following the with statement. Otherwise the exception continues propagating after this method has finished executing. Exceptions that occur during execution of this method will replace any exception that occurred in the body of the with statement.

The exception passed in should never be reraised explicitly - instead, this method should return a false value to indicate that the method completed successfully and does not want to suppress the raised exception. This allows context management code (such as contextlib.nested) to easily detect whether or not an __exit__() method has actually failed.

代碼:

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

    def __enter__(self):
        print('enter 方法')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('exit 方法') #######4來到__exit__方法
        print(exc_type)
        print(exc_val)
        print(exc_tb)
        return True  ####return True 后 盾致,with后面的代碼會正常執(zhí)行,打印 'the final'

with Open('a.txt') as f:         ####1.首先進(jìn)入__enter__方法
    print('with 方法')            #####2.來到with 方法
    sss ######3.拋出異常  (要是不拋出異常荣暮,exit方法中的三個參數(shù)值為None)
print('the final')

1.使用with語句的目的就是把代碼塊放入with中執(zhí)行庭惜,with結(jié)束后,自動完成清理工作穗酥,無須手動干預(yù)

2.在需要管理一些資源比如文件护赊,網(wǎng)絡(luò)連接和鎖的編程環(huán)境中,可以在exit中定制自動釋放資源的機(jī)制砾跃,你無須再去關(guān)系這個問題骏啰,這將大有用處

實際應(yīng)用:

class Open(object):
    def __init__(self,name,mode):
        self.name = name
        self.mode = mode

    def __enter__(self):
        self.opened = open(self.name,self.mode)   # 在enter方法中打開文件并返回文件名稱
        return self.opened  # 返回值就是as后面的writer

    def __exit__(self, exc_type, exc_val, exc_tb): #在 close方法中關(guān)閉文件
        self.opened.close()


with Open('mytext.txt','w') as writer:
    writer.write('hello world')

裝飾器實現(xiàn)上下文管理

from contextlib import contextmanager

@contextmanager
def open_file(filename,mode):
    try:
        f = open(filename,mode)
        yield f
    finally:
        f.close()

with open_file('bbb.txt','w') as f:
    f.write('I am so awesome')

print(f.closed)

iter方法

類實例化出的對象本身不可被循環(huán),當(dāng)在父類中加入iter方法后抽高,遍歷一個對象將會執(zhí)行此方法:

class Reverse(object):

    def __init__(self,data):
        self.data = data

    def __iter__(self):
        for i in self.data:
            yield i

data = Reverse([1,2,3,4])
for datum in data:
    print(datum)
class Reverse(object):
    def __init__(self,data):
        self.data = data
        self.index = len(data)

    def __iter__(self):
        return self

    def __next__(self):
        if self.index == 0:
            raise StopIteration
        self.index -= 1
        return self.data[self.index]
rev = Reverse([1,2,3,4])
i = iter(rev)
for char in i:
    print(char)

判斷函數(shù)與方法的區(qū)別:

from types import FunctionType,MethodType

class Foo(object):

    def __init__(self):
        pass

    def func(self):
        pass


obj = Foo()
print(isinstance(obj.func,MethodType))          #True
print(isinstance(obj.func,FunctionType))        #False

print(isinstance(Foo.func,MethodType))      #False
print(isinstance(Foo.func,FunctionType))    #True

方法判耕,無需傳入self參數(shù)

函數(shù),必須手動傳self參數(shù)

元類

class MyType(type):

    def __init__(self, *args,**kwargs):
        print(11)
        super().__init__(self)

    def __call__(self, *args, **kwargs):
        print(22)
        obj = self.__new__(self, *args, **kwargs)
        self.__init__(obj,*args)
        return obj


class Foo(metaclass=MyType):

    def __init__(self, name):
        print(44)
        self.name = name

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

# 第一階段:解釋器從上到下執(zhí)行代碼創(chuàng)建Foo類
# 第二階段:通過Foo類創(chuàng)建obj對象
obj = Foo('Parker')
print(obj)
print(obj.name)

元類總結(jié)翘骂,Python中一切皆對象壁熄,類本質(zhì)上也是對象帚豪,有type創(chuàng)建產(chǎn)生,因此上述代碼可以理解為:

1草丧、在解釋器執(zhí)行到class Foo時狸臣,就會觸發(fā)type的init方法,因而創(chuàng)建Foo這個類
2昌执、在實例化Foo時烛亦,由于Foo(),所以執(zhí)行創(chuàng)建其類(type)的call方法仙蚜,call方法將會調(diào)用init方法來來執(zhí)行call方法此洲,再由call方法來觸發(fā)new方法厂汗,創(chuàng)建類后委粉,開始執(zhí)行Foo類的init方法,初始化對象娶桦。

image.png

isinstance 和 type

image.png

判斷對象是否屬于一個類時贾节,isinstance() 不如type準(zhǔn)確

對象之間的相加

class Foo(object):
    def __init__(self,age):
        self.age = age

    def __add__(self, other):

        return Foo(obj1.age + other.age)

obj1 = Foo(11)
obj2 = Foo(12)
obj3 = obj1 + obj2
print(obj3.age)

私有屬性的方法


class A(object):

    __age = 23
    def __init__(self,name):
        self.__name = name

a = A('Parker')

print(a._A__age)  # 對象._類__字段
print(a._A__name)  
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市衷畦,隨后出現(xiàn)的幾起案子栗涂,更是在濱河造成了極大的恐慌,老刑警劉巖祈争,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斤程,死亡現(xiàn)場離奇詭異,居然都是意外死亡菩混,警方通過查閱死者的電腦和手機(jī)忿墅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沮峡,“玉大人疚脐,你說我怎么就攤上這事⌒细恚” “怎么了棍弄?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疟游。 經(jīng)常有香客問我呼畸,道長,這世上最難降的妖魔是什么颁虐? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任蛮原,我火速辦了婚禮,結(jié)果婚禮上聪廉,老公的妹妹穿的比我還像新娘瞬痘。我一直安慰自己故慈,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布框全。 她就那樣靜靜地躺著察绷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪津辩。 梳的紋絲不亂的頭發(fā)上拆撼,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天,我揣著相機(jī)與錄音喘沿,去河邊找鬼闸度。 笑死,一個胖子當(dāng)著我的面吹牛蚜印,可吹牛的內(nèi)容都是我干的莺禁。 我是一名探鬼主播,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼窄赋,長吁一口氣:“原來是場噩夢啊……” “哼哟冬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起忆绰,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤浩峡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后错敢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體翰灾,經(jīng)...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年稚茅,在試婚紗的時候發(fā)現(xiàn)自己被綠了纸淮。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡峰锁,死狀恐怖萎馅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情虹蒋,我是刑警寧澤糜芳,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站魄衅,受9級特大地震影響峭竣,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晃虫,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一皆撩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦扛吞、人聲如沸呻惕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亚脆。三九已至,卻和暖如春盲泛,著一層夾襖步出監(jiān)牢的瞬間濒持,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工寺滚, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留柑营,地道東北人。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓村视,卻偏偏與公主長得像官套,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蓖议,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,969評論 2 355

推薦閱讀更多精彩內(nèi)容