<!--- Verify first that your issue is not already reported on GitHub -->
<!--- Also test if the latest release and devel branch are affected too -->
<!--- Complete *all* sections as described, this form is processed automatically -->

##### SUMMARY
I've spent the better part of a working day troubleshooting this specific issue, and I don't think this issue is documented or already reported. I have a dictionary, which *sometimes* contains a list of dicts to be looped on, depending on what a key in the inside dict is set to.

So obviously I want to skip the task entirely when that list isn't present, and that is not a problem. But when combined with a check for a key value on item inside the loop, the when condition fails complaining about the list being undefined. Which is hugely annoying as I was checking explicitly for that in the first condition of my when statement.

This is part of a larger playbook which I cannot share, but I've managed to reproduce it with a small test case. I will paste two small playbooks, one that works and one that doesn't. (But in my opinion it should.)

##### ISSUE TYPE
- Bug Report

##### COMPONENT NAME
ansible

##### ANSIBLE VERSION
<!--- Paste verbatim output from "ansible --version" between quotes -->
```
ansible-playbook 2.8.0a1.post0
  config file = /Users/jh/git/ansible_cisco/ansible.cfg
  configured module search path = [u'/Users/jh/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /Users/jh/git/ansible_cisco/lib/python2.7/site-packages/ansible
  executable location = ./bin/ansible-playbook
  python version = 2.7.10 (default, Feb 22 2019, 21:55:15) [GCC 4.2.1 Compatible Apple LLVM 10.0.1 (clang-1001.0.37.14)]
```

##### CONFIGURATION
<!--- Paste verbatim output from "ansible-config dump --only-changed" between quotes -->
```
DEFAULT_STDOUT_CALLBACK(/Users/jh/git/ansible_cisco/ansible.cfg) = skippy
DEFAULT_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
HOST_KEY_CHECKING(/Users/jh/git/ansible_cisco/ansible.cfg) = False
INTERPRETER_PYTHON(/Users/jh/git/ansible_cisco/ansible.cfg) = ./bin/python
PARAMIKO_LOOK_FOR_KEYS(/Users/jh/git/ansible_cisco/ansible.cfg) = False
PERSISTENT_COMMAND_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
PERSISTENT_CONNECT_TIMEOUT(/Users/jh/git/ansible_cisco/ansible.cfg) = 300
RETRY_FILES_ENABLED(/Users/jh/git/ansible_cisco/ansible.cfg) = False
TRANSFORM_INVALID_GROUP_CHARS(/Users/jh/git/ansible_cisco/ansible.cfg) = ignore
```

##### OS / ENVIRONMENT
<!--- Provide all relevant information below, e.g. target OS versions, network device firmware, etc. -->
Running MacOS X Mojave and use a python virtualenv for the sole purpose of having stable versions of everything in this specific repository. None of this should matter though as this seems to be a purely ansible core thing.


##### STEPS TO REPRODUCE
<!--- Describe exactly how to reproduce the problem, using a minimal test-case -->

This playbook will fail with an error about mylist2 not being defined, despite the when statement explicitly checking for that. Remove the and item.test = test part from the when statement and it will work correctly.
```
---
- name: test ansible when defined
  hosts: localhost
  become: no
  gather_facts: no
  vars:
    mydict:
      var1: "val1"
      var2: "val2"
      mylist1:
        - test1
        - test2
  tasks:
    - debug:
        var: mydict

    - debug:
        msg: "This shouldn't be printed."
      with_items: "{{mydict.mylist2}}"
      when: mydict.mylist2 is defined and item.test = 'test'
```

This version, with the parts of the when statement on different lines works:
```
---
- name: test ansible when defined
  hosts: localhost
  become: no
  gather_facts: no
  vars:
    mydict:
      var1: "val1"
      var2: "val2"
      mylist1:
        - test1
        - test2
  tasks:
    - debug:
        var: mydict

    - debug:
        msg: "This shouldn't be printed."
      with_items: "{{mydict.mylist2}}"
      when:
        - mydict.mylist2 is defined
        - item.test = 'test'
```

<!--- HINT: You can paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- Describe what you expected to happen when running the steps above -->

I would expect both cases to work, and just skip the second task.

```
./bin/ansible-playbook works.yml
 [WARNING]: No inventory was parsed, only implicit localhost is available

 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'


PLAY [test ansible when defined] *************************************************************************************

TASK [debug] *********************************************************************************************************
ok: [localhost] => {
    "mydict": {
        "mylist1": [
            "test1",
            "test2"
        ],
        "var1": "val1",
        "var2": "val2"
    }
}

TASK [debug] *********************************************************************************************************

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
```

##### ACTUAL RESULTS
<!--- Describe what actually happened. If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes -->
```
./bin/ansible-playbook fails.yml
 [WARNING]: No inventory was parsed, only implicit localhost is available

 [WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'


PLAY [test ansible when defined] *************************************************************************************

TASK [debug] *********************************************************************************************************
ok: [localhost] => {
    "mydict": {
        "mylist1": [
            "test1",
            "test2"
        ],
        "var1": "val1",
        "var2": "val2"
    }
}

TASK [debug] *********************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "'dict object' has no attribute 'mylist2'"}

PLAY RECAP ***********************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0
```
for k in variables:
                if k.startswith('ansible_%s_' % self._connection._load_name) and k not in options:
                    options['_extras'][k] = templar.template(variables[k])
        task_keys = self._task.dump_attrs()
        if self._play_context.password:
            
            
            
            
            task_keys['password'] = self._play_context.password
        
        self._connection.set_options(task_keys=task_keys, var_options=options)
        varnames.extend(self._set_plugin_options('shell', variables, templar, task_keys))
        if self._connection.become is not None:
            if self._play_context.become_pass:
                
                
                
                
                task_keys['become_pass'] = self._play_context.become_pass
            varnames.extend(self._set_plugin_options('become', variables, templar, task_keys))
            
            for option in ('become_user', 'become_flags', 'become_exe', 'become_pass'):
                try:
                    setattr(self._play_context, option, self._connection.become.get_option(option))
                except KeyError:
                    pass  
            self._play_context.prompt = self._connection.become.prompt
        return varnames
    def _get_action_handler(self, connection, templar):