Random IP Address Generator
randip.py
I know there are probably better, easier ways to do this.
It was just a bit of a learning exercise for the sake of familiarising myself with Python.
It takes a single argument (positional parameter):
Either a 4
(IPv4) or a 6
(IPv6).
Usage:
./randip.py 4
61.104.170.242
./randip.py 6
4bfc:391d:3ec8:68ef:0ec8:529b:166d:2ece
Code:
#!/usr/bin/env python3
from sys import argv
from random import randint, choice
from string import hexdigits
def random_ip(v):
if v == 4:
octets =
for x in range(4):
octets.append(str(randint(0,255)))
return '.'.join(octets)
elif v == 6:
octets =
for x in range(8):
octet =
for x in range(4):
octet.append(str(choice(hexdigits.lower())))
octets.append(''.join(octet))
return ':'.join(octets)
else:
return
def main():
print(random_ip(int(argv[1])))
if __name__ == '__main__':
main()
python python-3.x random reinventing-the-wheel ip-address
add a comment |
randip.py
I know there are probably better, easier ways to do this.
It was just a bit of a learning exercise for the sake of familiarising myself with Python.
It takes a single argument (positional parameter):
Either a 4
(IPv4) or a 6
(IPv6).
Usage:
./randip.py 4
61.104.170.242
./randip.py 6
4bfc:391d:3ec8:68ef:0ec8:529b:166d:2ece
Code:
#!/usr/bin/env python3
from sys import argv
from random import randint, choice
from string import hexdigits
def random_ip(v):
if v == 4:
octets =
for x in range(4):
octets.append(str(randint(0,255)))
return '.'.join(octets)
elif v == 6:
octets =
for x in range(8):
octet =
for x in range(4):
octet.append(str(choice(hexdigits.lower())))
octets.append(''.join(octet))
return ':'.join(octets)
else:
return
def main():
print(random_ip(int(argv[1])))
if __name__ == '__main__':
main()
python python-3.x random reinventing-the-wheel ip-address
add a comment |
randip.py
I know there are probably better, easier ways to do this.
It was just a bit of a learning exercise for the sake of familiarising myself with Python.
It takes a single argument (positional parameter):
Either a 4
(IPv4) or a 6
(IPv6).
Usage:
./randip.py 4
61.104.170.242
./randip.py 6
4bfc:391d:3ec8:68ef:0ec8:529b:166d:2ece
Code:
#!/usr/bin/env python3
from sys import argv
from random import randint, choice
from string import hexdigits
def random_ip(v):
if v == 4:
octets =
for x in range(4):
octets.append(str(randint(0,255)))
return '.'.join(octets)
elif v == 6:
octets =
for x in range(8):
octet =
for x in range(4):
octet.append(str(choice(hexdigits.lower())))
octets.append(''.join(octet))
return ':'.join(octets)
else:
return
def main():
print(random_ip(int(argv[1])))
if __name__ == '__main__':
main()
python python-3.x random reinventing-the-wheel ip-address
randip.py
I know there are probably better, easier ways to do this.
It was just a bit of a learning exercise for the sake of familiarising myself with Python.
It takes a single argument (positional parameter):
Either a 4
(IPv4) or a 6
(IPv6).
Usage:
./randip.py 4
61.104.170.242
./randip.py 6
4bfc:391d:3ec8:68ef:0ec8:529b:166d:2ece
Code:
#!/usr/bin/env python3
from sys import argv
from random import randint, choice
from string import hexdigits
def random_ip(v):
if v == 4:
octets =
for x in range(4):
octets.append(str(randint(0,255)))
return '.'.join(octets)
elif v == 6:
octets =
for x in range(8):
octet =
for x in range(4):
octet.append(str(choice(hexdigits.lower())))
octets.append(''.join(octet))
return ':'.join(octets)
else:
return
def main():
print(random_ip(int(argv[1])))
if __name__ == '__main__':
main()
python python-3.x random reinventing-the-wheel ip-address
python python-3.x random reinventing-the-wheel ip-address
edited 1 hour ago
asked Jul 26 at 12:05
tjt263
29637
29637
add a comment |
add a comment |
6 Answers
6
active
oldest
votes
Python is often described as a "batteries included" kind of language, and this is no exception.
There's a module just for IP address manipulation and another module to generate random numbers. Put together, they do exactly what you want, in a way that's slightly more readable (IMO).
For this example, I'll assume that the variable v
contains either 4
or 6
.
from random import getrandbits
from ipaddress import IPv4Address, IPv6Address
if v == 4:
bits = getrandbits(32) # generates an integer with 32 random bits
addr = IPv4Address(bits) # instances an IPv4Address object from those bits
addr_str = str(addr) # get the IPv4Address object's string representation
elif v == 6:
bits = getrandbits(128) # generates an integer with 128 random bits
addr = IPv6Address(bits) # instances an IPv6Address object from those bits
# .compressed contains the short version of the IPv6 address
# str(addr) always returns the short address
# .exploded is the opposite of this, always returning the full address with all-zero groups and so on
addr_str = addr.compressed
print(addr_str)
Here, addr_str
will hold a fully random IPv4 or IPv6 address.
You can even generate random addresses from a subnet like this:
from random import getrandbits
from ipaddress import IPv4Network, IPv4Address
# network containing all addresses from 10.0.0.0 to 10.0.0.255
subnet = IPv4Network("10.0.0.0/24")
# subnet.max_prefixlen contains 32 for IPv4 subnets and 128 for IPv6 subnets
# subnet.prefixlen is 24 in this case, so we'll generate only 8 random bits
bits = getrandbits(subnet.max_prefixlen - subnet.prefixlen)
# here, we combine the subnet and the random bits
# to get an IP address from the previously specified subnet
addr = IPv4Address(subnet.network_address + bits)
addr_str = str(addr)
print(addr_str)
Here, addr_str
will always contain IP addresses like 10.0.0.184
, 10.0.0.42
and so on. It works the same way with IPv6 addresses, except in that case you'd have to import IPv6Network
and IPv6Address
instead.
7
Nice solution - did you consider pushingaddr_str = addr.compressed
to after the conditional?
– cmh
Jul 26 at 15:07
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
|
show 5 more comments
Here are a few ideas about your code.
Check for command line arguments
The code fails with an exception if it's invoked with no command line arguments because it attempts to use argv[1]
and there isn't any. I'd suggest that it would be nice to print a "usage" message if the user enters either an invalid or no argument.
Use a list comprehension
List comprehensions are extremely useful and very Pythonic. It's really good to become proficient with them. Here's how to use one to generate a random IPv4 address:
'.'.join([str(randint(0,255)) for x in range(4)])
And an IPv6 address is a little trickier because we need hex digits.
':'.join([hex(randint(2**16,2**17))[-4:] for x in range(8)])
That works because randint
generates a number in the range 0x10000 to 0x20000 and we then pick off the last four hex digits.
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
you can use0x10000
and0x20000
instead of2**16
and2**17
for better readability.
– Mathias Ettinger
Jul 26 at 13:40
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
add a comment |
For someone not familiar with Python, you have picked pretty good habits. Not everyone uses functions or the if __name__ == '__main__'
guard first try.
That being said, I think it would make more sense to provide 2 functions instead of a single one: random_ipv4
and random_ipv6
.
You could also feed generator expressions to join
. They are both faster to process than +
for
+ append
and easier to read:
def random_ipv4():
return '.'.join(str(randint(0,255)) for _ in range(4))
def random_ipv6():
return ':'.join(
''.join(choice(hexdigits).lower() for _ in range(4))
for _ in range(8)
)
The only thing left being to properly validate that the input is either 4 or 6:
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit('Usage: python random_ip.py VERSION')
version = sys.argv[1]
if version == '4':
print(random_ipv4())
elif version == '6':
print(random_ipv6())
else:
sys.exit('VERSION should be 4 or 6, not {}'.format(version))
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But forjoin
it shouldn't matter much as the current implementation convert the input to a list right away.
– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates5.792979179001122
seconds for 1 million calls torandom_ipv4
using a generator expression and5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.
– Mathias Ettinger
Jul 26 at 15:01
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
add a comment |
Check for invalid outputs, and regenerate them.
It's possible that you'll produce an output that's reserved for a particular purpose, such as loopback (127.0.0.1
or ::1
) or broadcast (255.255.255.255
, ff02::1
, ff02::2
). Build in knowledge of such addresses, and if you find you've produced one, then replace it. You can do that recursively:
def make_address(v):
address = random_ip(v)
if is_reserved(address):
return make_address(v)
return address
2
There is no need for this to be recursive. It might as well be awhile is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...
– Graipher
Jul 26 at 15:20
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
add a comment |
Validate the input: At present, your program
- aborts with
IndexError
if called without arguments, - aborts with
ValueError
if called with a non-integer argument, - prints
None
if called with an integer argument that is not4
or6
.
Missing or invalid arguments should print a helpful error message.
Most Unix command-line tools print the message to the standard error
and terminate with a non-zero exit status in the case of a failure.
It would be easier to compare the given argument against the
strings "4"
and "6"
instead of converting it to an integer
(which can fail).
Use list comprehension instead of appending to an array in a loop.
Use _
as iterator variable if the concrete value is not needed.
As an example, the "IPv4" case can be implemented as
if v == 4:
return '.'.join(str(randint(0,255)) for _ in range(4))
Why_
? Is that a thing people do? I've never seen it before.
– tjt263
Jul 26 at 17:45
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
add a comment |
Since you already got a couple of answers telling you to validate your inputs, here is a way how to do it using the argparse
module:
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-v',
type=int,
choices=(4, 6),
default=4,
help="Whether to generate a random IPv4 or IPv6 address. Default: IPv4.")
args = parser.parse_args()
print(random_ip(args.v))
You can then use it on the command line like this:
./randip
./randip -v 4
./randip -v4
./randip -v 6
If you do anything else, a helpful usage message is printed:
usage: [-h] [-v {4,6}]
optional arguments:
-h, --help show this help message and exit
-v {4,6} Whether to generate a random IPv4 or IPv6 address. Default:
IPv4.
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200337%2frandom-ip-address-generator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
6 Answers
6
active
oldest
votes
6 Answers
6
active
oldest
votes
active
oldest
votes
active
oldest
votes
Python is often described as a "batteries included" kind of language, and this is no exception.
There's a module just for IP address manipulation and another module to generate random numbers. Put together, they do exactly what you want, in a way that's slightly more readable (IMO).
For this example, I'll assume that the variable v
contains either 4
or 6
.
from random import getrandbits
from ipaddress import IPv4Address, IPv6Address
if v == 4:
bits = getrandbits(32) # generates an integer with 32 random bits
addr = IPv4Address(bits) # instances an IPv4Address object from those bits
addr_str = str(addr) # get the IPv4Address object's string representation
elif v == 6:
bits = getrandbits(128) # generates an integer with 128 random bits
addr = IPv6Address(bits) # instances an IPv6Address object from those bits
# .compressed contains the short version of the IPv6 address
# str(addr) always returns the short address
# .exploded is the opposite of this, always returning the full address with all-zero groups and so on
addr_str = addr.compressed
print(addr_str)
Here, addr_str
will hold a fully random IPv4 or IPv6 address.
You can even generate random addresses from a subnet like this:
from random import getrandbits
from ipaddress import IPv4Network, IPv4Address
# network containing all addresses from 10.0.0.0 to 10.0.0.255
subnet = IPv4Network("10.0.0.0/24")
# subnet.max_prefixlen contains 32 for IPv4 subnets and 128 for IPv6 subnets
# subnet.prefixlen is 24 in this case, so we'll generate only 8 random bits
bits = getrandbits(subnet.max_prefixlen - subnet.prefixlen)
# here, we combine the subnet and the random bits
# to get an IP address from the previously specified subnet
addr = IPv4Address(subnet.network_address + bits)
addr_str = str(addr)
print(addr_str)
Here, addr_str
will always contain IP addresses like 10.0.0.184
, 10.0.0.42
and so on. It works the same way with IPv6 addresses, except in that case you'd have to import IPv6Network
and IPv6Address
instead.
7
Nice solution - did you consider pushingaddr_str = addr.compressed
to after the conditional?
– cmh
Jul 26 at 15:07
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
|
show 5 more comments
Python is often described as a "batteries included" kind of language, and this is no exception.
There's a module just for IP address manipulation and another module to generate random numbers. Put together, they do exactly what you want, in a way that's slightly more readable (IMO).
For this example, I'll assume that the variable v
contains either 4
or 6
.
from random import getrandbits
from ipaddress import IPv4Address, IPv6Address
if v == 4:
bits = getrandbits(32) # generates an integer with 32 random bits
addr = IPv4Address(bits) # instances an IPv4Address object from those bits
addr_str = str(addr) # get the IPv4Address object's string representation
elif v == 6:
bits = getrandbits(128) # generates an integer with 128 random bits
addr = IPv6Address(bits) # instances an IPv6Address object from those bits
# .compressed contains the short version of the IPv6 address
# str(addr) always returns the short address
# .exploded is the opposite of this, always returning the full address with all-zero groups and so on
addr_str = addr.compressed
print(addr_str)
Here, addr_str
will hold a fully random IPv4 or IPv6 address.
You can even generate random addresses from a subnet like this:
from random import getrandbits
from ipaddress import IPv4Network, IPv4Address
# network containing all addresses from 10.0.0.0 to 10.0.0.255
subnet = IPv4Network("10.0.0.0/24")
# subnet.max_prefixlen contains 32 for IPv4 subnets and 128 for IPv6 subnets
# subnet.prefixlen is 24 in this case, so we'll generate only 8 random bits
bits = getrandbits(subnet.max_prefixlen - subnet.prefixlen)
# here, we combine the subnet and the random bits
# to get an IP address from the previously specified subnet
addr = IPv4Address(subnet.network_address + bits)
addr_str = str(addr)
print(addr_str)
Here, addr_str
will always contain IP addresses like 10.0.0.184
, 10.0.0.42
and so on. It works the same way with IPv6 addresses, except in that case you'd have to import IPv6Network
and IPv6Address
instead.
7
Nice solution - did you consider pushingaddr_str = addr.compressed
to after the conditional?
– cmh
Jul 26 at 15:07
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
|
show 5 more comments
Python is often described as a "batteries included" kind of language, and this is no exception.
There's a module just for IP address manipulation and another module to generate random numbers. Put together, they do exactly what you want, in a way that's slightly more readable (IMO).
For this example, I'll assume that the variable v
contains either 4
or 6
.
from random import getrandbits
from ipaddress import IPv4Address, IPv6Address
if v == 4:
bits = getrandbits(32) # generates an integer with 32 random bits
addr = IPv4Address(bits) # instances an IPv4Address object from those bits
addr_str = str(addr) # get the IPv4Address object's string representation
elif v == 6:
bits = getrandbits(128) # generates an integer with 128 random bits
addr = IPv6Address(bits) # instances an IPv6Address object from those bits
# .compressed contains the short version of the IPv6 address
# str(addr) always returns the short address
# .exploded is the opposite of this, always returning the full address with all-zero groups and so on
addr_str = addr.compressed
print(addr_str)
Here, addr_str
will hold a fully random IPv4 or IPv6 address.
You can even generate random addresses from a subnet like this:
from random import getrandbits
from ipaddress import IPv4Network, IPv4Address
# network containing all addresses from 10.0.0.0 to 10.0.0.255
subnet = IPv4Network("10.0.0.0/24")
# subnet.max_prefixlen contains 32 for IPv4 subnets and 128 for IPv6 subnets
# subnet.prefixlen is 24 in this case, so we'll generate only 8 random bits
bits = getrandbits(subnet.max_prefixlen - subnet.prefixlen)
# here, we combine the subnet and the random bits
# to get an IP address from the previously specified subnet
addr = IPv4Address(subnet.network_address + bits)
addr_str = str(addr)
print(addr_str)
Here, addr_str
will always contain IP addresses like 10.0.0.184
, 10.0.0.42
and so on. It works the same way with IPv6 addresses, except in that case you'd have to import IPv6Network
and IPv6Address
instead.
Python is often described as a "batteries included" kind of language, and this is no exception.
There's a module just for IP address manipulation and another module to generate random numbers. Put together, they do exactly what you want, in a way that's slightly more readable (IMO).
For this example, I'll assume that the variable v
contains either 4
or 6
.
from random import getrandbits
from ipaddress import IPv4Address, IPv6Address
if v == 4:
bits = getrandbits(32) # generates an integer with 32 random bits
addr = IPv4Address(bits) # instances an IPv4Address object from those bits
addr_str = str(addr) # get the IPv4Address object's string representation
elif v == 6:
bits = getrandbits(128) # generates an integer with 128 random bits
addr = IPv6Address(bits) # instances an IPv6Address object from those bits
# .compressed contains the short version of the IPv6 address
# str(addr) always returns the short address
# .exploded is the opposite of this, always returning the full address with all-zero groups and so on
addr_str = addr.compressed
print(addr_str)
Here, addr_str
will hold a fully random IPv4 or IPv6 address.
You can even generate random addresses from a subnet like this:
from random import getrandbits
from ipaddress import IPv4Network, IPv4Address
# network containing all addresses from 10.0.0.0 to 10.0.0.255
subnet = IPv4Network("10.0.0.0/24")
# subnet.max_prefixlen contains 32 for IPv4 subnets and 128 for IPv6 subnets
# subnet.prefixlen is 24 in this case, so we'll generate only 8 random bits
bits = getrandbits(subnet.max_prefixlen - subnet.prefixlen)
# here, we combine the subnet and the random bits
# to get an IP address from the previously specified subnet
addr = IPv4Address(subnet.network_address + bits)
addr_str = str(addr)
print(addr_str)
Here, addr_str
will always contain IP addresses like 10.0.0.184
, 10.0.0.42
and so on. It works the same way with IPv6 addresses, except in that case you'd have to import IPv6Network
and IPv6Address
instead.
edited Jul 27 at 7:10
answered Jul 26 at 13:25
Peter W.
57925
57925
7
Nice solution - did you consider pushingaddr_str = addr.compressed
to after the conditional?
– cmh
Jul 26 at 15:07
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
|
show 5 more comments
7
Nice solution - did you consider pushingaddr_str = addr.compressed
to after the conditional?
– cmh
Jul 26 at 15:07
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
7
7
Nice solution - did you consider pushing
addr_str = addr.compressed
to after the conditional?– cmh
Jul 26 at 15:07
Nice solution - did you consider pushing
addr_str = addr.compressed
to after the conditional?– cmh
Jul 26 at 15:07
4
4
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
@tjt263 Yeah, I'd say this might have less educational value than your approach, even though it is a much better way to just generate a random IP address if that's what you really want.
– David Z
Jul 26 at 17:46
5
5
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
In CodeReview users aren't trying to do something as efficiently as possible with builtins, but rather get the form of their approach right. Telling someone who's writing an IP generator from scratch to just import it doesn't really serve the community.
– user1717828
Jul 26 at 20:42
7
7
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
Before posting it, I considered prefacing my answer with something like "This isn't a proper answer for Code Review, but...", but I didn't think it'd blow up like this. I intended it to be a helpful resource for future people finding this via Google, because just a few months ago, I was in the exact same situation as OP: wanting to write an IP randomizer, not knowing Python could do it for me. I've added a few comments to my examples, hopefully they'll make it more obvious how the code works.
– Peter W.
Jul 27 at 6:58
2
2
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
@user1717828 That's not true. If you are open to feedback on CRSE, you are inherently open to alternative solutions to the problem. If you purposefully choose to reinvent the wheel (as a personal challenge or otherwise), there's the reinventing-the-wheel tag.
– Daniel
Jul 27 at 23:12
|
show 5 more comments
Here are a few ideas about your code.
Check for command line arguments
The code fails with an exception if it's invoked with no command line arguments because it attempts to use argv[1]
and there isn't any. I'd suggest that it would be nice to print a "usage" message if the user enters either an invalid or no argument.
Use a list comprehension
List comprehensions are extremely useful and very Pythonic. It's really good to become proficient with them. Here's how to use one to generate a random IPv4 address:
'.'.join([str(randint(0,255)) for x in range(4)])
And an IPv6 address is a little trickier because we need hex digits.
':'.join([hex(randint(2**16,2**17))[-4:] for x in range(8)])
That works because randint
generates a number in the range 0x10000 to 0x20000 and we then pick off the last four hex digits.
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
you can use0x10000
and0x20000
instead of2**16
and2**17
for better readability.
– Mathias Ettinger
Jul 26 at 13:40
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
add a comment |
Here are a few ideas about your code.
Check for command line arguments
The code fails with an exception if it's invoked with no command line arguments because it attempts to use argv[1]
and there isn't any. I'd suggest that it would be nice to print a "usage" message if the user enters either an invalid or no argument.
Use a list comprehension
List comprehensions are extremely useful and very Pythonic. It's really good to become proficient with them. Here's how to use one to generate a random IPv4 address:
'.'.join([str(randint(0,255)) for x in range(4)])
And an IPv6 address is a little trickier because we need hex digits.
':'.join([hex(randint(2**16,2**17))[-4:] for x in range(8)])
That works because randint
generates a number in the range 0x10000 to 0x20000 and we then pick off the last four hex digits.
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
you can use0x10000
and0x20000
instead of2**16
and2**17
for better readability.
– Mathias Ettinger
Jul 26 at 13:40
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
add a comment |
Here are a few ideas about your code.
Check for command line arguments
The code fails with an exception if it's invoked with no command line arguments because it attempts to use argv[1]
and there isn't any. I'd suggest that it would be nice to print a "usage" message if the user enters either an invalid or no argument.
Use a list comprehension
List comprehensions are extremely useful and very Pythonic. It's really good to become proficient with them. Here's how to use one to generate a random IPv4 address:
'.'.join([str(randint(0,255)) for x in range(4)])
And an IPv6 address is a little trickier because we need hex digits.
':'.join([hex(randint(2**16,2**17))[-4:] for x in range(8)])
That works because randint
generates a number in the range 0x10000 to 0x20000 and we then pick off the last four hex digits.
Here are a few ideas about your code.
Check for command line arguments
The code fails with an exception if it's invoked with no command line arguments because it attempts to use argv[1]
and there isn't any. I'd suggest that it would be nice to print a "usage" message if the user enters either an invalid or no argument.
Use a list comprehension
List comprehensions are extremely useful and very Pythonic. It's really good to become proficient with them. Here's how to use one to generate a random IPv4 address:
'.'.join([str(randint(0,255)) for x in range(4)])
And an IPv6 address is a little trickier because we need hex digits.
':'.join([hex(randint(2**16,2**17))[-4:] for x in range(8)])
That works because randint
generates a number in the range 0x10000 to 0x20000 and we then pick off the last four hex digits.
answered Jul 26 at 12:41
Edward
46.2k377209
46.2k377209
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
you can use0x10000
and0x20000
instead of2**16
and2**17
for better readability.
– Mathias Ettinger
Jul 26 at 13:40
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
add a comment |
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
you can use0x10000
and0x20000
instead of2**16
and2**17
for better readability.
– Mathias Ettinger
Jul 26 at 13:40
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
Thanks. That last part's a bit clever. I had a similar idea, but wasn't able to pull it off. The list comprehensions are a nice touch too, just a bit trickier to articulate.
– tjt263
Jul 26 at 13:37
3
3
you can use
0x10000
and 0x20000
instead of 2**16
and 2**17
for better readability.– Mathias Ettinger
Jul 26 at 13:40
you can use
0x10000
and 0x20000
instead of 2**16
and 2**17
for better readability.– Mathias Ettinger
Jul 26 at 13:40
2
2
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
It might be worth mentioning that you don't need the list comprehension to really be a list. It could be a generator instead.
– David Z
Jul 26 at 17:48
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do
':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
For IPv6, leading zeroes in a group can be omitted, so you don't need that trick, and just do
':'.join(hex(randrange(0x10000))[2:] for x in range(8))
– Robin
Jul 27 at 12:38
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
@Robin: it's true, but I like to make it appear consistent. Personally, I prefer PeterW. 's answer. Very elegant!
– Edward
Jul 27 at 12:40
add a comment |
For someone not familiar with Python, you have picked pretty good habits. Not everyone uses functions or the if __name__ == '__main__'
guard first try.
That being said, I think it would make more sense to provide 2 functions instead of a single one: random_ipv4
and random_ipv6
.
You could also feed generator expressions to join
. They are both faster to process than +
for
+ append
and easier to read:
def random_ipv4():
return '.'.join(str(randint(0,255)) for _ in range(4))
def random_ipv6():
return ':'.join(
''.join(choice(hexdigits).lower() for _ in range(4))
for _ in range(8)
)
The only thing left being to properly validate that the input is either 4 or 6:
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit('Usage: python random_ip.py VERSION')
version = sys.argv[1]
if version == '4':
print(random_ipv4())
elif version == '6':
print(random_ipv6())
else:
sys.exit('VERSION should be 4 or 6, not {}'.format(version))
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But forjoin
it shouldn't matter much as the current implementation convert the input to a list right away.
– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates5.792979179001122
seconds for 1 million calls torandom_ipv4
using a generator expression and5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.
– Mathias Ettinger
Jul 26 at 15:01
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
add a comment |
For someone not familiar with Python, you have picked pretty good habits. Not everyone uses functions or the if __name__ == '__main__'
guard first try.
That being said, I think it would make more sense to provide 2 functions instead of a single one: random_ipv4
and random_ipv6
.
You could also feed generator expressions to join
. They are both faster to process than +
for
+ append
and easier to read:
def random_ipv4():
return '.'.join(str(randint(0,255)) for _ in range(4))
def random_ipv6():
return ':'.join(
''.join(choice(hexdigits).lower() for _ in range(4))
for _ in range(8)
)
The only thing left being to properly validate that the input is either 4 or 6:
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit('Usage: python random_ip.py VERSION')
version = sys.argv[1]
if version == '4':
print(random_ipv4())
elif version == '6':
print(random_ipv6())
else:
sys.exit('VERSION should be 4 or 6, not {}'.format(version))
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But forjoin
it shouldn't matter much as the current implementation convert the input to a list right away.
– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates5.792979179001122
seconds for 1 million calls torandom_ipv4
using a generator expression and5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.
– Mathias Ettinger
Jul 26 at 15:01
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
add a comment |
For someone not familiar with Python, you have picked pretty good habits. Not everyone uses functions or the if __name__ == '__main__'
guard first try.
That being said, I think it would make more sense to provide 2 functions instead of a single one: random_ipv4
and random_ipv6
.
You could also feed generator expressions to join
. They are both faster to process than +
for
+ append
and easier to read:
def random_ipv4():
return '.'.join(str(randint(0,255)) for _ in range(4))
def random_ipv6():
return ':'.join(
''.join(choice(hexdigits).lower() for _ in range(4))
for _ in range(8)
)
The only thing left being to properly validate that the input is either 4 or 6:
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit('Usage: python random_ip.py VERSION')
version = sys.argv[1]
if version == '4':
print(random_ipv4())
elif version == '6':
print(random_ipv6())
else:
sys.exit('VERSION should be 4 or 6, not {}'.format(version))
For someone not familiar with Python, you have picked pretty good habits. Not everyone uses functions or the if __name__ == '__main__'
guard first try.
That being said, I think it would make more sense to provide 2 functions instead of a single one: random_ipv4
and random_ipv6
.
You could also feed generator expressions to join
. They are both faster to process than +
for
+ append
and easier to read:
def random_ipv4():
return '.'.join(str(randint(0,255)) for _ in range(4))
def random_ipv6():
return ':'.join(
''.join(choice(hexdigits).lower() for _ in range(4))
for _ in range(8)
)
The only thing left being to properly validate that the input is either 4 or 6:
if __name__ == '__main__':
if len(sys.argv) < 2:
sys.exit('Usage: python random_ip.py VERSION')
version = sys.argv[1]
if version == '4':
print(random_ipv4())
elif version == '6':
print(random_ipv6())
else:
sys.exit('VERSION should be 4 or 6, not {}'.format(version))
answered Jul 26 at 12:48
Mathias Ettinger
23.5k33182
23.5k33182
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But forjoin
it shouldn't matter much as the current implementation convert the input to a list right away.
– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates5.792979179001122
seconds for 1 million calls torandom_ipv4
using a generator expression and5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.
– Mathias Ettinger
Jul 26 at 15:01
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
add a comment |
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But forjoin
it shouldn't matter much as the current implementation convert the input to a list right away.
– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates5.792979179001122
seconds for 1 million calls torandom_ipv4
using a generator expression and5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.
– Mathias Ettinger
Jul 26 at 15:01
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
CMIIW, but aren't list comprehension a bit faster than generator comprehension when memory is not an issue?
– Ludisposed
Jul 26 at 14:01
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But for
join
it shouldn't matter much as the current implementation convert the input to a list right away.– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed Found old timings at bytes.com/topic/python/answers/… But for
join
it shouldn't matter much as the current implementation convert the input to a list right away.– Mathias Ettinger
Jul 26 at 14:49
@Ludisposed My own testing indicates
5.792979179001122
seconds for 1 million calls to random_ipv4
using a generator expression and 5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.– Mathias Ettinger
Jul 26 at 15:01
@Ludisposed My own testing indicates
5.792979179001122
seconds for 1 million calls to random_ipv4
using a generator expression and 5.526552320003248
using a list-comprehension. Nothing really conclusive to prefer one over the other. And since we aren't to re-use the result, a generator expression is a good indication of that.– Mathias Ettinger
Jul 26 at 15:01
1
1
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
Yes it shouldn't matter much and is dependent on the data. I agree with your reasoning for choosing a generator.
– Ludisposed
Jul 26 at 15:11
add a comment |
Check for invalid outputs, and regenerate them.
It's possible that you'll produce an output that's reserved for a particular purpose, such as loopback (127.0.0.1
or ::1
) or broadcast (255.255.255.255
, ff02::1
, ff02::2
). Build in knowledge of such addresses, and if you find you've produced one, then replace it. You can do that recursively:
def make_address(v):
address = random_ip(v)
if is_reserved(address):
return make_address(v)
return address
2
There is no need for this to be recursive. It might as well be awhile is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...
– Graipher
Jul 26 at 15:20
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
add a comment |
Check for invalid outputs, and regenerate them.
It's possible that you'll produce an output that's reserved for a particular purpose, such as loopback (127.0.0.1
or ::1
) or broadcast (255.255.255.255
, ff02::1
, ff02::2
). Build in knowledge of such addresses, and if you find you've produced one, then replace it. You can do that recursively:
def make_address(v):
address = random_ip(v)
if is_reserved(address):
return make_address(v)
return address
2
There is no need for this to be recursive. It might as well be awhile is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...
– Graipher
Jul 26 at 15:20
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
add a comment |
Check for invalid outputs, and regenerate them.
It's possible that you'll produce an output that's reserved for a particular purpose, such as loopback (127.0.0.1
or ::1
) or broadcast (255.255.255.255
, ff02::1
, ff02::2
). Build in knowledge of such addresses, and if you find you've produced one, then replace it. You can do that recursively:
def make_address(v):
address = random_ip(v)
if is_reserved(address):
return make_address(v)
return address
Check for invalid outputs, and regenerate them.
It's possible that you'll produce an output that's reserved for a particular purpose, such as loopback (127.0.0.1
or ::1
) or broadcast (255.255.255.255
, ff02::1
, ff02::2
). Build in knowledge of such addresses, and if you find you've produced one, then replace it. You can do that recursively:
def make_address(v):
address = random_ip(v)
if is_reserved(address):
return make_address(v)
return address
answered Jul 26 at 12:50
Toby Speight
23.4k639111
23.4k639111
2
There is no need for this to be recursive. It might as well be awhile is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...
– Graipher
Jul 26 at 15:20
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
add a comment |
2
There is no need for this to be recursive. It might as well be awhile is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...
– Graipher
Jul 26 at 15:20
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
2
2
There is no need for this to be recursive. It might as well be a
while is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...– Graipher
Jul 26 at 15:20
There is no need for this to be recursive. It might as well be a
while is_reserved(address):
loop. But then again, if the chance to generate a valid IP is only a per mille (so you are in danger of regularly hitting the stack size limit), you are probably doing something wrong...– Graipher
Jul 26 at 15:20
1
1
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Yes, I was just showing one way. Python's only an occasional language for me, and I couldn't remember whether it guarantees tail-call elimination...
– Toby Speight
Jul 26 at 16:13
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
Maybe you want extra options to create IPv6 addresses formed from mapping IPv4 addresses and from hardware MAC addresses, then.
– Toby Speight
Jul 26 at 16:59
1
1
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
@TobySpeight It doesn't, but there is a way to guarantee it manually, by using a decorator: stackoverflow.com/q/27417874/2415524
– mbomb007
Jul 27 at 21:52
add a comment |
Validate the input: At present, your program
- aborts with
IndexError
if called without arguments, - aborts with
ValueError
if called with a non-integer argument, - prints
None
if called with an integer argument that is not4
or6
.
Missing or invalid arguments should print a helpful error message.
Most Unix command-line tools print the message to the standard error
and terminate with a non-zero exit status in the case of a failure.
It would be easier to compare the given argument against the
strings "4"
and "6"
instead of converting it to an integer
(which can fail).
Use list comprehension instead of appending to an array in a loop.
Use _
as iterator variable if the concrete value is not needed.
As an example, the "IPv4" case can be implemented as
if v == 4:
return '.'.join(str(randint(0,255)) for _ in range(4))
Why_
? Is that a thing people do? I've never seen it before.
– tjt263
Jul 26 at 17:45
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
add a comment |
Validate the input: At present, your program
- aborts with
IndexError
if called without arguments, - aborts with
ValueError
if called with a non-integer argument, - prints
None
if called with an integer argument that is not4
or6
.
Missing or invalid arguments should print a helpful error message.
Most Unix command-line tools print the message to the standard error
and terminate with a non-zero exit status in the case of a failure.
It would be easier to compare the given argument against the
strings "4"
and "6"
instead of converting it to an integer
(which can fail).
Use list comprehension instead of appending to an array in a loop.
Use _
as iterator variable if the concrete value is not needed.
As an example, the "IPv4" case can be implemented as
if v == 4:
return '.'.join(str(randint(0,255)) for _ in range(4))
Why_
? Is that a thing people do? I've never seen it before.
– tjt263
Jul 26 at 17:45
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
add a comment |
Validate the input: At present, your program
- aborts with
IndexError
if called without arguments, - aborts with
ValueError
if called with a non-integer argument, - prints
None
if called with an integer argument that is not4
or6
.
Missing or invalid arguments should print a helpful error message.
Most Unix command-line tools print the message to the standard error
and terminate with a non-zero exit status in the case of a failure.
It would be easier to compare the given argument against the
strings "4"
and "6"
instead of converting it to an integer
(which can fail).
Use list comprehension instead of appending to an array in a loop.
Use _
as iterator variable if the concrete value is not needed.
As an example, the "IPv4" case can be implemented as
if v == 4:
return '.'.join(str(randint(0,255)) for _ in range(4))
Validate the input: At present, your program
- aborts with
IndexError
if called without arguments, - aborts with
ValueError
if called with a non-integer argument, - prints
None
if called with an integer argument that is not4
or6
.
Missing or invalid arguments should print a helpful error message.
Most Unix command-line tools print the message to the standard error
and terminate with a non-zero exit status in the case of a failure.
It would be easier to compare the given argument against the
strings "4"
and "6"
instead of converting it to an integer
(which can fail).
Use list comprehension instead of appending to an array in a loop.
Use _
as iterator variable if the concrete value is not needed.
As an example, the "IPv4" case can be implemented as
if v == 4:
return '.'.join(str(randint(0,255)) for _ in range(4))
answered Jul 26 at 12:41
Martin R
15.5k12264
15.5k12264
Why_
? Is that a thing people do? I've never seen it before.
– tjt263
Jul 26 at 17:45
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
add a comment |
Why_
? Is that a thing people do? I've never seen it before.
– tjt263
Jul 26 at 17:45
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
Why
_
? Is that a thing people do? I've never seen it before.– tjt263
Jul 26 at 17:45
Why
_
? Is that a thing people do? I've never seen it before.– tjt263
Jul 26 at 17:45
2
2
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
@tjt263: It is just by convention used as a “throw-away variable,” see for example stackoverflow.com/q/5893163/1187415
– Martin R
Jul 26 at 18:27
add a comment |
Since you already got a couple of answers telling you to validate your inputs, here is a way how to do it using the argparse
module:
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-v',
type=int,
choices=(4, 6),
default=4,
help="Whether to generate a random IPv4 or IPv6 address. Default: IPv4.")
args = parser.parse_args()
print(random_ip(args.v))
You can then use it on the command line like this:
./randip
./randip -v 4
./randip -v4
./randip -v 6
If you do anything else, a helpful usage message is printed:
usage: [-h] [-v {4,6}]
optional arguments:
-h, --help show this help message and exit
-v {4,6} Whether to generate a random IPv4 or IPv6 address. Default:
IPv4.
add a comment |
Since you already got a couple of answers telling you to validate your inputs, here is a way how to do it using the argparse
module:
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-v',
type=int,
choices=(4, 6),
default=4,
help="Whether to generate a random IPv4 or IPv6 address. Default: IPv4.")
args = parser.parse_args()
print(random_ip(args.v))
You can then use it on the command line like this:
./randip
./randip -v 4
./randip -v4
./randip -v 6
If you do anything else, a helpful usage message is printed:
usage: [-h] [-v {4,6}]
optional arguments:
-h, --help show this help message and exit
-v {4,6} Whether to generate a random IPv4 or IPv6 address. Default:
IPv4.
add a comment |
Since you already got a couple of answers telling you to validate your inputs, here is a way how to do it using the argparse
module:
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-v',
type=int,
choices=(4, 6),
default=4,
help="Whether to generate a random IPv4 or IPv6 address. Default: IPv4.")
args = parser.parse_args()
print(random_ip(args.v))
You can then use it on the command line like this:
./randip
./randip -v 4
./randip -v4
./randip -v 6
If you do anything else, a helpful usage message is printed:
usage: [-h] [-v {4,6}]
optional arguments:
-h, --help show this help message and exit
-v {4,6} Whether to generate a random IPv4 or IPv6 address. Default:
IPv4.
Since you already got a couple of answers telling you to validate your inputs, here is a way how to do it using the argparse
module:
import argparse
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument('-v',
type=int,
choices=(4, 6),
default=4,
help="Whether to generate a random IPv4 or IPv6 address. Default: IPv4.")
args = parser.parse_args()
print(random_ip(args.v))
You can then use it on the command line like this:
./randip
./randip -v 4
./randip -v4
./randip -v 6
If you do anything else, a helpful usage message is printed:
usage: [-h] [-v {4,6}]
optional arguments:
-h, --help show this help message and exit
-v {4,6} Whether to generate a random IPv4 or IPv6 address. Default:
IPv4.
edited Jul 26 at 16:47
answered Jul 26 at 15:27
Graipher
23.5k53585
23.5k53585
add a comment |
add a comment |
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200337%2frandom-ip-address-generator%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown