Repository: linw1995/data_extractor

Issue:
The field name is the same as Item's parameter in Item.

```python3
class Parameter(Item):
    name = Field(XPathExtractor("./span[@class='name']"))
    default = Field(XPathExtractor("./span[@class='default']"))

extractor = Parameter(XPathExtractor("./li[@class='parameter']", default=None)
```
the `default=None` parameter overwrites the Field `default = Field(XPathExtractor("./span[@class='default']"))` of Item.

Comments:

Patch:
diff --git a/data_extractor/abc.py b/data_extractor/abc.py
index 0c2434e..115b15e 100644
--- a/data_extractor/abc.py
+++ b/data_extractor/abc.py
@@ -3,6 +3,7 @@
 ====================================
 """
 # Standard Library
+import inspect
 import warnings
 
 from abc import abstractmethod
@@ -20,8 +21,41 @@ class ComplexExtractorMeta(type):
     def __init__(cls, name: str, bases: Tuple[type], attr_dict: Dict[str, Any]):
         super().__init__(name, bases, attr_dict)
         field_names: List[str] = []
+
+        __init_args = inspect.getfullargspec(getattr(cls, "__init__")).args
+
         for key, attr in attr_dict.items():
             if isinstance(type(attr), ComplexExtractorMeta):
+                if key in __init_args:
+                    frame = inspect.currentframe()
+                    assert (
+                        frame is not None
+                    ), "If running in an implementation without Python stack frame support this function returns None."
+                    try:
+                        outer_frame = frame.f_back
+
+                        filename = outer_frame.f_code.co_filename
+                        firstlineno = outer_frame.f_lineno
+                        lines, _ = inspect.findsource(outer_frame)
+
+                        for lineno, line in enumerate(lines[firstlineno:], start=1):
+                            if line.strip().startswith(key):
+                                break
+                        else:  # pragma: no cover
+                            assert False, "This line is never executed."
+
+                        lineno += firstlineno
+                        index = inspect.indentsize(line)
+                    finally:
+                        del outer_frame
+                        del frame
+
+                    line = line.strip()
+                    raise SyntaxError(
+                        f"{line!r} overwriten the parameter {key!r} of '{name}.__init__' method.",
+                        (filename, lineno, index, line),
+                    )
+
                 field_names.append(key)
 
         cls._field_names = field_names


Test patch:
diff --git a/tests/test_exceptions.py b/tests/test_exceptions.py
index decde7e..7f8cbe9 100644
--- a/tests/test_exceptions.py
+++ b/tests/test_exceptions.py
@@ -1,4 +1,5 @@
 # Standard Library
+import inspect
 import textwrap
 
 # Third Party Library
@@ -8,6 +9,7 @@ import pytest
 from data_extractor.exceptions import ExtractError
 from data_extractor.item import Field, Item
 from data_extractor.json import JSONExtractor
+from data_extractor.lxml import XPathExtractor
 
 
 def test_exception_trace(json0):
@@ -47,3 +49,17 @@ def test_exception_trace(json0):
             """
         ).strip()
     )
+
+
+def test_field_name_overwrite_item_parameter():
+    with pytest.raises(SyntaxError) as catch:
+
+        class Parameter(Item):
+            name = Field(XPathExtractor("./span[@class='name']"))
+            default = Field(XPathExtractor("./span[@class='default']"))
+
+    exc = catch.value
+    assert exc.filename == __file__
+    assert exc.lineno == inspect.currentframe().f_lineno - 4
+    assert exc.offset == 12
+    assert exc.text == "default = Field(XPathExtractor(\"./span[@class='default']\"))"