[英]A way to access context manager variable from class instance in Python?
我會從其他模塊中定義的某些類訪問上下文中定義的一些變量,就像我在以下內容中進行了超級簡化:
在 main.py 中
import class_def1
import class_def2
class Starter(object):
#context manager
def __init__(self):
self.att = 'Myfirst'
def __enter__(self):
return self.att
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Starter() as f:
for name in ('a', 'b', 'c'):
for number in range(2):
c1 = class_def1.MyClass1()
print(c1.attr1)
c2 = class_def2.MyClass2()
print(c2.attr2)
而在 class_def1.py 中:
class MyClass1(object):
global f
global number
def __init__(self):
self.attr1 = ','.join([f,str(number)])
在 class_def2.py 中:
class MyClass2(object):
def __init__(self):
global f
global name
global number
self.attr2 = ','.join([f,name,str(number)])
這段代碼不起作用,我還想避免同時使用“全局”和init輸入參數,因為我有很多要“傳遞”的變量......也許我要求太多了。 有什么建議嗎?
新的考慮
考慮到使用數據類作為 DTO 的可能性(如@Niel Godfrey Ponciano 所建議的),我可以通過這種方式創建一個數據類(或者甚至可能列出其他變量並將默認值設置為零):
@dataclass
class AllInfo:
f: str
with Starter() as f:
info = AllInfo(f)
for name in (a,b,c):
info.name = name
for number in range(2):
info.number = number
c1 = class_def1.MyClass1(info)
print(c1.attr1)
c2 = class_def2.MyClass2(info)
print(c2.attr2)
但是,由於它只是存儲變量的問題(不需要任何方法),因此這等效於:
class AllInfo:
def __init__(self,f):
self.f = f
(在我看來,自動添加到數據類中的repr方法無關緊要)。
但是,在這兩種情況下,我都需要傳遞整個信息集。 可能不是這樣的問題,因為它是一個指針......
關於上下文管理器Starter
的__enter__
方法,如文檔中所述:
此方法返回的值綁定到使用此上下文管理器的 with 語句的 as 子句中的標識符。
返回的值是self.att
:
def __enter__(self):
return self.att # Returns the string "Myfirst"
這意味着f
的值將是字符串“Myfirst”。 如果您想要f
是整個Starter
實例,而不僅僅是屬性Starter.att
,那么請return self
而不是return self.att
。
with Starter() as f: # f will be a string "Myfirst"
現在,下一步是將該上下文管理器變量(來自Starter.att
f
)以及一些迭代值name
和number
傳遞給您的其他類MyClass1
和MyClass2
。 執行此操作的一種標准方法是執行依賴項注入,其中我們將依賴項f
、 name
和value
注入目標客戶端,即MyClass1
和MyClass2
。 簡單來說,設計是MyClass1
和MyClass2
依賴於f
、 name
和value
。
你提到你不想傳遞給init。 但這是執行此操作的標准方法之一,也是最簡單的方法。 如果它更適合您,請繼續下面的解決方案 2,
class Starter(object):
#context manager
def __init__(self):
self.att = 'Myfirst'
def __enter__(self):
return self.att
def __exit__(self, exc_type, exc_val, exc_tb):
pass
class MyClass2(object):
def __init__(self, f, name, number):
text_list = [f, name, str(number)]
self.attr2 = ','.join(text_list)
with Starter() as f:
for name in ('a', 'b', 'c'):
for number in range(2):
# Inject all dependencies to the class
c2 = MyClass2(f, name, number)
print(c2.attr2)
輸出:
Myfirst,a,0
Myfirst,a,1
Myfirst,b,0
Myfirst,b,1
Myfirst,c,0
Myfirst,c,1
如果您有很多變量,但只會使用其中的少數幾個,這可能適用。 最好的用例之一是構建器設計模式。
class Starter(object):
#context manager
def __init__(self):
self.att = 'Myfirst'
def __enter__(self):
return self.att
def __exit__(self, exc_type, exc_val, exc_tb):
pass
class MyClass2(object):
def __init__(self):
self._f = None
self._name = None
self._number = None
# Here, we are using property getters and setters. Of course you can also do it by just directly
# accessing the variable from the outside, just remove the _ in the name to imply that they are
# public and not private as it is now).
@property
def f(self):
return self._f
@f.setter
def f(self, value):
self._f = value
@property
def name(self):
return self._name
@name.setter
def name(self, value):
self._name = value
@property
def number(self):
return self._number
@number.setter
def number(self, value):
self._number = value
@property
def attr2(self):
# Optionally, you can add checks to filter out null variables in the list
text_list = [self.f, self.name, str(self.number)]
return ','.join(text_list)
with Starter() as f:
for name in ('a', 'b', 'c'):
for number in range(2):
c2 = MyClass2()
# Manually inject each dependency to the class. You can add conditionals to select what
# should be injected and what shouldn't.
c2.f = f
c2.name = name
c2.number = number
print(c2.attr2)
輸出:
如果您有很多變量,如@chepner 所建議的,您可以將它們全部(或按相關數據組)放入其自己的數據結構中。 您可以為此目的使用數據類(就像 C/C++ 中的struct
一樣),它將充當您的數據傳輸對象 (DTO) 。
Python 旨在允許在不使用全局聲明的情況下讀取全局變量,如果函數需要修改在全局范圍內聲明的變量,則需要使用全局聲明。 所以下面的代碼應該工作
class MyClass1(object):
def __init__(self):
self.attr1 = ','.join([f,str(number)])
class MyClass2(object):
def __init__(self):
self.attr2 = ','.join([f,name,str(number)])
class Starter(object):
#context manager
def __init__(self):
self.att = 'Myfirst'
def __enter__(self):
return self.att
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Starter() as f:
for name in ('a', 'b', 'c'):
for number in range(2):
c1 = MyClass1()
print(c1.attr1)
c2 = MyClass2()
print(c2.attr2)
>>> Myfirst,0
Myfirst,a,0
Myfirst,1
Myfirst,a,1
Myfirst,0
Myfirst,b,0
Myfirst,1
Myfirst,b,1
Myfirst,0
Myfirst,c,0
Myfirst,1
Myfirst,c,1
如果這沒有幫助,並且您確實想訪問在另一個類的上下文中定義的某個變量,則需要在初始化時傳遞該變量。 像這樣的東西:
class MyClass1(object):
def __init__(self,f):
self.attr1 = ','.join([f,str(number)])
class MyClass2(object):
def __init__(self,f):
self.attr2 = ','.join([f,name,str(number)])
class Starter(object):
#context manager
def __init__(self):
self.att = 'Myfirst'
def __enter__(self):
return self.att
def __exit__(self, exc_type, exc_val, exc_tb):
pass
with Starter() as f:
for name in ('a', 'b', 'c'):
for number in range(2):
c1 = MyClass1(f)
print(c1.attr1)
c2 = MyClass2(f)
print(c2.attr2)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.