[英]Aren't class member varialbes as bad as global variable?
由於使用了全局變量,我們都知道下面的代碼很糟糕:
a = 3.14
def inc():
global a
a += 1
inc()
b = a
太糟糕了,在 python 中,必須故意聲明 global 以“打破”禁令。 但是以 OO 的名義,下面的代碼怎么是有道理的:
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
A_instance = A()
A_instance.inc()
b = A_instance.a
在類實例的范圍內,成員變量不就是和全局變量一樣嗎? “self”基本上允許任何成員函數不受限制地訪問所有變量,而不管其必要性,使其非常有狀態,容易出錯,並且難以閱讀(基本上是全局變量的所有不良特征)?
我們也知道干凈和更好的方法是:
def inc(_a):
return _a+1
a = 3.14
b = inc(a)
這樣函數 inc() 至少是無狀態的並且具有可預測的行為。 使用類並使其盡可能無狀態的最佳實踐是什么? 或者根據定義,OO 是否總是有狀態的,並且必須完全不使用類進行函數式編程? 我也聽人說@static 方法很笨,破壞封裝,應該避免......
現在self
的概念不被認為是不好的做法的原因是,如果您要創建一個類,該類中的所有內容都應該以一種或另一種方式相關,這通常是通過__init__
dunder 初始化類實例的類屬性方法。 基本上,如果您要創建一個類,那么應該有某種鏈接,如果您願意,則應該有一個全局類,這些類是類屬性
通常的想法是像這樣用self創建類
class A:
def __init__(self):
self.a = 3.14
def inc(self):
self.a += 1
不是經常看到的東西,而是人們選擇了在許多觀點中通常被認為更清潔和更可預測的方式
class A:
def __init__(self, a):
self.a = a
def inc(self):
self.a += 1
有了這個,當您聲明類實例時,您可以更好地控制實際存在的內容,因此類實例用變量聲明
A_instance = A(3.14) #a will be 3.14 in this instance
B_instance = A(3.142) #a will be 3.142 in this instance
等等。 在__init__
函數外部聲明但在類內部聲明的類變量本身有很大不同,看起來像
class A:
a = 22/7
def __init__(self):
....
有了這個a將是整個類中的全局變量(不是實例而是類本身)。 那看起來像什么
class A:
a = 22/7
def __init__(self, item):
self.item = item
A_instance = A(3.14)
B_instance = A(5)
盡管A_instance
和B_instance
是完全不同的, A_instance.item
將等於3.14而B_instance.item
將等於5這兩個都將具有類變量a
為22/7
A_instance.a #this will return a value of 22/7
B_instance.a #this will also return a value of 22/7
因此,除非主動更改,否則類變量在該類的所有實例中保持一致/相同。
要點是,如果您要創建一個類,它應該具有相互交織的特定變量並影響所有特定組的函數,這些是您將函數放入類方法中,因此在類中使用self
並沒有錯如果使用得當
這歸結為您是否需要保存狀態。 如果您確實需要保存狀態,則需要將其保存在某處。 類允許您將狀態與對該狀態進行操作的方法一起保存,並強制實施一個類本地范圍,該范圍比將狀態存儲在全局范圍內更不容易出錯。
作為一個具體的例子,我最近為森林模擬實現了一個 Tree 類。 與樹相關聯的重要變量之一是它的年齡。 樹的年齡應該存儲在哪里? 將其存儲在 Tree 類中比將其存儲在外部更有意義。
如果防止樹的年齡被類外的代碼操縱很重要,我可以為此目的使用 Python 出色的@property
語法,或者不直接通過 Python _varname
變量命名約定。
在類中,是的,樹的年齡對其他方法是可見的,但這是一個相對狹窄的范圍,如果您的類是按照 SOLID 面向對象設計原則編寫的單一職責,那么肯定不類似於全局范圍.
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.