Python:保留实例

时间:2019-07-07 03:41:07

标签: python python-3.x

Working with PRAW,在主线程中,我创建了一个Reddit实例:

import praw

reddit = praw.Reddit(client_id='my client id',
                     client_secret='my client secret',
                     user_agent='my user agent')

哪个工作正常。

随着代码的增长,我已经创建了各种模块(.py文件),其中.py的主main文件将它们导入到其中。

有时候,这些其他模块需要访问上述实例,而不是创建只会浪费资源或API速率限制的新模块。

在Python 3.6中,处理此问题的适当方法是什么?全局变量只是答案吗?如果要调用很多函数,将其作为函数参数传递数十次似乎也不太组织。

2 个答案:

答案 0 :(得分:6)

您可以将该代码放入自己的模块reddit

reddit.py:

import praw

reddit = praw.Reddit(client_id='my client id',
                     client_secret='my client secret',
                     user_agent='my user agent')

然后像这样使用它。

some_other_module.py

import reddit

for submission in reddit.reddit.subreddit('learnpython').hot(limit=10):
    print(submission.title)

Python只会运行模块the first time it is imported中的代码,然后将其保留在内部,以便将来导入时引用相同的模块。

您可以看到一个小示例,它是创建以下模块。

a.py

import b # j.x is now 4
import c # j.x is now 9
import j # j.x is still 9
print(j.x) # 9 is printed out

j.py

x = 1

b.py

import j
j.x += 3

c.py

import j
j.x += 5

数字9将被打印出来,因为x只是在第一次导入时才被设置为1。将来对所有使用相同x的模块的引用。

在您的情况下,您可以导入main.pytdepend.py reddit.py,它们都将使用完全相同的reddit对象。


仅供参考,您可以使用以下内容查看您距离Reddit的API限制有多近:praw.models.Auth(reddit).limits()

答案 1 :(得分:1)

在我从事的项目中,我遇到了类似的问题,最终出现了3种可能的情况:

方法1

在我们的案例中,经过一些研究,集思广益等,我们决定通过class解决该问题,我想说它工作得很好。在这些情况下,在python中使用类有很多优点。

假设您有tdepend.py定义了一个函数caller(),而您需要其中的reddit实例:

def caller( a ) :
    print( a.reddit )

然后定义一个类,并将reddit定义为该类的属性,以便可以从访问该类对象的任何地方访问它。也就是说,您还可以重新考虑main.py脚本作为类对象,并将所有变量作为其属性,例如:

import praw
from tdepend import caller

class MyClass() :
     def __init__(self, name):
         self.name = name
         self.reddit = praw.Reddit(client_id='my client id',
                                    client_secret='my client secret',
                                    user_agent='my user agent')
        ### define bunch of other stuffs

a = MyClass( "a" )

caller( a )
### bunch of other functions on "a" object

此解决方案还允许您在另一个脚本中定义class并只需导入reddit以及已配置的其他所有内容,并仅操作在其对象上其他位置定义的功能即可(相信我,这使组织和未来需要修改代码,并且记住在哪里定义一切都容易得多。它还允许您传递大量仅传递一个对象的参数,并在不同的对象等中重用相同类型的属性。对此我感到非常满意。

方法2

如果您不想通过class,也可以在这种特殊情况下将其作为参数(function( reddit ))传递,不仅可以避免globals()相关风险而且还可以使您的代码在以后访问时更具可读性(例如,当读取这些“依赖”文件之一时,当您不得不检索地狱reddit的来源时。)

方法3

如果出于某种原因您真的不想既不将其作为参数传递给新的对象,也不希望将类对象作为参数传递(这使您可以将一个其他对象传递给一个参数,则必须使用{{1 }},但请充分了解problems related with global variables,尤其是将来的可读性。

希望有帮助!

对您的评论进行了编辑:

使用类,您可以完全按照您的要求进行操作:使用这种方法,您可以在创建globals()对象时进行API调用,仅此而已,无需调用它,因为您可以看到它保持不变(对于同一对象)。

a

,如果您有一些功能需要访问您在### main.py caller(a) <praw.reddit.Reddit object at 0x7f74d89a1470> # the same a.reddit <praw.reddit.Reddit object at 0x7f74d89a1470> ### if you create another object of course it will be a different one b = MyClass( "b" ) caller(b) <praw.reddit.Reddit object at 0x7f74bf60bc88> 中的MyClass()中的tdepend.py中在tdepend.py中创建的reddit元素,只需在类中定义它们:

tdependclass.py

import praw

class MyClass() :
    def __init__(self, name):
        self.name = name
        self.reddit = praw.Reddit(client_id='my client id',
                                client_secret='my client secret',
                                user_agent='my user agent')
        ### if you want to be called at the initiation of the object
        self.redditStringized = str( self.reddit ) + " hello!"
    ### if you want to be able to decide when calling the function from main
    def stringizeReddit( self, string ) :
        return str( self.reddit ) + " " + string
    ### ... define a bunch of other stuffs and functions ...

main.py

from tdependclass import MyClass
from tdepend import caller

a = MyClass( "a" )

caller( a )
<praw.reddit.Reddit object at 0x7f00c787d668>

a.reddit
<praw.reddit.Reddit object at 0x7f00c787d668>

### called here
a.stringizeReddit( "hello!" )
'<praw.reddit.Reddit object at 0x7f00c787d668> hello!'

### defined at initiation of object
a.redditStringized
'<praw.reddit.Reddit object at 0x7f00c787d668> hello!'