gpt4 book ai didi

python - 使用类避免python中的命名空间污染

转载 作者:行者123 更新时间:2023-12-04 17:02:38 25 4
gpt4 key购买 nike

一点背景

我正在编写一个 Python 模块供我自己使用,我正在使用 Python 的 logging模块。有处理程序和格式化程序,甚至我创建的一对函数(在大多数情况下)不会在其他任何地方使用。但是,我仍然希望能够在其他地方访问和修改这些变量(例如,其他紧密耦合的模块或脚本)

一个简单的命名空间

我目前正在做的是使用类定义将所有变量组合在一起,如下所示:

class _Logging:
'''A little namespace for our logging facilities. Don't try to instantiate
it: all it does is group together some logging objects and keep them out of
the global namespace'''
global logger

def __init__(self):
raise TypeError("that's not how this works...")

def gz_log_rotator(source, dest):
'''accept a source filename and a destination filename. copy source to
dest and add gzip compression. for use with
logging.handlers.RotatingFileHandler.rotator.'''
with gzip.open(dest, 'wb', 1) as ofile, open(source, 'rb') as ifile:
ofile.write(ifile.read())
os.remove(source)

def gz_log_namer(name):
'''accept a filename, and return it with ".gz" appended. for use with
logging.handlers.RotatingFileHandler.namer.'''
return name + ".gz"

fmtr = logging.Formatter(
'[%(asctime)s:%(name)s:%(thread)05d:%(levelname)-8s] %(message)s')

gz_rotfile_loghandler = logging.handlers.RotatingFileHandler(
'%s.log' % __name__, mode='a', maxBytes=(1024**2 * 20), backupCount=3)
gz_rotfile_loghandler.setLevel(5)
gz_rotfile_loghandler.setFormatter(fmtr)
gz_rotfile_loghandler.rotator = gz_log_rotator
gz_rotfile_loghandler.namer = gz_log_namer

simplefile_loghandler = logging.FileHandler(
'%s.simple.log' % __name__, mode='w')
simplefile_loghandler.setLevel(15)
simplefile_loghandler.setFormatter(fmtr)

stream_loghandler = logging.StreamHandler()
stream_loghandler.setLevel(25)
stream_loghandler.setFormatter(fmtr)

logger = logging.getLogger(__name__)
logger.setLevel(5)
logger.addHandler(gz_rotfile_loghandler)
logger.addHandler(simplefile_loghandler)
logger.addHandler(stream_loghandler)

然而,pylint 提示(我同意)在类中定义的方法应该是静态方法,或者遵循第一个参数的命名约定(例如 gz_log_rotator(self, dest) ),这不是函数的使用方式,而且会更多令人困惑。

有趣的事实

在此过程中,我还发现了 classmethod 的实例和 staticmethod本身不可调用 (???)。虽然在类命名空间中定义的方法在内部和外部均可调用, classmethodsstaticmethods仅在通过它们的类访问时才可调用(此时它们指的是底层函数,而不是 classmethod/ staticmethod 对象)

>>> class Thing:
... global one_, two_, three_
... def one(self):
... print('one')
... @classmethod
... def two(cls):
... print('two')
... @staticmethod
... def three():
... print('three')
... one_, two_, three_ = one, two, three
...
>>> Thing.one()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: one() missing 1 required positional argument: 'self'
>>> Thing.two()
two
>>> Thing.three()
three
>>> # all as expected
>>> one_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: one() missing 1 required positional argument: 'self'
>>> # so far so good
>>> two_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'classmethod' object is not callable
>>> # what?
>>> three_()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'staticmethod' object is not callable
>>> # ???

我的问题

有没有更好的方法来保存这些变量而不污染我的命名空间?

我的代码工作正常,但它让我觉得有点不干净。我可以定义一个只被调用一次然后立即调用它的函数,但是我要么丢失对我不返回的所有内容的引用,要么我又回到污染全局命名空间。我可以做一切 _hidden ,但我觉得它们应该在逻辑上分组。我可以做 _Logging一个真正的类(class),把我所有的东西放在一个 __init__函数并将我所有的小变量添加到 self ,但这也让人觉得不雅。我可以为此创建另一个文件,但到目前为止,我已经将所有内容都保存在同一个文件中。唯一看起来可口的选择是使两个函数 staticmethods并且只能通过我们的类(即 _Logging.gz_log_namer )来引用它们,但这似乎也是不可能的。

>>> class Thing:
... @staticmethod
... def say_hello():
... print('hello!')
... Thing.say_hello()
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in Thing
AttributeError: type object 'Thing' has no attribute 'say_hello'
>>>

就目前而言,我认为最好的选择是使用无私的方法。

最佳答案

您可以创建一个继承自 staticmethod 的新类类,并添加 __call__类的方法。
例如:

class callablestatic(staticmethod):
def __init__(self, func):
super().__init__(func)
self.func = func
def __call__(self, *args, **kwargs):
# the __call__ method allows you to call the class instance
return self.func(*args, **kwargs)
然后在你的类里面使用它:
class Thing:
@callablestatic
def hello(name):
print(f"hello {name}")
hello("John") # works
但最好创建新文件并将其作为模块导入

关于python - 使用类避免python中的命名空间污染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36708270/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com