我使用的库需要异步上下文(aioboto3(。我的问题是,我不能在自定义S3StreamingFile
实例上从async with
块之外调用方法。如果我这样做,python会引发一个异常,告诉我HttpClient是None。
我想从外部函数访问S3StreamingFile
的类方法,例如在API路由中。除了S3StreamingFile
类实例之外,我不想(从file_2.py
(向调用方(file_3.py
(返回更多内容。aiobot3相关代码无法移动到file_3.py
。CCD_ 8和CCD_ 9需要包含aioboto3相关逻辑。
我该如何解决这个问题?
不工作代码示例:
# file_1.py
class S3StreamingFile():
def __init__(self, s3_object):
self.s3_object = s3_object
async def size(self):
return await self.s3_object.content_length # raises exception, HttpClient is None
...
# file_2.py
async def get_file():
async with s3.resource(...) as resource:
s3_object = await resource.Object(...)
s3_file = S3StreamingFile(s3_object)
return s3_file
# file_3.py
async def main()
s3_file = await get_file()
size = await s3_file.size() # raises exception, HttpClient is None
工作代码示例:
# file_1.py
class S3StreamingFile():
def __init__(self, s3_object):
self.s3_object = s3_object
async def size(self):
return await self.s3_object.content_length
...
# file_2.py
async def get_file():
async with s3.resource(...) as resource:
s3_object = await resource.Object(...)
s3_file = S3StreamingFile(s3_object)
size = await s3_file.size() # works OK here, HttpClient is available
return s3_file
# file_3.py
async def main()
s3_file = await get_file()
我想从外部函数访问类方法。。。我该如何解决这个问题?
不要。这个库使用异步上下文管理器来处理资源获取/释放。关于上下文管理器的整个要点是,像s3_file.size()
这样的东西只有在您获取了相关资源(这里是s3文件实例(时才有意义。
但是如何在程序的其余部分使用这些数据呢?一般来说,由于您还没有说明程序的其余部分是什么,也没有说明为什么需要这些数据,因此有两种方法:
- 在其他地方获取资源,然后使其在更大的范围内可用,或者
- 让您的其他功能资源知道
在第一种情况下,您会在所有逻辑运行之前获取资源,然后保留它。(这可能看起来像RAII。(这在较小的脚本中可能很有意义,或者当资源被设计为一次只由一个进程保留时。它不适合大部分时间无所事事的代码,或者必须与资源的其他用户共存。(这方面的一个扩展是作为上下文管理器编写自己的代码,并有效地将问题转移到调用堆栈中。如果每个代码路径只处理一个资源,那么这很可能是一种方法。(
在第二种情况下,您可以编写更高级别的函数,使其知道正在访问资源。您可以通过传递资源本身来做到这一点:
def get_file(resource: AcquiredResource) -> FileResource:
...
def get_size(thing: AcquirableResource) -> int:
with thing as resource:
s3_file = get_file(resource)
return s3_file.size
(这里使用虚构的泛型类型来说明这一点(。
或者,您可能想要一个特定资源(某些(属性的静态副本,比如这里的文件,以及构建该副本的步骤。就我个人而言,我可能会将这些存储在dict或本地对象中,以明确我没有处理资源本身。
这里的基本思想是with
块保护对潜在的难以获取的资源的访问。这种安全性内置于库中,但它的代价是必须考虑获取并将其构建到代码流中。