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中,处理此问题的适当方法是什么?全局变量只是答案吗?如果要调用很多函数,将其作为函数参数传递数十次似乎也不太组织。
答案 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.py
和tdepend.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!'