一、再論靜態(tài)方法和類方法以及實(shí)例方法
-
1.1、類屬性辜荠、實(shí)例屬性
它們?cè)诙x和使用中有所區(qū)別辐宾,而最本質(zhì)的區(qū)別是內(nèi)存中保存的位置不同實(shí)例屬性屬于對(duì)象
-
類屬性屬于類
class Province(object): # 類屬性 country = '中國(guó)' def __init__(self, name): # 實(shí)例屬性 self.name = name # 創(chuàng)建一個(gè)實(shí)例對(duì)象 obj = Province('山東省') # 直接訪問實(shí)例屬性 print(obj.name) # 直接訪問類屬性 Province.country
由上述代碼可以看出【實(shí)例屬性需要通過對(duì)象來(lái)訪問】【類屬性通過類訪問】誉察,在使用上可以看出 實(shí)例屬性和類屬性的歸屬是不同的。
- 類屬性在內(nèi)存中只保存一份
- 實(shí)例屬性在每個(gè)對(duì)象中都要保存一份
應(yīng)用場(chǎng)景:通過類創(chuàng)建實(shí)例對(duì)象時(shí)惹谐,如果每個(gè)對(duì)象需要具有相同名字的屬性氨肌,那么就使用類屬性鸿秆,用一份既可
-
1.2贩虾、實(shí)例方法策精、靜態(tài)方法和類方法 (類里面的三種方法,區(qū)別在于調(diào)用方式不同)
實(shí)例方法:由對(duì)象調(diào)用易茬;至少一個(gè)self參數(shù)酬蹋;執(zhí)行實(shí)例方法時(shí),自動(dòng)將調(diào)用該方法的對(duì)象賦值給self食铐;
類方法:由類調(diào)用匕垫; 至少一個(gè)cls參數(shù);執(zhí)行類方法時(shí)虐呻,自動(dòng)將調(diào)用該方法的類賦值給cls象泵;
-
靜態(tài)方法:由類調(diào)用;無(wú)默認(rèn)參數(shù)斟叼;
class Foo(object): def __init__(self, name): self.name = name def ord_func(self): """ 定義實(shí)例方法偶惠,至少有一個(gè)self參數(shù) """ # print(self.name) print('實(shí)例方法') @classmethod def class_func(cls): """ 定義類方法,至少有一個(gè)cls參數(shù) """ print('類方法') @staticmethod def static_func(): """ 定義靜態(tài)方法 朗涩,無(wú)默認(rèn)參數(shù)""" print('靜態(tài)方法') f = Foo("中國(guó)") # 調(diào)用實(shí)例方法 f.ord_func() # 調(diào)用類方法 Foo.class_func() # 調(diào)用靜態(tài)方法 Foo.static_func()
- 相同點(diǎn):對(duì)于所有的方法而言忽孽,均屬于類,所以 在內(nèi)存中也只保存一份
- 不同點(diǎn):方法調(diào)用者不同谢床、調(diào)用方法時(shí)自動(dòng)傳入的參數(shù)不同兄一。
二、property 屬性
-
2.1识腿、什么是property屬性出革,在方法名的加上property就是 property屬性,在調(diào)用上
dog.run
優(yōu)于dog.eat()
class Dog(object): def eat(self): print("吃") # 定義property屬性 @property def run(self): print("跑") dog = Dog() dog.eat() # 調(diào)用實(shí)例方法 dog.run # 調(diào)用property屬性
- property屬性的定義和調(diào)用要注意一下幾點(diǎn):
定義時(shí)渡讼,在實(shí)例方法的基礎(chǔ)上添加 @property 裝飾器蹋盆;并且僅有一個(gè)self參數(shù)
-
調(diào)用時(shí)费薄,無(wú)需括號(hào)
方法:dog.eat() property屬性:dog.run
- property屬性的定義和調(diào)用要注意一下幾點(diǎn):
-
2.2、property屬性有兩種方式
裝飾器 即:在方法上應(yīng)用裝飾器
類屬性 即:在類中定義值為property對(duì)象的類屬性
-
2.2.1栖雾、裝飾器方式
在類的實(shí)例方法上應(yīng)用@property裝飾器楞抡,Python中的類有經(jīng)典類和新式類,新式類的屬性比經(jīng)典類的屬性豐富析藕。( 如果類繼object召廷,那么該類是新式類 )-
經(jīng)典類,具有一種@property裝飾器
class Goods: @property def price(self): return "laowang" # ############### 調(diào)用 ############### obj = Goods() result = obj.price # 自動(dòng)執(zhí)行 @property 修飾的 price 方法账胧,并獲取方法的返回值 print(result)
-
新式類竞慢,具有三種@property裝飾器
# ############### 定義 ############### class Goods: """python3中默認(rèn)繼承object類 以python2、3執(zhí)行此程序的結(jié)果不同治泥,因?yàn)橹挥性趐ython3中才有@xxx.setter @xxx.deleter """ @property def price(self): print('@property') @price.setter def price(self, value): print('@price.setter') @price.deleter def price(self): print('@price.deleter') # ############### 調(diào)用 ############### obj = Goods() obj.price # 自動(dòng)執(zhí)行 @property 修飾的 price 方法筹煮,并獲取方法的返回值 obj.price = 123 # 自動(dòng)執(zhí)行 @price.setter 修飾的 price 方法,并將 123 賦值給方法的參數(shù) del obj.price # 自動(dòng)執(zhí)行 @price.deleter 修飾的 price 方法
注意
- 經(jīng)典類中的屬性只有一種訪問方式居夹,其對(duì)應(yīng)被 @property 修飾的方法
- 新式類中的屬性有三種訪問方式败潦,并分別對(duì)應(yīng)了三個(gè)被@property、@方法名.setter准脂、@方法名.deleter修飾的方法
由于新式類中具有三種訪問方式劫扒,我們可以根據(jù)它們幾個(gè)屬性的訪問特點(diǎn),分別將三個(gè)方法定義為對(duì)同一個(gè)屬性:獲取狸膏、修改沟饥、刪除
class Goods(object): def __init__(self): # 原價(jià) self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 實(shí)際價(jià)格 = 原價(jià) * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 獲取商品價(jià)格 obj.price = 200 # 修改商品原價(jià) del obj.price # 刪除商品原價(jià)
-
-
2.2.2、類屬性 方式湾戳,創(chuàng)建值為property對(duì)象的類屬性,我比較喜歡這個(gè)方式
-
當(dāng)使用
類屬性
的方式創(chuàng)建property屬性
時(shí)贤旷,經(jīng)典類 和 新式類 無(wú)區(qū)別class Person: def get_name(self): return 'laowang' BAR = property(get_name) obj = Person() reuslt = obj.BAR # 自動(dòng)調(diào)用get_bar方法,并獲取方法的返回值 print(reuslt)
-
property 方法中有個(gè)
四個(gè)參數(shù)
- 第 1 個(gè)參數(shù)是方法名砾脑,調(diào)用
對(duì)象.屬性
時(shí)自動(dòng)觸發(fā)執(zhí)行方法 - 第 2 個(gè)參數(shù)是方法名幼驶,調(diào)用
對(duì)象.屬性 = XXX
時(shí)自動(dòng)觸發(fā)執(zhí)行方法 - 第 3 個(gè)參數(shù)是方法名,調(diào)用
del 對(duì)象.屬性
時(shí)自動(dòng)觸發(fā)執(zhí)行方法 - 第 4 個(gè)參數(shù)是字符串拦止,調(diào)用
對(duì)象.屬性.__doc__
县遣,此參數(shù)是該屬性的描述信息
- 第 1 個(gè)參數(shù)是方法名砾脑,調(diào)用
class Person(object): def __init__(self,name): self.name = name def get_name(self): return self.name def set_name(self,new_name): self.name = new_name print("設(shè)置名字為:%s"%self.name) def del_name(self): del self.name BAR = property(get_name,set_name,del_name,"描述信息...") person = Person("小王") person.BAR # 自動(dòng)調(diào)用第一個(gè)參數(shù)中定義的方法:get_name person.BAR = "小李" # 自動(dòng)調(diào)用第二個(gè)參數(shù)中定義的方法:set_name方法糜颠,并將 "小李" 當(dāng)作參數(shù)傳入 person.del_name # 自動(dòng)調(diào)用第三個(gè)參數(shù)中定義的方法:del_name方法 desc = Person.BAR.__doc__ # 自動(dòng)獲取第四個(gè)參數(shù)中設(shè)置的值:描述信息... print("描述是:%s"%desc)
由于類屬性方式創(chuàng)建 property屬性 具有3種訪問方式汹族,我們可以根據(jù)它們幾個(gè)屬性的訪問特點(diǎn),分別將 三個(gè)方法定義為對(duì)同一個(gè)屬性:獲取其兴、修改顶瞒、刪除,如下商品的價(jià)格
class Goods(object): def __init__(self): # 原價(jià) self.original_price = 100 # 折扣 self.discount = 0.8 def get_price(self): # 實(shí)際價(jià)格 = 原價(jià) * 折扣 new_price = self.original_price * self.discount return new_price def set_price(self, value): self.original_price = value def del_price(self): del self.original_price PRICE = property(get_price, set_price, del_price, '價(jià)格屬性描述...') obj = Goods() obj.PRICE # 獲取商品價(jià)格 obj.PRICE = 200 # 修改商品原價(jià) del obj.PRICE # 刪除商品原價(jià)
-
-
2.3、Django框架中應(yīng)用了property屬性(了解)
WEB框架 Django 的視圖中 request.POST 就是使用的類屬性的方式創(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 self.path = '%s/%s' % (script_name.rstrip('/'), path_info.lstrip('/')) self.META = environ self.META['PATH_INFO'] = path_info self.META['SCRIPT_NAME'] = script_name self.method = environ['REQUEST_METHOD'].upper() _, content_params = cgi.parse_header(environ.get('CONTENT_TYPE', '')) if 'charset' in content_params: try: codecs.lookup(content_params['charset']) except LookupError: pass else: self.encoding = 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') def _get_request(self): warnings.warn('`request.REQUEST` is deprecated, use `request.GET` or ' '`request.POST` instead.', RemovedInDjango19Warning, 2) if not hasattr(self, '_request'): self._request = datastructures.MergeDict(self.POST, self.GET) return self._request @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) def _get_files(self): if not hasattr(self, '_files'): self._load_post_and_files() return self._files # ############### 看這里看這里 ############### POST = property(_get_post, _set_post) FILES = property(_get_files) REQUEST = property(_get_request)
綜上所述
- 定義property屬性共有兩種方式元旬,分別是【裝飾器】和【類屬性】榴徐,而【裝飾器】方式針對(duì)經(jīng)典類和新式類又有所不同守问。
- 通過使用property屬性,能夠簡(jiǎn)化調(diào)用者在獲取數(shù)據(jù)的流程