Repository: PyCQA/pyflakes

Issue:
should produce error for attribute hidden by a method
# How to reproduce

```
$ flake8 --version
6.0.0 (mccabe: 0.7.0, pycodestyle: 2.10.0, pyflakes: 3.0.1) CPython 3.11.1 on Linux
$ flake8 ok.py
ok.py:5:5: F811 redefinition of unused 'bar' from line 2
$ flake8 fail.py
```

## `ok.py`

```python
class Foo:
    def bar(self):
        return 0

    def bar(self):
        return 1
```

## `fail.py`

```python
class Foo:
    bar = 0

    def bar(self):
        return 1
```

# Reasons

I do understand that redefinition of variables is a useful pattern, for example [`structlog` Bound Loggers](https://www.structlog.org/en/stable/bound-loggers.html) uses it extensively.

```python
log = structlog.get_logger()
log = log.bind(user=user)
log = log.bind(time=now())
log.info('hello world')
```

## Problems

I spent some time debugging a problem in our code base related to [Factory Boy Lazy Attributes](https://factoryboy.readthedocs.io/en/stable/#lazy-attributes).

```python
class UserFactory(Factory):
    class Meta:
        model = User

    name = 'joe'
    email = LazyAttribute(lambda user: f'{user.name}@example.com')

    # A 1000 lines later

    @post_generation
    def email(self):
        return 'fake@stub.io'
```

## Proposal

Deny attribute redefinition inside class body.

Thoughts?

Discussion:

Patch:
diff --git a/pyflakes/checker.py b/pyflakes/checker.py
index e927715..4d778a8 100644
--- a/pyflakes/checker.py
+++ b/pyflakes/checker.py
@@ -263,6 +263,11 @@ class Definition(Binding):
     """
     A binding that defines a function or a class.
     """
+    def redefines(self, other):
+        return (
+            super().redefines(other) or
+            (isinstance(other, Assignment) and self.name == other.name)
+        )
 
 
 class Builtin(Definition):


Test patch:
diff --git a/pyflakes/test/test_other.py b/pyflakes/test/test_other.py
index 42e99ae..aebdcea 100644
--- a/pyflakes/test/test_other.py
+++ b/pyflakes/test/test_other.py
@@ -118,6 +118,12 @@ class Test(TestCase):
         def a(): pass
         ''', m.RedefinedWhileUnused)
 
+    def test_redefined_function_shadows_variable(self):
+        self.flakes('''
+        x = 1
+        def x(): pass
+        ''', m.RedefinedWhileUnused)
+
     def test_redefinedUnderscoreFunction(self):
         """
         Test that shadowing a function definition named with underscore doesn't