Sometimes it is useful to get the number of tasks currently holding the semaphore. Currently, assuming that every call to acquire is paired with a call to release in the same task (e.g. the semaphore is only used in [async] with statements), one can do

    INITIAL_VALUE - sem._value

where INITIAL_VALUE is the value that was used to construct the semaphore and sem is the semaphore object. But, as the name indicates, `sem._value` is intended for internal use only.

I would proposing exposing this value "officially" by adding a property:

    def count(self):
        return self._initial_value - self._value

The implementation would probably have to be a bit more sophisticated than this, because there can be spurious calls to .release() that aren't actually releasing the semaphore because it was never acquired, and it would need to be decided whether reentrant acquires of the semaphore in the same task are counted separately or not.

Perhaps this could be added only to asyncio.BoundedSemaphore.