How do I pad a numeric string with zeroes to the left, so that the string has a specific length?
19 Answers
To pad strings:
>>> n = '4'
>>> print(n.zfill(3))
004
To pad numbers:
>>> n = 4
>>> print(f'{n:03}') # Preferred method, python >= 3.6
004
>>> print('%03d' % n)
004
>>> print(format(n, '03')) # python >= 2.6
004
>>> print('{0:03d}'.format(n)) # python >= 2.6 + python 3
004
>>> print('{foo:03d}'.format(foo=n)) # python >= 2.6 + python 3
004
>>> print('{:03d}'.format(n)) # python >= 2.7 + python3
004

- 24,552
- 19
- 101
- 135

- 175,848
- 15
- 70
- 63
-
9Comments `python >= 2.6` are incorrect. That syntax doesn't work on `python >= 3`. You could change it to `python < 3`, but may I suggest instead always using parenthesis and omitting the comments altogether (encouraging recommended usage)? – Jason R. Coombs Sep 28 '15 at 13:13
-
5Note that you don't need to number your format strings: `'{:03d} {:03d}'.format(1, 2)` implicitly assigns the values in order. – Dragon Jul 08 '16 at 11:32
-
1@JasonR.Coombs: I assume you meant the `print` statement, when it should be a `print` function on Python 3? I edited in the parens; since only one thing is being printed, it works identically now on Py2 and Py3. – ShadowRanger Jan 25 '19 at 02:19
-
4Can any of these approaches be adapted to work with a variable number of zeroes? – Anders Rabo Thorbeck May 21 '19 at 22:04
-
10How could you have not used the number 7 for your example?!? – Motti Aug 13 '19 at 08:54
-
1@PhaniRithvij: Use another set of curly brackets: print(f'{i:0{n}d}') where i is your value and n is the amount of characters you want. Or when using format: '{i:0{n}d}'.format(i=4, n=6) or the less readable version without labels: '{:0{}d}'.format(4, 6) – Jasper Dec 05 '21 at 19:37
-
1@Motti It's probably just a random number https://xkcd.com/221/ – PM 2Ring May 19 '22 at 06:07
Just use the rjust
method of the string object.
This example creates a 10-character length string, padding as necessary:
>>> s = 'test'
>>> s.rjust(10, '0')
>>> '000000test'

- 24,552
- 19
- 101
- 135

- 19,939
- 18
- 59
- 63
-
In my opinion, it should be 't = t.rjust(10, '0'), otherwise the value of t remains unchanged (at least for me) – Stanislav Koncebovski Mar 10 '22 at 08:50
-
3@StanislavKoncebovski strings are immutable in Python. The value of a string will always remain unchanged no matter what you do to it and you always have to reassign if you want to update the variable to reference the new string. This has nothing to do with rjust. – Neil Apr 13 '22 at 09:59
-
@Paul D.Eden You may be right theoretically, but I checked it again, and yes, if you do not assign like t = t.rjust(10, '0') you will not obtain '000000test' in t. My assertion is based on a test. I am using Python 3.7. – Stanislav Koncebovski Apr 22 '22 at 17:18
Besides zfill
, you can use general string formatting:
print(f'{number:05d}') # (since Python 3.6), or
print('{:05d}'.format(number)) # or
print('{0:05d}'.format(number)) # or (explicit 0th positional arg. selection)
print('{n:05d}'.format(n=number)) # or (explicit `n` keyword arg. selection)
print(format(number, '05d'))
Documentation for string formatting and f-strings.

- 2,308
- 20
- 34

- 530,221
- 131
- 937
- 1,214
-
@Konrad: "The documentation, however, says to use format instead." I know I'm late to the party, but I'd like to see what you mean by this. The documentation I see (https://docs.python.org/3/library/stdtypes.html#old-string-formatting) says using `format` or other alternatives "may help avoid [aforementioned] errors" associated with `%` interpolation. That's not very robust "deprecation." – LarsH Jun 11 '19 at 22:33
-
1@LarsH Well it’s notable that the link in my answer originally pointed to `%` formatting. It now points to `str.format` formatting. *I did not change the link!* Rather, the Python documentation website behind that link was rewritten. Apart from that, the [documentation used to have stronger wording](https://docs.python.org/2.7/library/stdtypes.html?highlight=str%20format#str.format), and literally states that `str.format` “should be preferred to the `%` formatting”, just as I wrote in the comment you quoted. – Konrad Rudolph Jun 11 '19 at 23:25
For Python 3.6+ using f-strings:
>>> i = 1
>>> f"{i:0>2}" # Works for both numbers and strings.
'01'
>>> f"{i:02}" # Works only for numbers.
'01'
For Python 2.6 to Python 3.5:
>>> "{:0>2}".format("1") # Works for both numbers and strings.
'01'
>>> "{:02}".format(1) # Works only for numbers.
'01'
Those standard format specifiers are [[fill]align][minimumwidth]
and [0][minimumwidth]
.

- 17,623
- 11
- 91
- 124
-
Thx. Where can we find the official doc of things like `f"{i:0>2}"` ? The only official doc about f-string I can find is https://peps.python.org/pep-0498/#format-specifiers, but I get no result when I type `ctrl-f` then type in `pad` or `fill`. – Good Pen Dec 05 '22 at 01:42
-
@GoodPen Unfortunately, Python docs never caught up to PHP docs ease, but i found it at https://peps.python.org/pep-3101/#standard-format-specifiers – Cees Timmerman Dec 05 '22 at 23:44
-
>>> '99'.zfill(5)
'00099'
>>> '99'.rjust(5,'0')
'00099'
if you want the opposite:
>>> '99'.ljust(5,'0')
'99000'

- 2,258
- 2
- 20
- 13
str(n).zfill(width)
will work with string
s, int
s, float
s... and is Python 2.x and 3.x compatible:
>>> n = 3
>>> str(n).zfill(5)
'00003'
>>> n = '3'
>>> str(n).zfill(5)
'00003'
>>> n = '3.0'
>>> str(n).zfill(5)
'003.0'

- 136,902
- 23
- 188
- 247
What is the most pythonic way to pad a numeric string with zeroes to the left, i.e., so the numeric string has a specific length?
str.zfill
is specifically intended to do this:
>>> '1'.zfill(4)
'0001'
Note that it is specifically intended to handle numeric strings as requested, and moves a +
or -
to the beginning of the string:
>>> '+1'.zfill(4)
'+001'
>>> '-1'.zfill(4)
'-001'
Here's the help on str.zfill
:
>>> help(str.zfill)
Help on method_descriptor:
zfill(...)
S.zfill(width) -> str
Pad a numeric string S with zeros on the left, to fill a field
of the specified width. The string S is never truncated.
Performance
This is also the most performant of alternative methods:
>>> min(timeit.repeat(lambda: '1'.zfill(4)))
0.18824880896136165
>>> min(timeit.repeat(lambda: '1'.rjust(4, '0')))
0.2104538488201797
>>> min(timeit.repeat(lambda: f'{1:04}'))
0.32585487607866526
>>> min(timeit.repeat(lambda: '{:04}'.format(1)))
0.34988890308886766
To best compare apples to apples for the %
method (note it is actually slower), which will otherwise pre-calculate:
>>> min(timeit.repeat(lambda: '1'.zfill(0 or 4)))
0.19728074967861176
>>> min(timeit.repeat(lambda: '%04d' % (0 or 1)))
0.2347015216946602
Implementation
With a little digging, I found the implementation of the zfill
method in Objects/stringlib/transmogrify.h
:
static PyObject *
stringlib_zfill(PyObject *self, PyObject *args)
{
Py_ssize_t fill;
PyObject *s;
char *p;
Py_ssize_t width;
if (!PyArg_ParseTuple(args, "n:zfill", &width))
return NULL;
if (STRINGLIB_LEN(self) >= width) {
return return_self(self);
}
fill = width - STRINGLIB_LEN(self);
s = pad(self, fill, 0, '0');
if (s == NULL)
return NULL;
p = STRINGLIB_STR(s);
if (p[fill] == '+' || p[fill] == '-') {
/* move sign to beginning of string */
p[0] = p[fill];
p[fill] = '0';
}
return s;
}
Let's walk through this C code.
It first parses the argument positionally, meaning it doesn't allow keyword arguments:
>>> '1'.zfill(width=4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: zfill() takes no keyword arguments
It then checks if it's the same length or longer, in which case it returns the string.
>>> '1'.zfill(0)
'1'
zfill
calls pad
(this pad
function is also called by ljust
, rjust
, and center
as well). This basically copies the contents into a new string and fills in the padding.
static inline PyObject *
pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
{
PyObject *u;
if (left < 0)
left = 0;
if (right < 0)
right = 0;
if (left == 0 && right == 0) {
return return_self(self);
}
u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
if (u) {
if (left)
memset(STRINGLIB_STR(u), fill, left);
memcpy(STRINGLIB_STR(u) + left,
STRINGLIB_STR(self),
STRINGLIB_LEN(self));
if (right)
memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
fill, right);
}
return u;
}
After calling pad
, zfill
moves any originally preceding +
or -
to the beginning of the string.
Note that for the original string to actually be numeric is not required:
>>> '+foo'.zfill(10)
'+000000foo'
>>> '-foo'.zfill(10)
'-000000foo'

- 374,368
- 89
- 403
- 331
-
for the performance, are there cases where f strings are better including use cases for python2 vs python3? also, I think as zfill is not common it would help your answer to have a link to the docs – elad silver May 24 '19 at 13:21
-
1@eladsilver depends on your intent, keeping in mind the behavior with `+` and `-`, and I added a link to the docs! – Russia Must Remove Putin May 24 '19 at 14:22
For the ones who came here to understand and not just a quick answer. I do these especially for time strings:
hour = 4
minute = 3
"{:0>2}:{:0>2}".format(hour,minute)
# prints 04:03
"{:0>3}:{:0>5}".format(hour,minute)
# prints '004:00003'
"{:0<3}:{:0<5}".format(hour,minute)
# prints '400:30000'
"{:$<3}:{:#<5}".format(hour,minute)
# prints '4$$:3####'
"0" symbols what to replace with the "2" padding characters, the default is an empty space
">" symbols allign all the 2 "0" character to the left of the string
":" symbols the format_spec

- 9,222
- 4
- 43
- 67
When using Python >= 3.6
, the cleanest way is to use f-strings with string formatting:
>>> s = f"{1:08}" # inline with int
>>> s
'00000001'
>>> s = f"{'1':0>8}" # inline with str
>>> s
'00000001'
>>> n = 1
>>> s = f"{n:08}" # int variable
>>> s
'00000001'
>>> c = "1"
>>> s = f"{c:0>8}" # str variable
>>> s
'00000001'
I would prefer formatting with an int
, since only then the sign is handled correctly:
>>> f"{-1:08}"
'-0000001'
>>> f"{1:+08}"
'+0000001'
>>> f"{'-1':0>8}"
'000000-1'

- 21,987
- 6
- 62
- 97
For numbers:
i = 12
print(f"{i:05d}")
Output
00012

- 3,044
- 9
- 42
- 86
-
1I'd rather hope you'll get '00002'. Also an example with i>10 might have been a good idea. Nonetheless, this helped me. – André Aichert Sep 20 '21 at 08:51
-
width = 10
x = 5
print "%0*d" % (width, x)
> 0000000005
See the print documentation for all the exciting details!
Update for Python 3.x (7.5 years later)
That last line should now be:
print("%0*d" % (width, x))
I.e. print()
is now a function, not a statement. Note that I still prefer the Old School printf()
style because, IMNSHO, it reads better, and because, um, I've been using that notation since January, 1980. Something ... old dogs .. something something ... new tricks.

- 17,605
- 2
- 49
- 65
I am adding how to use a int from a length of a string within an f-string because it didn't appear to be covered:
>>> pad_number = len("this_string")
11
>>> s = f"{1:0{pad_number}}" }
>>> s
'00000000001'

- 348
- 2
- 7
-
it's covered in this answer: https://stackoverflow.com/a/57360675/860196 – runDOSrun Sep 14 '20 at 12:59
For zip codes saved as integers:
>>> a = 6340
>>> b = 90210
>>> print '%05d' % a
06340
>>> print '%05d' % b
90210

- 57,944
- 17
- 167
- 143
Quick timing comparison:
setup = '''
from random import randint
def test_1():
num = randint(0,1000000)
return str(num).zfill(7)
def test_2():
num = randint(0,1000000)
return format(num, '07')
def test_3():
num = randint(0,1000000)
return '{0:07d}'.format(num)
def test_4():
num = randint(0,1000000)
return format(num, '07d')
def test_5():
num = randint(0,1000000)
return '{:07d}'.format(num)
def test_6():
num = randint(0,1000000)
return '{x:07d}'.format(x=num)
def test_7():
num = randint(0,1000000)
return str(num).rjust(7, '0')
'''
import timeit
print timeit.Timer("test_1()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_2()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_3()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_4()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_5()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_6()", setup=setup).repeat(3, 900000)
print timeit.Timer("test_7()", setup=setup).repeat(3, 900000)
> [2.281613943830961, 2.2719342631547077, 2.261691106209631]
> [2.311480238815406, 2.318420542148333, 2.3552384305184493]
> [2.3824197456864304, 2.3457239951596485, 2.3353268829498646]
> [2.312442972404032, 2.318053102249902, 2.3054072168069872]
> [2.3482314132374853, 2.3403386400002475, 2.330108825844775]
> [2.424549090688892, 2.4346475296851438, 2.429691196530058]
> [2.3259756401716487, 2.333549212826732, 2.32049893822186]
I've made different tests of different repetitions. The differences are not huge, but in all tests, the zfill
solution was fastest.

- 6,605
- 5
- 55
- 97
If you're looking to pad an integer, and limit the significant figures at the same time (with f strings):
a = 4.432
>> 4.432
a = f'{a:04.1f}'
>> '04.4'
f'{a:04.1f}'
this translates to 1 decimal/(float) point, left pad the digit until 4 characters total.

- 145
- 3
- 11
Its ok too:
h = 2
m = 7
s = 3
print("%02d:%02d:%02d" % (h, m, s))
so output will be: "02:07:03"

- 1,528
- 1
- 14
- 21
You could also repeat "0", prepend it to str(n)
and get the rightmost width slice. Quick and dirty little expression.
def pad_left(n, width, pad="0"):
return ((pad * width) + str(n))[-width:]
-
1This only works for positive numbers though. It gets a little more complicated if you want negatives too. But this expression is good for quick and dirty work, if you don't mind that kind of thing. – J Lacar May 06 '13 at 22:06
-
1I have absolutely no idea why this is downvoted. If it's cause it doesn't work on negative numbers fair enough, but the overwhelming reason one would left pad with zeros is for id numbers. If you have negative id numbers I think you have bigger problems... are you expecting your pad to be of the form '00000-1234'? or '-000001234'? Honestly given the question this answer works, it's simple, it's clean, it's extensible. It may not be zfill but if it answers the question it should be upvoted. – TastySlowCooker Sep 23 '19 at 01:55
Another approach would be to use a list comprehension with a condition checking for lengths. Below is a demonstration:
# input list of strings that we want to prepend zeros
In [71]: list_of_str = ["101010", "10101010", "11110", "0000"]
# prepend zeros to make each string to length 8, if length of string is less than 8
In [83]: ["0"*(8-len(s)) + s if len(s) < desired_len else s for s in list_of_str]
Out[83]: ['00101010', '10101010', '00011110', '00000000']

- 57,311
- 13
- 161
- 150
I made a function :
def PadNumber(number, n_pad, add_prefix=None):
number_str = str(number)
paded_number = number_str.zfill(n_pad)
if add_prefix:
paded_number = add_prefix+paded_number
print(paded_number)
PadNumber(99, 4)
PadNumber(1011, 8, "b'")
PadNumber('7BEF', 6, "#")
The output :
0099
b'00001011
#007BEF

- 57
- 1