diff --git a/conans/model/conan_file.py b/conans/model/conan_file.py
index f025e5367..c77ae3263 100644
--- a/conans/model/conan_file.py
+++ b/conans/model/conan_file.py
@@ -22,13 +22,13 @@ def create_options(conanfile):
 
         default_options = getattr(conanfile, "default_options", None)
         if default_options:
-            if isinstance(default_options, (list, tuple)):
+            if isinstance(default_options, (list, tuple, dict)):
                 default_values = OptionsValues(default_options)
             elif isinstance(default_options, str):
                 default_values = OptionsValues.loads(default_options)
             else:
-                raise ConanException("Please define your default_options as list or "
-                                     "multiline string")
+                raise ConanException("Please define your default_options as list, "
+                                     "multiline string or dictionary")
             options.values = default_values
         return options
     except Exception as e:
diff --git a/conans/model/options.py b/conans/model/options.py
index da7cde5b0..51feaa4fb 100644
--- a/conans/model/options.py
+++ b/conans/model/options.py
@@ -1,8 +1,11 @@
-from conans.util.sha import sha1
-from conans.errors import ConanException
+
 import yaml
 import six
 import fnmatch
+from collections import Counter
+
+from conans.util.sha import sha1
+from conans.errors import ConanException
 
 
 _falsey_options = ["false", "none", "0", "off", ""]
@@ -162,19 +165,20 @@ class OptionsValues(object):
 
         # convert tuple "Pkg:option=value", "..." to list of tuples(name, value)
         if isinstance(values, tuple):
-            new_values = []
-            for v in values:
-                option, value = v.split("=", 1)
-                new_values.append((option.strip(), value.strip()))
-            values = new_values
+            values = [item.split("=", 1) for item in values]
+
+        # convert dict {"Pkg:option": "value", "..": "..", ...} to list of tuples (name, value)
+        if isinstance(values, dict):
+            values = [(k, v) for k, v in values.items()]
 
         # handle list of tuples (name, value)
         for (k, v) in values:
+            k = k.strip()
+            v = v.strip() if isinstance(v, six.string_types) else v
             tokens = k.split(":")
             if len(tokens) == 2:
                 package, option = tokens
-                package_values = self._reqs_options.setdefault(package.strip(),
-                                                               PackageOptionValues())
+                package_values = self._reqs_options.setdefault(package.strip(), PackageOptionValues())
                 package_values.add_option(option, v)
             else:
                 self._package_values.add_option(k, v)
@@ -264,14 +268,8 @@ class OptionsValues(object):
         other_option=3
         OtherPack:opt3=12.1
         """
-        result = []
-        for line in text.splitlines():
-            line = line.strip()
-            if not line:
-                continue
-            name, value = line.split("=", 1)
-            result.append((name.strip(), value.strip()))
-        return OptionsValues(result)
+        options = tuple(line.strip() for line in text.splitlines() if line.strip())
+        return OptionsValues(options)
 
     @property
     def sha(self):

Allow specifying default options as a dictionary
To help us debug your issue please explain:

- [x] I've read the [CONTRIBUTING guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).
- [x] I've specified the Conan version, operating system version and any tool that can be relevant.
- [x] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.

Hello,

Looking at the structure of the conanfile.py, I always found it weird why the options were specified as a dictionary, but the default_options as a list of tuples.
This is not an issue for packages that have a small amount of options, but it gets ugly for projects with a lot of options. I always end up doing the following:
```python
_default_options = {
    "shared": True,
    "tools": True,
    ...
}
default_options = [(k, str(v)) for k, v in _default_options.items()]
```
In my opinion, it would be a great enhancement if the default_options would allow specifying values as a dictionary and would make the style of the conanfile.py more uniform.

Software information:
I'm currently using ```Conan version 1.2.0``` on
```
ProductName:    Mac OS X
ProductVersion: 10.13.3
BuildVersion:   17D102
```
with
```
Xcode 9.2
Build version 9C40b
```
and ```Python 3.6.4``` installed from brew
diff --git a/conans/test/integration/options_test.py b/conans/test/integration/options_test.py
index 5ea8211a6..05b59e375 100644
--- a/conans/test/integration/options_test.py
+++ b/conans/test/integration/options_test.py
@@ -65,6 +65,73 @@ zlib/0.1@lasote/testing
         conaninfo = load(os.path.join(client.current_folder, CONANINFO))
         self.assertNotIn("zlib:shared=True", conaninfo)
 
+    def test_default_options(self):
+        client = TestClient()
+        conanfile = """
+from conans import ConanFile
+
+class MyConanFile(ConanFile):
+    name = "MyConanFile"
+    version = "1.0"
+    options = {"config": %s}
+    default_options = "config%s"
+
+    def configure(self):
+        if self.options.config:
+            self.output.info("Boolean evaluation")
+        if self.options.config is None:
+            self.output.info("None evaluation")
+        if self.options.config == "None":
+            self.output.info("String evaluation")
+"""
+        # Using "ANY" as possible options
+        client.save({"conanfile.py": conanfile % ("\"ANY\"", "")})
+        error = client.run("create . danimtb/testing", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("Error while initializing options.", client.out)
+        client.save({"conanfile.py": conanfile % ("\"ANY\"", "=None")})
+        client.run("create . danimtb/testing")
+        self.assertNotIn("Boolean evaluation", client.out)
+        self.assertNotIn("None evaluation", client.out)
+        self.assertIn("String evaluation", client.out)
+
+        # Using None as possible options
+        client.save({"conanfile.py": conanfile % ("[None]", "")})
+        error = client.run("create . danimtb/testing", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("Error while initializing options.", client.out)
+        client.save({"conanfile.py": conanfile % ("[None]", "=None")})
+        client.run("create . danimtb/testing")
+        self.assertNotIn("Boolean evaluation", client.out)
+        self.assertNotIn("None evaluation", client.out)
+        self.assertIn("String evaluation", client.out)
+
+        # Using "None" as possible options
+        client.save({"conanfile.py": conanfile % ("[\"None\"]", "")})
+        error = client.run("create . danimtb/testing", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("Error while initializing options.", client.out)
+        client.save({"conanfile.py": conanfile % ("[\"None\"]", "=None")})
+        client.run("create . danimtb/testing")
+        self.assertNotIn("Boolean evaluation", client.out)
+        self.assertNotIn("None evaluation", client.out)
+        self.assertIn("String evaluation", client.out)
+        client.save({"conanfile.py": conanfile % ("[\"None\"]", "=\\\"None\\\"")})
+        error = client.run("create . danimtb/testing", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("'\"None\"' is not a valid 'options.config' value", client.out)
+
+        # Using "ANY" as possible options and "otherstringvalue" as default
+        client.save({"conanfile.py": conanfile % ("[\"otherstringvalue\"]", "")})
+        error = client.run("create . danimtb/testing", ignore_error=True)
+        self.assertTrue(error)
+        self.assertIn("Error while initializing options.", client.out)
+        client.save({"conanfile.py": conanfile % ("\"ANY\"", "=otherstringvalue")})
+        client.run("create . danimtb/testing")
+        self.assertIn("Boolean evaluation", client.out)
+        self.assertNotIn("None evaluation", client.out)
+        self.assertNotIn("String evaluation", client.out)
+
     def general_scope_options_test(self):
         # https://github.com/conan-io/conan/issues/2538
         client = TestClient()
diff --git a/conans/test/model/options_test.py b/conans/test/model/options_test.py
index c672bf204..6b4a24e2d 100644
--- a/conans/test/model/options_test.py
+++ b/conans/test/model/options_test.py
@@ -1,3 +1,4 @@
+import six
 import unittest
 from conans.model.options import OptionsValues, PackageOptions, Options, PackageOptionValues,\
     option_undefined_msg
@@ -239,6 +240,39 @@ class OptionsValuesTest(unittest.TestCase):
         option_values = OptionsValues(self.sut.as_list())
         self.assertEqual(option_values.dumps(), self.sut.dumps())
 
+    def test_from_dict(self):
+        options_as_dict = dict([item.split('=') for item in self.sut.dumps().splitlines()])
+        option_values = OptionsValues(options_as_dict)
+        self.assertEqual(option_values.dumps(), self.sut.dumps())
+
+    def test_consistency(self):
+        def _check_equal(hs1, hs2, hs3, hs4):
+            opt_values1 = OptionsValues(hs1)
+            opt_values2 = OptionsValues(hs2)
+            opt_values3 = OptionsValues(hs3)
+            opt_values4 = OptionsValues(hs4)
+
+            self.assertEqual(opt_values1.dumps(), opt_values2.dumps())
+            self.assertEqual(opt_values1.dumps(), opt_values3.dumps())
+            self.assertEqual(opt_values1.dumps(), opt_values4.dumps())
+
+        # Check that all possible input options give the same result
+        _check_equal([('opt', 3)],       [('opt', '3'), ],       ('opt=3', ),       {'opt': 3})
+        _check_equal([('opt', True)],    [('opt', 'True'), ],    ('opt=True', ),    {'opt': True})
+        _check_equal([('opt', False)],   [('opt', 'False'), ],   ('opt=False', ),   {'opt': False})
+        _check_equal([('opt', None)],    [('opt', 'None'), ],    ('opt=None', ),    {'opt': None})
+        _check_equal([('opt', 0)],       [('opt', '0'), ],       ('opt=0', ),       {'opt': 0})
+        _check_equal([('opt', '')],      [('opt', ''), ],        ('opt=', ),        {'opt': ''})
+
+        # Check for leading and trailing spaces
+        _check_equal([('  opt  ', 3)], [(' opt  ', '3'), ], ('  opt =3', ), {' opt ': 3})
+        _check_equal([('opt', '  value  ')], [('opt', '  value '), ], ('opt= value  ', ),
+                     {'opt': ' value '})
+
+        # This is expected behaviour:
+        self.assertNotEqual(OptionsValues([('opt', ''), ]).dumps(),
+                            OptionsValues(('opt=""', )).dumps())
+
     def test_dumps(self):
         self.assertEqual(self.sut.dumps(), "\n".join(["optimized=3",
                                                       "static=True",
@@ -265,3 +299,34 @@ class OptionsValuesTest(unittest.TestCase):
                                                       "Poco:new_option=0"]))
         self.assertEqual(self.sut.sha,
                          "2442d43f1d558621069a15ff5968535f818939b5")
+
+    def test_loads_exceptions(self):
+        emsg = "not enough values to unpack" if six.PY3 else "need more than 1 value to unpack"
+        with self.assertRaisesRegexp(ValueError, emsg):
+            OptionsValues.loads("a=2\nconfig\nb=3")
+
+        with self.assertRaisesRegexp(ValueError, emsg):
+            OptionsValues.loads("config\na=2\ncommit\nb=3")
+
+    def test_exceptions_empty_value(self):
+        emsg = "not enough values to unpack" if six.PY3 else "need more than 1 value to unpack"
+        with self.assertRaisesRegexp(ValueError, emsg):
+            OptionsValues("a=2\nconfig\nb=3")
+
+        with self.assertRaisesRegexp(ValueError, emsg):
+            OptionsValues(("a=2", "config"))
+
+        with self.assertRaisesRegexp(ValueError, emsg):
+            OptionsValues([('a', 2), ('config', ), ])
+
+    def test_exceptions_repeated_value(self):
+        try:
+            OptionsValues.loads("a=2\na=12\nb=3").dumps()
+            OptionsValues(("a=2", "b=23", "a=12"))
+            OptionsValues([('a', 2), ('b', True), ('a', '12')])
+        except Exception as e:
+            self.fail("Not expected exception: {}".format(e))
+
+    def test_package_with_spaces(self):
+        self.assertEqual(OptionsValues([('pck2:opt', 50), ]).dumps(),
+                         OptionsValues([('pck2 :opt', 50), ]).dumps())
diff --git a/conans/test/model/transitive_reqs_test.py b/conans/test/model/transitive_reqs_test.py
index 5ef9a24ea..fb867ce48 100644
--- a/conans/test/model/transitive_reqs_test.py
+++ b/conans/test/model/transitive_reqs_test.py
@@ -560,6 +560,17 @@ class HelloConan(ConanFile):
 """
         _assert_conanfile(hello_content_tuple)
 
+        hello_content_dict = """
+from conans import ConanFile
+
+class HelloConan(ConanFile):
+    name = "Hello"
+    version = "1.2"
+    requires = "Say/0.1@user/testing"
+    default_options = {"Say:myoption" : 234, }  # To test dict definition
+"""
+        _assert_conanfile(hello_content_dict)
+
     def test_transitive_two_levels_options(self):
         say_content = """
 from conans import ConanFile

pip install -e .[dev]
parse_log_pytest
requirements.txt
nose nose-cov pytest
apt-get update apt-get install -y gcc
3.6
conans/requirements.txt conans/requirements_server.txt conans/requirements_dev.txt
pytest --no-header -rA --tb=line --color=no -p no:cacheprovider -W ignore::DeprecationWarning
astroid==2.11.7
attrs==22.2.0
beautifulsoup4==4.12.3
bottle==0.12.25
certifi==2021.5.30
charset-normalizer==2.0.12
codecov==2.1.13
colorama==0.3.9
-e git+https://github.com/conan-io/conan.git@82631b05304f07dddfbd9f2cb0721e10fcd43d17#egg=conan
cov-core==1.15.0
coverage==4.2
deprecation==2.0.7
dill==0.3.4
distro==1.1.0
fasteners==0.19
future==0.16.0
idna==3.10
importlib-metadata==4.8.3
iniconfig==1.1.1
isort==5.10.1
lazy-object-proxy==1.7.1
mccabe==0.7.0
mock==1.3.0
node-semver==0.2.0
nose==1.3.7
nose-cov==1.6
packaging==21.3
parameterized==0.8.1
patch==1.16
pbr==6.1.1
platformdirs==2.4.0
pluggy==1.0.0
pluginbase==0.7
py==1.11.0
Pygments==2.14.0
PyJWT==1.7.1
pylint==2.13.9
pyparsing==3.1.4
pytest==7.0.1
PyYAML==3.13
requests==2.27.1
six==1.17.0
soupsieve==2.3.2.post1
tomli==1.2.3
typed-ast==1.5.5
typing_extensions==4.1.1
urllib3==1.26.20
waitress==2.0.0
WebOb==1.8.9
WebTest==2.0.35
wrapt==1.16.0
zipp==3.6.0

name: conan
channels:
  - defaults
  - https://repo.anaconda.com/pkgs/main
  - https://repo.anaconda.com/pkgs/r
  - conda-forge
dependencies:
  - _libgcc_mutex=0.1=main
  - _openmp_mutex=5.1=1_gnu
  - ca-certificates=2025.2.25=h06a4308_0
  - certifi=2021.5.30=py36h06a4308_0
  - ld_impl_linux-64=2.40=h12ee557_0
  - libffi=3.3=he6710b0_2
  - libgcc-ng=11.2.0=h1234567_1
  - libgomp=11.2.0=h1234567_1
  - libstdcxx-ng=11.2.0=h1234567_1
  - ncurses=6.4=h6a678d5_0
  - openssl=1.1.1w=h7f8727e_0
  - pip=21.2.2=py36h06a4308_0
  - python=3.6.13=h12debd9_1
  - readline=8.2=h5eee18b_0
  - setuptools=58.0.4=py36h06a4308_0
  - sqlite=3.45.3=h5eee18b_0
  - tk=8.6.14=h39e8969_0
  - wheel=0.37.1=pyhd3eb1b0_0
  - xz=5.6.4=h5eee18b_1
  - zlib=1.2.13=h5eee18b_1
  - pip:
      - astroid==2.11.7
      - attrs==22.2.0
      - beautifulsoup4==4.12.3
      - bottle==0.12.25
      - charset-normalizer==2.0.12
      - codecov==2.1.13
      - colorama==0.3.9
      - cov-core==1.15.0
      - coverage==4.2
      - deprecation==2.0.7
      - dill==0.3.4
      - distro==1.1.0
      - fasteners==0.19
      - future==0.16.0
      - idna==3.10
      - importlib-metadata==4.8.3
      - iniconfig==1.1.1
      - isort==5.10.1
      - lazy-object-proxy==1.7.1
      - mccabe==0.7.0
      - mock==1.3.0
      - node-semver==0.2.0
      - nose==1.3.7
      - nose-cov==1.6
      - packaging==21.3
      - parameterized==0.8.1
      - patch==1.16
      - pbr==6.1.1
      - platformdirs==2.4.0
      - pluggy==1.0.0
      - pluginbase==0.7
      - py==1.11.0
      - pygments==2.14.0
      - pyjwt==1.7.1
      - pylint==2.13.9
      - pyparsing==3.1.4
      - pytest==7.0.1
      - pyyaml==3.13
      - requests==2.27.1
      - six==1.17.0
      - soupsieve==2.3.2.post1
      - tomli==1.2.3
      - typed-ast==1.5.5
      - typing-extensions==4.1.1
      - urllib3==1.26.20
      - waitress==2.0.0
      - webob==1.8.9
      - webtest==2.0.35
      - wrapt==1.16.0
      - zipp==3.6.0
prefix: /opt/conda/envs/conan

conans/test/model/options_test.py::OptionsValuesTest::test_consistency conans/test/model/options_test.py::OptionsValuesTest::test_from_dict conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_basic_transitive_option
conans/test/integration/options_test.py::OptionsTest::test_default_options
conans/test/model/options_test.py::OptionsTest::test_in conans/test/model/options_test.py::OptionsTest::test_int conans/test/model/options_test.py::OptionsValuesTest::test_dumps conans/test/model/options_test.py::OptionsValuesTest::test_exceptions_empty_value conans/test/model/options_test.py::OptionsValuesTest::test_exceptions_repeated_value conans/test/model/options_test.py::OptionsValuesTest::test_from_list conans/test/model/options_test.py::OptionsValuesTest::test_loads_exceptions conans/test/model/options_test.py::OptionsValuesTest::test_package_with_spaces conans/test/model/options_test.py::OptionsValuesTest::test_sha_constant conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_basic conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_basic_option conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_conditional conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_conditional_diamond conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_dep_requires_clear conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_conflict conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_conflict_error conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_conflict_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_conflict_options_solved conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_conflict_solved conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_no_conflict conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_diamond_no_conflict_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_propagate_indirect_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_remove_build_requires conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_remove_two_build_requires conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_simple_override conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_diamond_private conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_pattern_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_private conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_two_levels conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_two_levels_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_transitive_two_levels_wrong_options conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_version_requires2_change conans/test/model/transitive_reqs_test.py::ConanRequirementsTest::test_version_requires_change conans/test/model/transitive_reqs_test.py::ConanRequirementsOptimizerTest::test_avoid_duplicate_expansion conans/test/model/transitive_reqs_test.py::ConanRequirementsOptimizerTest::test_expand_conflict_options conans/test/model/transitive_reqs_test.py::ConanRequirementsOptimizerTest::test_expand_options conans/test/model/transitive_reqs_test.py::ConanRequirementsOptimizerTest::test_expand_requirements conans/test/model/transitive_reqs_test.py::ConanRequirementsOptimizerTest::test_expand_requirements_direct conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_basic conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_config conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_config_remove conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_config_remove2 conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_errors conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_new_configure conans/test/model/transitive_reqs_test.py::CoreSettingsTest::test_transitive_two_levels_options
conans/model/options.py conans/model/conan_file.py
conans/model/options.py conans/model/conan_file.py