The first is more efficient than the second. del foo.bar compiles to two bytecode instructions:
2 0 LOAD_FAST 0 (foo)
3 DELETE_ATTR 0 (bar)
whereas delattr(foo, "bar") takes five:
2 0 LOAD_GLOBAL 0 (delattr)
3 LOAD_FAST 0 (foo)
6 LOAD_CONST 1 ('bar')
9 CALL_FUNCTION 2
12 POP_TOP
This translates into the first running slightly faster (but it’s not a huge difference – .15 μs on my machine).
Like the others have said, you should really only use the second form when the attribute that you’re deleting is determined dynamically.
[Edited to show the bytecode instructions generated inside a function, where the compiler can use LOAD_FAST and LOAD_GLOBAL]