摘錄以下內容供學習,特別聲明內容引自:
https://blog.csdn.net/anshuai_aw1/article/details/82344884
文章主要包括2部分內容,分別是if __name__ == '__main__'的解析和__init__與self的解析。
目錄
1 if __name__ == '__main__'
1.1 摘要
1.2 程序入口
1.2.1 一個.py文件被其他.py文件引用
1.2.2 修改const.py,添加if __name__ == "__main__"
2 __init__與self
2.1 Python中self的含義
2.2 Python中為何要有self
2.3 首先來看一下__init__()和self對象
2.4 如果沒有在__init__中初始化對應的實例變量的話,導致后續引用實例變量會出錯
2.5 在函數中,使用對應的變量,雖然代碼是可以運行的,但是實際上使用的,不是實例中的變量
3 參考文獻
1 if __name__ == '__main__'
1.1 摘要
通俗的理解__name__ == '__main__':假如你叫小明.py,在朋友眼中,你是小明(__name__ == '小明');在你自己眼中,你是你自己(__name__ == '__main__')。
if __name__ == '__main__'的意思是:當.py文件被直接運行時,if __name__ == '__main__'之下的代碼塊將被運行;當.py文件以模塊形式被導入時,if __name__ == '__main__'之下的代碼塊不被運行。
1.2 程序入口
對於很多編程語言來說,程序都必須要有一個入口,比如C,C++,以及完全面向對象的編程語言Java,C#等。如果你接觸過這些語言,對於程序入口這個概念應該很好理解,C,C++都需要有一個main函數作為程序的入口,也就是程序的運行會從main函數開始。同樣,Java,C#必須要有一個包含Main方法的主類,作為程序入口。
而Python則不同,它屬於腳本語言,不像編譯型語言那樣先將程序編譯成二進制再運行,而是動態的逐行解釋運行。也就是從腳本第一行開始運行,沒有統一的入口。
一個Python源碼文件(.py)除了可以被直接運行外,還可以作為模塊(也就是庫),被其他.py文件導入。不管是直接運行還是被導入,.py文件的最頂層代碼都會被運行(Python用縮進來區分代碼層次),而當一個.py文件作為模塊被導入時,我們可能不希望一部分代碼被運行。
1.2.1 一個.py文件被其他.py文件引用
假設我們有一個const.py文件,內容如下:
PI = 3.14
def main():
print("PI:", PI)
main()
# 運行結果:PI: 3.14
現在,我們寫一個用於計算圓面積的area.py文件,area.py文件需要用到const.py文件中的PI變量。從const.py中,我們把PI變量導入area.py:
from const import PI
def calc_round_area(radius):
return PI * (radius ** 2)
def main():
print("round area: ", calc_round_area(2))
main()
'''
運行結果:
PI: 3.14
round area: 12.56
'''
1.2.2 修改const.py,添加if __name__ == "__main__"
我們看到const.py中的main函數也被運行了,實際上我們不希望它被運行,因為const.py提供的main函數只是為了測試常量定義。這時if __name__ == '__main__'派上了用場,我們把const.py改一下,添加if __name__ == "__main__":
PI = 3.14
def main():
print("PI:", PI)
if __name__ == "__main__":
main()
運行const.py,輸出如下:
PI: 3.14
運行area.py,輸出如下:
round area: 12.56
如上,我們可以看到if __name__ == '__main__'相當於Python模擬的程序入口,Python本身並沒有這么規定,這只是一種編碼習慣。由於模塊之間相互引用,不同模塊可能有這樣的定義,而程序入口只有一個。到底哪個程序入口被選中,這取決於__name__的值。
2 __init__與self
2.1 Python中self的含義
self,英文單詞意思很明顯,表示自己,本身。python的self,是個對象(Object),是當前類的實例。
2.2 Python中為何要有self
那就是:
在類的代碼(函數)中,需要訪問當前的實例中的變量和函數的,即,訪問Instance中的:
對應的變量(屬性,property):Instance.ProperyNam,去讀取之前的值和寫入新的值
調用對應函數(function):Instance.function(),即執行對應的動作
-> 而需要訪問實例的變量和調用實例的函數,當然需要對應的實例Instance對象本身
-> 而Python中就規定好了,函數的第一個參數,就必須是實例對象本身,並且建議,約定俗成,把其名字寫為self
-> 所以,我們需要self
而如果沒有用到self,即代碼中,去掉self后,那種寫法所使用到的變量,實際上不是你所希望的,不是真正的實例中的變量和函數,而是的訪問到了其他部分的變量和函數了。甚至會由於沒有合適的初始化實例變量,而導致后續無法訪問的錯誤。
下面,就通過代碼,來演示,如果去掉self,或者沒有合理的使用self,會出現哪些錯誤。
2.3 首先來看一下__init__()和self對象
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies
class Person(object):
def __init__(self, name, lang, website):
self.name = name
self.lang = lang
self.website = website
print('self: ', self)
print('type of self: ', type(self))
'''
未實例化時,運行程序,構造方法沒有運行
'''
p = Person('Tim', 'English', 'www.universal.com')
'''實例化后運行的結果
self: <__main__.Person object at 0x00000000021EAF98>
type of self: <class '__main__.Person'>
'''
可以看出self為實例變量p,是一個Person類型的對象。
class Dog(object):
def __init__(self,name,dog_type):
self.name = name
self.type = dog_type
def sayhi(self):
print("hello,I am a dog, my name is ",self.name)
d = Dog('LiChuang',"京巴") # 實例化
d.sayhi()
以下是d = Dog('LiChuang',"京巴")實例化的示意圖:
2.4 如果沒有在__init__中初始化對應的實例變量的話,導致后續引用實例變量會出錯
如下代碼,完整的演示了,如果沒有在類Class的最初的__init__函數中,正確的初始化實例變量,則會導致后續沒有變量可用,因而出現AttributeError的錯誤:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies
name = 'whole global name'
'''
注:此處全局的變量名,寫成name,只是為了演示而用
實際上,好的編程風格,應該寫成gName之類的名字,
以表示該變量是Global的變量
'''
class Person(object):
def __init__(self, newPersonName):
# self.name = newPersonName
'''
如果此處不寫成self.name
那么此處的name,只是__init__函數中的局部臨時變量name而已
和全局中的name,沒有半毛錢關系
'''
name = newPersonName
'''
此處只是為了代碼演示,而使用了局部變量name,
不過需要注意的是,此處很明顯,由於接下來的代碼也沒有利用到此處的局部變量name
則就導致了,此處的name變量,實際上被浪費了,根本沒有利用到
'''
def sayYourName(self):
'''
此處由於找不到實例中的name變量,所以會報錯:
AttributeError: Person instance has no attribute 'name'
'''
print('My name is %s' %self.name)
def selfAndInitDemo():
personInstance = Person('Tim')
personInstance.sayYourName()
if __name__ == '__main__':
selfAndInitDemo()
''' 未使用self.name時拋異常
Traceback (most recent call last):
File "E:/python14_workspace/s14/day06/test_1.py", line 18, in <module>
selfAndInitDemo()
File "E:/python14_workspace/s14/day06/test_1.py", line 15, in selfAndInitDemo
personInstance.sayYourName()
File "E:/python14_workspace/s14/day06/test_1.py", line 11, in sayYourName
print('My name is %s' %self.name)
AttributeError: 'Person' object has no attribute 'name'
'''
從上述代碼可見,由於在類的初始化(實例化)的__init__函數中,沒有給self.name設置值,使得實例中,根本沒有name這個變量,導致后續再去訪問self.name,就會出現AttributeError的錯誤了。
對應的,如果寫成self.name,則意思就正確了,就是初始化的時候,給實例中新增加,並且正常設置了正確的值newPersionName了,所以后續再去通過self.name,就可以訪問到,當前實例中正確的變量name了。
相應的正確寫法的代碼如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies
name = 'whole global name'
'''
注:此處全局的變量名,寫成name,只是為了演示而用
實際上,好的編程風格,應該寫成gName之類的名字,
以表示該變量是Global的變量
'''
class Person(object):
def __init__(self, newPersonName):
self.name = newPersonName
'''
此處正確的,通過訪問self.name的形式,實現了:
1.給實例中,增加了name變量
2.並且給name賦了初值,為newPersionName
'''
def sayYourName(self):
'''
此處由於開始正確的初始化了self對象,使得其中有了name變量,
所以此處可以正確訪問了name值了
'''
print('My name is %s' %self.name)
def selfAndInitDemo():
personInstance = Person('Tim')
personInstance.sayYourName()
if __name__ == '__main__':
selfAndInitDemo()
'''My name is Tim'''
2.5 在函數中,使用對應的變量,雖然代碼是可以運行的,但是實際上使用的,不是實例中的變量
有時候,雖然你寫的代碼,可以運行,但是使用到的變量,由於沒有加self,實際上是用到的不是實例的變量,而是其他的變量。
此類問題,主要和Python中的變量的作用域有關,但是此處例子中,也和是否使用self有關:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Author: antcolonies
name = 'whole global name'
'''
注:此處全局的變量名,寫成name,只是為了演示而用
實際上,好的編程風格,應該寫成gName之類的名字,
以表示該變量是Global的變量
'''
class Person(object):
name = 'class global name'
def __init__(self, newPersonName):
# self.name = newPersonName
'''
此處,沒有使用self.name
而使得此處的name,實際上仍是局部變量name
雖然此處賦值了,但是后面沒有被利用到,屬於被浪費了的局部變量name
'''
name = newPersonName
def sayYourName(self):
'''
此處,之所以沒有像之前一樣出現:
AttributeError: Person instance has no attribute 'name'
那是因為,雖然當前的實例self中,沒有在__init__中初始化對應的name變量,實例self中沒有對應的name變量
但是由於實例所對應的類Person,有對應的name變量,所以也是可以正常執行代碼的
對應的,此處的self.name,實際上是Person.name
'''
print('My name is %s' %self.name)
print('Name within class Person is actually the global name: %s' %name)
print("Only access Person's name via Person.name = %s" %(Person.name))
def selfAndInitDemo():
personInstance = Person('Tim')
personInstance.sayYourName()
print('whole global name is %s' %name)
if __name__ == '__main__':
selfAndInitDemo()
'''
My name is class global name
Name within class Person is actually the global name: whole global name
Only access Person's name via Person.name = class global name
whole global name is whole global name
'''
其中,可見,此處開始__init__中,沒有給self實例初始化對應的name,
而后面的函數sayYourName中,雖然可以調用到self.name而沒有出現AttributeError錯誤,
但是實際上此處的值,不是所期望的,傳入的name,即"Tim",而是類中的name的值,即"class global name"。
3 參考文獻
【1】如何簡單地理解Python中的if __name__ == '__main__'
【2】Python類中的__init__() 和 self 的解析
————————————————
版權聲明:本文為CSDN博主「anshuai_aw1」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/anshuai_aw1/article/details/82344884
