【问题标题】:Properties file in python (similar to Java Properties)python中的属性文件(类似于Java Properties)
【发布时间】:2011-04-05 10:52:39
【问题描述】:

给定以下格式(.properties.ini):

propertyName1=propertyValue1
propertyName2=propertyValue2
...
propertyNameN=propertyValueN

对于 Java,有 Properties 类提供解析/与上述格式交互的功能。

pythonstandard 库 (2.x) 中是否有类似的东西?

如果没有,我还有什么其他选择?

【问题讨论】:

标签: python properties configparser


【解决方案1】:

这不完全是属性,但 Python 确实有一个 nice library 用于解析配置文件。另请参阅此配方:A python replacement for java.util.Properties

【讨论】:

  • 对于第二个链接...不再积极开发。 Jesse noller 从这个秘籍创建了一个项目,其中一些修复在这里没有。作者向使用此配方的任何人推荐该项目。 pypi.python.org/pypi/pyjavaproperties
【解决方案2】:

对于.ini 文件,configparser 模块提供与.ini 文件兼容的格式。

无论如何,没有任何东西可用于解析完整的 .properties 文件,当我不得不这样做时,我只需使用 jython(我说的是脚本)。

【讨论】:

  • 如果您不想使用 Jython,pyjavaproperties 似乎是一个选项:bitbucket.org/jnoller/pyjavaproperties
  • java 属性文件不等同于 .ini 文件。 pyjavaproperties 是正确的答案
  • Alex Matelli 在stackoverflow.com/a/2819788/15274 建议了一种使用 ConfigParser 解析 .properties 文件的简单方法
  • bitbucket.org/jnoller/pyjavaproperties 自 2010 年以来一直没有维护。它与 python 3 不兼容。我会使用@pi 链接的解决方案。
  • 既然这里没有提到,让我再补充一下,这不一样。我不能说 Java 或 Py3,也许它适用于简单的键/值。但是字符串插值的语法是不同的。该解决方案提供 Python 格式,即。 %(string)s 而(例如 Ant)我会使用 ${string}。 pymotw.com/2/ConfigParser
【解决方案3】:

This 是 java.util.Propeties 的一对一替换

来自文档:

  def __parse(self, lines):
        """ Parse a list of lines and create
        an internal property dictionary """

        # Every line in the file must consist of either a comment
        # or a key-value pair. A key-value pair is a line consisting
        # of a key which is a combination of non-white space characters
        # The separator character between key-value pairs is a '=',
        # ':' or a whitespace character not including the newline.
        # If the '=' or ':' characters are found, in the line, even
        # keys containing whitespace chars are allowed.

        # A line with only a key according to the rules above is also
        # fine. In such case, the value is considered as the empty string.
        # In order to include characters '=' or ':' in a key or value,
        # they have to be properly escaped using the backslash character.

        # Some examples of valid key-value pairs:
        #
        # key     value
        # key=value
        # key:value
        # key     value1,value2,value3
        # key     value1,value2,value3 \
        #         value4, value5
        # key
        # This key= this value
        # key = value1 value2 value3

        # Any line that starts with a '#' is considerered a comment
        # and skipped. Also any trailing or preceding whitespaces
        # are removed from the key/value.

        # This is a line parser. It parses the
        # contents like by line.

【讨论】:

    【解决方案4】:

    Java 属性文件通常也是有效的 Python 代码。您可以将 myconfig.properties 文件重命名为 myconfig.py。然后像这样导入你的文件

    import myconfig
    

    直接访问属性

    print myconfig.propertyName1
    

    【讨论】:

    • 我喜欢这个想法,但它不适用于包含点的属性,即prop.name="val" 在这种情况下不起作用。
    • A java properties file is valid python code:我必须有所不同。 一些 Java 属性文件将传递有效的python 代码,但肯定不是全部。正如@mmjj 所说,点是个问题。不带引号的文字字符串也是如此。 -1.
    • 一个相当糟糕的主意......因为它被打破了。 Java prop 文件允许用“:”代替“=”;他们在续行后吃空格;他们不引用字符串。这些都不是“有效的 Python”。
    • Java 属性文件通常不会通过有效的 python 代码。一种替代方法是在 python 文件中设置你的属性,并使用有效的 python (例如:MEDIA_ROOT='/foo') ...
    • 这是一个最好避免的hack。当您更改属性并且文件不再是有效的python时,您将度过糟糕的一天。
    【解决方案5】:

    如果您可以选择文件格式,我建议您使用前面提到的 .ini 和 Python 的 ConfigParser。如果您需要与 Java .properties 文件兼容,我已经为它编写了一个名为 jprops 的库。我们使用的是 pyjavaproperties,但在遇到各种限制后,我最终实现了自己的。它完全支持 .properties 格式,包括 unicode 支持和对转义序列的更好支持。 Jprops 还可以解析任何类似文件的对象,而 pyjavaproperties 仅适用于磁盘上的真实文件。

    【讨论】:

    • 我刚刚试了一下。奇迹般有效。为马特古德 +1!
    • 如果您添加 pip install 和代码示例,您的答案将是更好的 pip install jprops,open(path) as fp: properties = jprops.load_properties(fp) print(properties)
    【解决方案6】:

    这是我的项目的链接:https://sourceforge.net/projects/pyproperties/。它是一个库,其中包含处理 Python 3.x 的 *.properties 文件的方法。

    但它不是基于 java.util.Properties

    【讨论】:

      【解决方案7】:

      这就是我在我的项目中所做的:我只是创建了另一个名为 properties.py 的 .py 文件,其中包含我在项目中使用的所有公共变量/属性,并且在任何文件中都需要引用这些变量,把

      from properties import *(or anything you need)
      

      当我经常更改开发位置并且一些常见变量与本地环境相当相关时,使用此方法来保持 svn 和平。对我来说效果很好,但不确定这种方法是否适合正式的开发环境等。

      【讨论】:

        【解决方案8】:

        我能够让它与ConfigParser一起工作,没有人展示任何关于如何做到这一点的示例,所以这里是一个简单的属性文件的python阅读器和属性文件的示例。请注意,扩展名仍然是 .properties,但我必须添加一个类似于您在 .ini 文件中看到的部分标题...有点混蛋,但它有效。

        python 文件:PythonPropertyReader.py

        #!/usr/bin/python    
        import ConfigParser
        config = ConfigParser.RawConfigParser()
        config.read('ConfigFile.properties')
        
        print config.get('DatabaseSection', 'database.dbname');
        

        属性文件:ConfigFile.properties

        [DatabaseSection]
        database.dbname=unitTest
        database.user=root
        database.password=
        

        更多功能,请阅读:https://docs.python.org/2/library/configparser.html

        【讨论】:

        • 在 Python 3 中 ConfigParser 模块已重命名为 configparser。
        • 这适用于 .ini 文件,而不是 .properties 文件,因为它们不包含节,如果找不到任何节头,configParser 将失败。此外,ini 文件可能不包含部分,因此这个 configParser 似乎根本不可靠
        【解决方案9】:

        我使用 ConfigParser 执行此操作,如下所示。该代码假设在放置 BaseTest 的同一目录中有一个名为 config.prop 的文件:

        config.prop

        [CredentialSection]
        app.name=MyAppName
        

        BaseTest.py:

        import unittest
        import ConfigParser
        
        class BaseTest(unittest.TestCase):
            def setUp(self):
                __SECTION = 'CredentialSection'
                config = ConfigParser.ConfigParser()
                config.readfp(open('config.prop'))
                self.__app_name = config.get(__SECTION, 'app.name')
        
            def test1(self):
                print self.__app_name % This should print: MyAppName
        

        【讨论】:

          【解决方案10】:

          我知道这是一个非常古老的问题,但我现在才需要它,我决定实现自己的解决方案,一个纯 python 解决方案,它涵盖了大多数用例(不是全部):

          def load_properties(filepath, sep='=', comment_char='#'):
              """
              Read the file passed as parameter as a properties file.
              """
              props = {}
              with open(filepath, "rt") as f:
                  for line in f:
                      l = line.strip()
                      if l and not l.startswith(comment_char):
                          key_value = l.split(sep)
                          key = key_value[0].strip()
                          value = sep.join(key_value[1:]).strip().strip('"') 
                          props[key] = value 
              return props
          

          您可以将 sep 更改为 ':' 以解析具有以下格式的文件:

          key : value
          

          代码正确解析如下行:

          url = "http://my-host.com"
          name = Paul = Pablo
          # This comment line will be ignored
          

          你会得到一个字典:

          {"url": "http://my-host.com", "name": "Paul = Pablo" }
          

          【讨论】:

          • 一流的解决方案,正是我想要的!
          • 请注意,这不支持与 foo = "bar" # bat 等条目位于同一行的 cmets。
          • @ThomasW 如果我们使用 Java 作为事实上的标准,Properties#load 会将其视为属性foo,其值为"bar" # bat
          • 您认为发布老问题的答案有什么意义?关键是我可以通过在我的一个天蓝色管道中复制粘贴来节省时间,而不是自己实现它。所以谢谢:)
          • 喜欢这个答案!我为处理内联 cmets 所做的唯一更改是将 l = line.strip() 更改为 l = line.split(comment_char)[0].strip(),然后仅检查 l 是否具有值,而不是在 if l: 的后续行中。
          【解决方案11】:

          我创建了一个python模块,它几乎类似于Java的Properties类(实际上它就像春天的PropertyPlaceholderConfigurer,它可以让你使用${variable-reference}来引用已经定义的属性)

          编辑:您可以通过运行命令来安装此软件包(目前已针对 python 3 进行了测试)。
          pip install property

          项目托管在GitHub

          示例:(详细文档可以找到here

          假设您在 my_file.properties 文件中定义了以下属性

          foo = I am awesome
          bar = ${chocolate}-bar
          chocolate = fudge
          

          加载上述属性的代码

          from properties.p import Property
          
          prop = Property()
          # Simply load it into a dictionary
          dic_prop = prop.load_property_files('my_file.properties')
          

          【讨论】:

          • 假设您在 my_file.properties 文件中定义了以下属性 foo = I am awesome bar = ${chocolate}-bar Chocolate = fudge 加载上述属性的代码 prop = Property() prop。 load('path/to/my_file.properties') prop.get('foo') # 我很棒 prop.get('bar') # fudge-bar
          • 完成。希望对你有帮助
          【解决方案12】:
          import json
          f=open('test.json')
          x=json.load(f)
          f.close()
          print(x)
          

          test.json 的内容: {“主机”:“127.0.0.1”,“用户”:“jms”}

          【讨论】:

            【解决方案13】:

            这是我编写的解析文件并将其设置为跳过 cmets 和非键值行的 env 变量添加的开关以指定 hg:d

            • -h 或 --help 打印使用摘要
            • -c 指定标识注释的字符
            • -s prop 文件中键和值之间的分隔符
            • 并指定需要解析的属性文件,例如:python EnvParamSet.py -c # -s = env.properties

              import pipes
              import sys , getopt
              import os.path
              
              class Parsing :
              
                      def __init__(self , seprator , commentChar , propFile):
                      self.seprator = seprator
                      self.commentChar = commentChar
                      self.propFile  = propFile
              
                  def  parseProp(self):
                      prop = open(self.propFile,'rU')
                      for line in prop :
                          if line.startswith(self.commentChar)==False and  line.find(self.seprator) != -1  :
                              keyValue = line.split(self.seprator)
                              key =  keyValue[0].strip() 
                              value = keyValue[1].strip() 
                                      print("export  %s=%s" % (str (key),pipes.quote(str(value))))
              
              
              
              
              class EnvParamSet:
              
                  def main (argv):
              
                      seprator = '='
                      comment =  '#'
              
                      if len(argv)  is 0:
                          print "Please Specify properties file to be parsed "
                          sys.exit()
                      propFile=argv[-1] 
              
              
                      try :
                          opts, args = getopt.getopt(argv, "hs:c:f:", ["help", "seprator=","comment=", "file="])
                      except getopt.GetoptError,e:
                          print str(e)
                          print " possible  arguments  -s <key value sperator > -c < comment char >    <file> \n  Try -h or --help "
                          sys.exit(2)
              
              
                      if os.path.isfile(args[0])==False:
                          print "File doesnt exist "
                          sys.exit()
              
              
                      for opt , arg  in opts :
                          if opt in ("-h" , "--help"):
                              print " hg:d  \n -h or --help print usage summary \n -c Specify char that idetifes comment  \n -s Sperator between key and value in prop file \n  specify file  "
                              sys.exit()
                          elif opt in ("-s" , "--seprator"):
                              seprator = arg 
                          elif opt in ("-c"  , "--comment"):
                              comment  = arg
              
                      p = Parsing( seprator, comment , propFile)
                      p.parseProp()
              
                  if __name__ == "__main__":
                          main(sys.argv[1:])
              

            【讨论】:

              【解决方案14】:

              如果您需要以简单的方式从属性文件中的某个部分读取所有值:

              您的config.properties 文件布局:

              [SECTION_NAME]  
              key1 = value1  
              key2 = value2  
              

              你的代码:

                 import configparser
              
                 config = configparser.RawConfigParser()
                 config.read('path_to_config.properties file')
              
                 details_dict = dict(config.items('SECTION_NAME'))
              

              这将为您提供一个字典,其中键与配置文件中的键及其对应的值相同。

              details_dict 是:

              {'key1':'value1', 'key2':'value2'}
              

              现在获取 key1 的值: details_dict['key1']

              将所有内容放在一个方法中,该方法只从配置文件中读取该部分一次(在程序运行期间第一次调用该方法)。

              def get_config_dict():
                  if not hasattr(get_config_dict, 'config_dict'):
                      get_config_dict.config_dict = dict(config.items('SECTION_NAME'))
                  return get_config_dict.config_dict
              

              现在调用上述函数并获取所需键的值:

              config_details = get_config_dict()
              key_1_value = config_details['key1'] 
              

              ----------------------------------------------- --------------

              扩展上述方法,自动逐段读取,然后按段名后键名访问。

              def get_config_section():
                  if not hasattr(get_config_section, 'section_dict'):
                      get_config_section.section_dict = dict()
              
                      for section in config.sections():
                          get_config_section.section_dict[section] = 
                                           dict(config.items(section))
              
                  return get_config_section.section_dict
              

              访问:

              config_dict = get_config_section()
              
              port = config_dict['DB']['port'] 
              

              (这里 'DB' 是配置文件中的部分名称 并且“端口”是“数据库”部分下的键。)

              【讨论】:

                【解决方案15】:

                您可以在此处定义的ConfigParser.RawConfigParser.readfp 中使用类似文件的对象 -> https://docs.python.org/2/library/configparser.html#ConfigParser.RawConfigParser.readfp

                定义一个覆盖readline 的类,在属性文件的实际内容之前添加一个节名。

                我已将它打包到返回所有已定义属性的dict 的类中。

                import ConfigParser
                
                class PropertiesReader(object):
                
                    def __init__(self, properties_file_name):
                        self.name = properties_file_name
                        self.main_section = 'main'
                
                        # Add dummy section on top
                        self.lines = [ '[%s]\n' % self.main_section ]
                
                        with open(properties_file_name) as f:
                            self.lines.extend(f.readlines())
                
                        # This makes sure that iterator in readfp stops
                        self.lines.append('')
                
                    def readline(self):
                        return self.lines.pop(0)
                
                    def read_properties(self):
                        config = ConfigParser.RawConfigParser()
                
                        # Without next line the property names will be lowercased
                        config.optionxform = str
                
                        config.readfp(self)
                        return dict(config.items(self.main_section))
                
                if __name__ == '__main__':
                    print PropertiesReader('/path/to/file.properties').read_properties()
                

                【讨论】:

                  【解决方案16】:

                  以下 2 行代码显示了如何使用 Python 列表理解来加载“java 样式”属性文件。

                  split_properties=[line.split("=") for line in open('/<path_to_property_file>)]
                  properties={key: value for key,value in split_properties }
                  

                  详情请看下面的帖子 https://ilearnonlinesite.wordpress.com/2017/07/24/reading-property-file-in-python-using-comprehension-and-generators/

                  【讨论】:

                  • 代码没有关闭文件对象,也不欢迎仅链接回答。
                  • 该解决方案不包括多行值或包含等号的值。
                  【解决方案17】:

                  Lightbend 发布了 Typesafe Config 库,它可以解析属性文件以及一些基于 JSON 的扩展。 Lightbend 的库仅适用于 JVM,但它似乎已被广泛采用,并且现在有多种语言的端口,包括 Python:https://github.com/chimpler/pyhocon

                  【讨论】:

                    【解决方案18】:

                    如果你没有多行属性,而且需求很简单,几行代码就可以为你解决:

                    文件t.properties

                    a=b
                    c=d
                    e=f
                    

                    Python 代码:

                    with open("t.properties") as f:
                        l = [line.split("=") for line in f.readlines()]
                        d = {key.strip(): value.strip() for key, value in l}
                    

                    【讨论】:

                    • 谢谢,直截了当!
                    【解决方案19】:

                    可以使用下面的函数,就是@mvallebr的修改代码。它尊重属性文件 cmets,忽略空的新行,并允许检索单个键值。

                    def getProperties(propertiesFile ="/home/memin/.config/customMemin/conf.properties", key=''):
                        """
                        Reads a .properties file and returns the key value pairs as dictionary.
                        if key value is specified, then it will return its value alone.
                        """
                        with open(propertiesFile) as f:
                            l = [line.strip().split("=") for line in f.readlines() if not line.startswith('#') and line.strip()]
                            d = {key.strip(): value.strip() for key, value in l}
                    
                            if key:
                                return d[key]
                            else:
                                return d
                    

                    【讨论】:

                      【解决方案20】:

                      这对我有用。

                      from pyjavaproperties import Properties
                      p = Properties()
                      p.load(open('test.properties'))
                      p.list()
                      print p
                      print p.items()
                      print p['name3']
                      

                      【讨论】:

                      • 请删除这个重复的帖子。顺便说一句,我确实赞成你的另一个;)
                      【解决方案21】:

                      我用过这个,这个库很好用

                      from pyjavaproperties import Properties
                      p = Properties()
                      p.load(open('test.properties'))
                      p.list()
                      print(p)
                      print(p.items())
                      print(p['name3'])
                      p['name3'] = 'changed = value'
                      

                      【讨论】:

                        【解决方案22】:

                        我遵循 configparser 方法,它对我来说效果很好。创建了一个 PropertyReader 文件并在那里使用配置解析器来准备属性以对应每个部分。

                        **使用 Python 2.7

                        PropertyReader.py 文件内容:

                        #!/usr/bin/python
                        import ConfigParser
                        
                        class PropertyReader:
                        
                        def readProperty(self, strSection, strKey):
                            config = ConfigParser.RawConfigParser()
                            config.read('ConfigFile.properties')
                            strValue = config.get(strSection,strKey);
                            print "Value captured for "+strKey+" :"+strValue
                            return strValue
                        

                        读取架构文件的内容:

                        from PropertyReader import *
                        
                        class ReadSchema:
                        
                        print PropertyReader().readProperty('source1_section','source_name1')
                        print PropertyReader().readProperty('source2_section','sn2_sc1_tb')
                        

                        .properties 文件的内容:

                        [source1_section]
                        source_name1:module1
                        sn1_schema:schema1,schema2,schema3
                        sn1_sc1_tb:employee,department,location
                        sn1_sc2_tb:student,college,country
                        
                        [source2_section]
                        source_name1:module2
                        sn2_schema:schema4,schema5,schema6
                        sn2_sc1_tb:employee,department,location
                        sn2_sc2_tb:student,college,country
                        

                        【讨论】:

                        • 这是一个ini文件,属性文件不会没有节头
                        • 似乎不适用于 python 3?我得到AttributeError: type object 'ConfigParser' has no attribute 'RawConfigParser'
                        【解决方案23】:

                        在你的 python 模块中创建一个字典并将所有内容存储到其中并访问它,例如:

                        dict = {
                               'portalPath' : 'www.xyx.com',
                               'elementID': 'submit'}
                        

                        现在要访问它,您只需执行以下操作:

                        submitButton = driver.find_element_by_id(dict['elementID'])
                        

                        【讨论】:

                        • 强烈建议分享一些代码示例。现在你的答案很差
                        • @NikolayShevchenko 很抱歉格式不好,我已经更新了我的答案
                        【解决方案24】:

                        您可以使用参数“fromfile_prefix_chars”和 argparse 从配置文件中读取如下---

                        temp.py

                        parser = argparse.ArgumentParser(fromfile_prefix_chars='#')
                        parser.add_argument('--a')
                        parser.add_argument('--b')
                        args = parser.parse_args()
                        print(args.a)
                        print(args.b)
                        

                        配置文件

                        --a
                        hello
                        --b
                        hello dear
                        

                        运行命令

                        python temp.py "#config"
                        

                        【讨论】:

                          【解决方案25】:

                          我的 Java ini 文件没有节标题,因此我想要一个 dict。所以我只是注入了一个“[ini]”部分,让默认配置库完成它的工作。

                          以eclipse IDE.metadata目录的version.ini文件为例:

                          #Mon Dec 20 07:35:29 CET 2021
                          org.eclipse.core.runtime=2
                          org.eclipse.platform=4.19.0.v20210303-1800
                          
                          # 'injected' ini section
                          [ini]
                          #Mon Dec 20 07:35:29 CET 2021
                          org.eclipse.core.runtime=2
                          org.eclipse.platform=4.19.0.v20210303-1800
                          

                          结果转换为dict:

                          from configparser import ConfigParser
                          
                          @staticmethod
                              def readPropertyFile(path):
                                  # https://stackoverflow.com/questions/3595363/properties-file-in-python-similar-to-java-properties
                                  config = ConfigParser()
                                  s_config= open(path, 'r').read()
                                  s_config="[ini]\n%s" % s_config
                                  # https://stackoverflow.com/a/36841741/1497139
                                  config.read_string(s_config)
                                  items=config.items('ini')
                                  itemDict={}
                                  for key,value in items:
                                      itemDict[key]=value
                                  return itemDict
                          

                          【讨论】:

                          • 注入了一个[ini]?那是什么意思?请出示您的配置文件。
                          • @johnktejik - 请找到按要求添加的示例
                          猜你喜欢
                          • 2011-12-10
                          • 1970-01-01
                          • 2013-09-13
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2012-05-28
                          相关资源
                          最近更新 更多