[英]Avoiding namespace pollution in python by using Classes
我正在编写供自己使用的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
实例本身是不可调用的(???)。 虽然在类名称空间中定义的方法可以在内部和staticmethods
均可调用,但仅通过类访问时才可调用classmethods
和staticmethods
方法(此时它们引用基础函数,而不是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
成为一个真正的类,将我所有的东西都放在__init__
函数中,然后将所有小变量_Logging
到self
,但这也_Logging
。 我可以为此创建另一个文件,但是到目前为止,我已经将所有内容保存在同一文件中。 似乎很可口的唯一其他选择是使这两个函数成为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'
>>>
就目前而言,我认为最好的选择是使用无私方法。
很抱歉两年后回答,但这可以帮助某人。
您可以将您的方法设为静态,然后创建另一个静态方法(例如init
),在初始化类后立即对其进行调用。 然后使用setattr
保留对变量的引用。
要设置多个类变量,可以使用
[setattr(Class, name, value) for name,value in locals().items()]
里面的方法。
完整代码:
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'''
def __init__(self):
raise TypeError("that's not how this works...")
@staticmethod
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)
@staticmethod
def gz_log_namer(name):
'''accept a filename, and return it with ".gz" appended. for use with
logging.handlers.RotatingFileHandler.namer.'''
return name + ".gz"
@staticmethod
def init():
global logger
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 = _Logging.gz_log_rotator
gz_rotfile_loghandler.namer = _Logging.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)
[setattr(_Logging, name, value) for name,value in locals().items()]
_Logging.init()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.