Your convoluted way is pretty much how to do it - I think all the answers will be variations on that theme.
For example, I like to generate the mydf$gender=="F"
indices first:
idx <- which(mydf$gender=="F")
Then I sample from that:
mydf[ sample(idx,3), ]
So in one line (although, you reduce the absurd number of brackets and possibly make your code easier to understand by having multiple lines):
mydf[ sample( which(mydf$gender=='F'), 3 ), ]
While the "wheee I'm a hacker!" part of me prefers the one-liner, the sensible part of me says that even though the two-liner is two lines, it is much more understandable - it's just your choice.