您好,登錄后才能下訂單哦!
這篇“python下劃線怎么應(yīng)用”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“python下劃線怎么應(yīng)用”文章吧。
單下劃線一般用于表示臨時變量,在REPL、for循環(huán)和元組拆包等場景中比較常見。
單下劃線在REPL中關(guān)聯(lián)的是上一次計算的非None結(jié)果。
>>> 1+1 2 >>> _ 2 >>> a=2+2 >>> _ 2
1+1,結(jié)果為2,賦值給_;而賦值表達(dá)式a=2+2a為4,但整個表達(dá)式結(jié)果為None,故不會關(guān)聯(lián)到_。這有點類似日常大家使用的計算器中的ANS按鍵,直接保存了上次的計算結(jié)果。
for循環(huán)中_作為臨時變量用。下劃線來指代沒什么意義的變量。例如在如下函數(shù)中,當(dāng)我們只關(guān)心函數(shù)執(zhí)行次數(shù),而不關(guān)心具體次序的情況下,可以使用_作為參數(shù)。
nums = 13
for _ in range(nums):
fun_oper()
第三個用法是元組拆包,賦值的時候可以用_來表示略過的內(nèi)容。如下代碼忽略北京市人口數(shù),只取得名字和區(qū)號。
>>> city,_,code = ('Beijing',21536000,'010')
>>> print(city,code)
Beijing 010
如果需要略過的內(nèi)容多于一個的話,可以使用*開頭的參數(shù),表示忽略多個內(nèi)容。如下代碼忽略面積和人口數(shù),只取得名字和區(qū)號
city,*_,code = ('Beijing',21536000,16410.54,'010')
在一些國際化編程中,_常用來表示翻譯函數(shù)名。例如gettext包使用時:
import gettext
zh = gettext.tranlation('dict','locale',languages=['zh_CN'])
zh.install()
_('hello world')
依據(jù)設(shè)定的字典文件,其返回相應(yīng)的漢字“你好世界”。
_也可用于數(shù)字的分割,這在數(shù)字比較長的時候常用。
>>> a = 9_999_999_999 >>> a 9999999999
a的值自動忽略了下劃線。這樣用_分割數(shù)字,有利于便捷讀取比較大的數(shù)。
變量后面加一個下劃線。主要用于解決命名沖突問題,元編程中遇時Python保留的關(guān)鍵字時,需要臨時創(chuàng)建一個變量的副本時,都可以使用這種機(jī)制。
def type_obj_class(name,class_):
pass
def tag(name,*content,class_):
pass
以上代碼中出現(xiàn)的class是Python的保留關(guān)鍵字,直接使用會報錯,使用下劃線后綴的方式解決了這個問題。
前面一個下劃線,后面加上變量,這是僅供內(nèi)部使用的“保護(hù)變量”。比如函數(shù)、方法或者屬性。
這種保護(hù)不是強(qiáng)制規(guī)定,而是一種程序員的約定,解釋器不做訪問控制。一般來講這些屬性都作為實現(xiàn)細(xì)節(jié)而不需要調(diào)用者關(guān)心,隨時都可能改變,我們編程時雖然能訪問,但是不建議訪問。
這種屬性,只有在導(dǎo)入時,才能發(fā)揮保護(hù)作用。而且必須是from XXX import *
這種導(dǎo)入形式才能發(fā)揮保護(hù)作用。
使用
from XXX import *
是一種通配導(dǎo)入(wildcard import),這是Python社區(qū)不推薦的方式,因為你根本搞不清你到底導(dǎo)入了什么屬性、方法,很可能搞亂你自己的命名空間。PEP8推薦的導(dǎo)入方式是from XXX import aVar , b_func , c_func
這種形式。
比如在下例汽車庫函數(shù)tools.py里定義的“保護(hù)屬性”:發(fā)動機(jī)型號和輪胎型號,這屬于實現(xiàn)細(xì)節(jié),沒必要暴露給用戶。當(dāng)我們使用from tools import *
語句調(diào)用時,其實際并沒有導(dǎo)入所有_開頭的屬性,只導(dǎo)入了普通drive方法。
_moto_type = 'L15b2'
_wheel_type = 'michelin'
def drive():
_start_engine()
_drive_wheel()
def _start_engine():
print('start engine %s'%_moto_type)
def _drive_wheel():
print('drive wheel %s'%_wheel_type)
查看命令空間print(vars())可見,只有drive函數(shù)被導(dǎo)入進(jìn)來,其他下劃線開頭的“私有屬性”都沒有導(dǎo)入進(jìn)來。
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x005CF868>, '__spec__': None, '__annotations__':{}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '.\xiahuaxian.py', '__cached__': None, 'walk': <function walk at 0x01DA8C40>, 'root': '.\__pycache__', '_': [21536000, 16410.54], 'dirs': ['tools.cpython-38.pyc'], 'city': 'Beijing', 'code': '010', 'drive': <function drive at 0x01DBC4A8>}
之所以說是“保護(hù)”并不是“私有”,是因為Python沒有提供解釋器機(jī)制來控制訪問權(quán)限。我們依然可以訪問這些屬性:
import tools
tools._moto_type = 'EA211'
tools.drive()
以上代碼,以越過“保護(hù)屬性”。此外,還有兩種方法能突破這個限制,一種是將“私有屬性”添加到tool.py文件的__all__列表里,使from tools import *
也導(dǎo)入這些本該隱藏的屬性。
__all__ = ['drive','_moto_type','_wheel_type']
另一種是導(dǎo)入時指定“受保護(hù)屬性”名。
from tools import drive,_start_engine
_start_engine()
甚至是,使用import tools
也可以輕易突破保護(hù)限制。所以可見,“保護(hù)屬性”是一種簡單的隱藏機(jī)制,只有在from tools import *
時,由解釋器提供簡單的保護(hù),但是可以輕易突破。這種保護(hù)更多地依賴程序員的共識:不訪問、修改“保護(hù)屬性”。除此之外,有沒有更安全的保護(hù)機(jī)制呢?有,就是下一部分討論的私有變量。
私有屬性解決的之前的保護(hù)屬性保護(hù)力度不夠的問題。變量前面加上兩個下劃線,類里面作為屬性名和方法都可以。兩個下劃線屬性由Python的改寫機(jī)制來實現(xiàn)對這個屬性的保護(hù)。
看下面汽車?yán)又?,品牌為普通屬性,發(fā)動機(jī)為“保護(hù)屬性”,車輪品牌為“私有屬性”。
class Car:
def __init__(self):
self.brand = 'Honda'
self._moto_type = 'L15B2'
self.__wheel_type = 'michelin'
def drive(self):
print('Start the engine %s,drive the wheel %s,I get a running %s car'%
(self._moto_type,
self.__wheel_type,
self.brand))
我們用var(car1)查看下具體屬性值,
['_Car__wheel_type', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_moto_type', 'brand', 'drive']
可見,實例化car1中,普通屬性self.brand和保護(hù)屬性self._moto_type都得以保存,兩個下劃線的私有屬性__wheel_type沒有了。取而代之的是_Car_wheel_type這個屬性。這就是改寫機(jī)制(Name mangling)。兩個下劃線的屬性,被改寫成帶有類名前綴的變量,這樣子類很難明明一個和如此復(fù)雜名字重名的屬性。保證了屬性不被重載,保證了其的私有性。
這里“私有變量”的實現(xiàn),是從解釋器層面給與的改寫,保護(hù)了私有變量。但是這個機(jī)制并非絕對安全,因為我們依然可以通過obj._ClasssName__private來訪問__private私有屬性。
car1.brand = 'Toyota'
car1._moto_type = '6AR-FSE'
car1._Car__wheel_type = 'BRIDGESTONE'
car1.drive()
結(jié)果
Start the engine 6AR-FSE,
drive the wheel BRIDGESTONE,
I get a running Toyota car
可見,對改寫機(jī)制改寫的私有變量,雖然保護(hù)性加強(qiáng)了,但依然可以訪問并修改。只是這種修改,只是一種雜耍般的操作,并不可取。
變量前面兩個下劃線,后面兩個下劃線。這是Python當(dāng)中的魔術(shù)方法,一般是給系統(tǒng)程序調(diào)用的。例如上例中的__init__就是類的初始化魔術(shù)方法,還有支持len函數(shù)的__len__方法,支持上下文管理器協(xié)議的__enter__和__exit__方法,支持迭代器協(xié)議的__iter__方法,支持格式化顯示的__repr__和__str__方法等等。這里我們?yōu)樯侠腃ar類添加魔術(shù)方法__repr__來支持格式化顯示。
def __repr__(self):
return '***Car %s:with %s Engine,%sWheel***'%
(self.brand,self._moto_type,self.__wheel_type)
未添加__repr__魔術(shù)方法之前,print(car1)結(jié)果為<__main__.Car object at 0x0047F7F0>,這個結(jié)果讓人看的一頭霧水,增加repr魔術(shù)方法之后,顯示結(jié)果為***Car Toyota:with 6AR-FSE Engine,BRIDGESTONE Wheel***清晰明了,利于調(diào)試。這就是魔術(shù)方法的功效:支持系統(tǒng)調(diào)用,改進(jìn)用戶類表現(xiàn),增加協(xié)議支持,使用戶類表現(xiàn)得更像系統(tǒng)類。
以下所有魔術(shù)方法均需要在前后加上__,這里省略了這些雙下劃線。
一元運算符 neg pos abs invert
轉(zhuǎn)換 complex int float round inex
算術(shù)運算 add sub mul truediv floordiv mod divmod pow lshift rshift and xor or
算術(shù)運算除and之外,前面再加上r,表示反運算。除dimod外,前面加上i,表示就地運算。
比較 lt le eq ne gt ge
類屬性 getattr getattribute setattr delattr dir get set delete
格式化 bytes hash bool format
類相關(guān) init del new
列表 getitem
迭代器 iter next
上下文管理器 enter exit
以上就是關(guān)于“python下劃線怎么應(yīng)用”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。