将一组函数转换为类,与命名和对象有关

时间:2016-03-04 12:58:05

标签: python class

我有很多函数来评估我的配置文件。 (在下面添加一些)

class Struct:
    """Returns an callable structure"""
    def __init__(self, **entries):
        self.__dict__.update(entries)   

def read_config(filename):
    """Reads a config file.
    :param filename: String with path to file name
    :returns dict: Dict structure of config file
    """

    try:
        config_file = open(filename,'r')

        try:
            config = yaml.safe_load(config_file)
        except yaml.YAMLError as e:
                print "Error in configuration file:", e
                sys.exit(e.errno)
        finally:
            config_file.close()
    except ( IOError, OSError ) as e:
        print "{0}: Error while openining configuration: {2}".format(__name__,
                e.errno, e.strerror)
        sys.exit(e.errno)

    c = Struct(**config)

    return c

def get_depot_param(depot,param):
    """Reads the param from configuration file. If does not exist returns the default.
    :param depot: The depot to be read from config file
    :retuns string: String with param
    """
    try:
        p = cfg.depots[depot][param]
    except ( TypeError, KeyError) as e:
        try:
            # We failed to get the project regex. Fetching default.
            p = getattr(cfg, param)
        except KeyError as e:
            # Default not defined
                print "Error in configuration file: {0}: No default {1} defined. Please add a {1} entry on conf file".format(exc, param)
                sys.exit(e.errno)

    return p

读取的conf文件是一个yaml,格式如下:

loglevel: INFO
username: root
password: globalsecret
destdir: /dsk/bkpdir/

# Configurations here overwrites the defaults. The valid ones are:
# username, password, destdir
depots:
    server1:
        password: secret

    server2:
        username: root

    server3:

    server4:
        destdir: /disk2/bkp/

如果未在库中设置配置,则可以使用“全局”配置。因为我创建的get_depot_param会尝试阅读depot param(usernamepassworddstdir和其他人。如果它没有在仓库中找到,请从全局抓取。

我经常将这些函数称为:

# To "initialize" the configurator descriptor
config_filename='backup.cfg'
cfg=read_config(config_filename)

# Calling one attribute from server2 (here I expect receive /dsk/bkpdir/)
get_depot_param('server2','destdir') 

# Calling one attribute from server4 (here I expect receive /disk2/bkp)
get_depot_param('server4','destdir') 

但是我开始将这些函数转换为类似的类:

import errno
import yaml
import sys


class Struct:
    def __init__(self, **entries): 
        self.__dict__.update(entries)

class Config:
    def __init__(self, filename="backup.cfg"):
        try:
            fd = open(filename,'r')

            try:
                yamlcfg = yaml.safe_load(fd)
            except yaml.YAMLError as e:
                    sys.exit(e.errno)
            finally:
                fd.close()
        except ( IOError, OSError ) as e:
            sys.exit(e.errno)

        self.cfg = Struct(**yamlcfg)

    def __getattribute__(self, name):
        try:
            return object.__getattribute__(self, name)
        except AttributeError:
            return self.cfg.__getattribute__(name)


    def depot_param(self,depot,param):
        try:
            self.depot_param = self.cfg.depots[depot][param]
        except ( TypeError, KeyError) as e:
            try:
                self.depot_param = getattr(self.cfg, param)
            except KeyError as e:
                    sys.exit(e.errno)

        return self.depot_param

    def project_param(self,project,param):
        try:
            self.project_param = self.cfg.projects[project][param]
        except ( TypeError, KeyError) as e:
            try:
                self.project_param = getattr(self.cfg, param)
            except KeyError as e:
                sys.exit(e.errno)

        return self.project_param



###################################################################################

if __name__ == '__main__':
    # Read config file to cfg
    config = Config()

    #print config.loglevel
    #print config.depot_param('server1','destdir')
    #print config.depot_param('server2','destdir')
    #print config.depot_param('server3','password')

我收到运行此代码:

# python backup.py 
Traceback (most recent call last):
  File "backup.py", line 59, in <module>
    print config.loglevel
AttributeError: Config instance has no attribute 'loglevel'

1 个答案:

答案 0 :(得分:2)

能够访问班级内的自定义属性并避免错误的命名问题。由您提供,我们将需要使用 getattribute (self,name)来完全控制新类。

一个例子;

class Config:
    def __init__(self):
        self.myItems = {'loglevel':'INFO'}

    def __getattribute__(self, name):
        try:
            # get the class attributes as "priority", before anything else.
            return object.__getattribute__(self, name)
        except AttributeError:
            # attribute was not found, try to get it from our list.
            return self.myItems.get(name)

这将使我们能够做到,

config = Config()
print config.loglevel # output is INFO.

但是,它会在不存在的属性上返回None,您可以通过检查我们的字典是否包含它来转回异常,如果不再重新抛出它。

到目前为止,我还无法找到depot_param返回TypeError的任何问题。

编辑: depot_param中没有问题,在我的工作区中对其进行了测试。但是,以更好的方式快速获取属性的问题可以更快地解决您的问题;

def __getattribute__(self, name):
    try:
        # call superclass for attribute, they come in as priority.
        return object.__getattribute__(self, name)
    except AttributeError:
        # call cfg for attribute, this would be like 'self.cfg.cfg.loglevel'
        # but instead, 'self.cfg.loglevel'
        return self.cfg.__getattribute__(name)