In the original PCI framework ("Conventional PCI") and in PCI-X as well, devices corresponded to "slots", each with its own connectors attached to the same parallel bus. Each slot had a unique ID pin that was asserted during enumeration. The enumeration was essentially asking (for each slot): "Hey, is there anything present in this slot?" The device responded by driving data onto the bus in response to this signal. Lack of response meant no device.
A device could also be a "bridge" which meant that it formed a subordinate bus. That bus would have a separate ID (assigned from the upstream), and would have its own set of slots that were enumerated independently.
PCI-Express (PCIe) is totally different. PCIe isn't really a bus -- as in a resource shared among devices; instead each device has its own individual point-to-point serial connection to its upstream device (and to any downstream devices -- and if it has downstream devices, that means it is functioning as a bridge too). Think of PCIe like a LAN. Each bridge is analogous to a switch, that has a bunch of ports connected to other devices. The other devices may be terminal devices, or they might be other switches (i.e. PCIe bridges).
PCIe was designed in such a way that its conceptual framework and addressing (and hence the behavior provided to software) is compatible with PCI and PCI-X. The implementation though is completely different. In enumerating devices, for example, since it's point-to-point, the only question that needs to be determined at each point in the enumeration is "anything there?" Since each device has its own independent set of wires, the device IDs are essentially all hard-coded (hence each bridge, including the top-level "root complex", tells each device what its device ID will be).
In all cases, the "function" part of the bus/device/function is handled strictly within the peripheral. For example, a dual port NIC controller will often have two functions, one for each port. They can be configured and operated independently, but the data path from CPU to function is the same for both.