# Is there a simpler way to modify all arguments in a function beforeusing the arguments?

Discussion in 'Python' started by bruceg113355@gmail.com, Nov 10, 2012.

1. ### Guest

Is there a simpler way to modify all arguments in a function before using the arguments?

For example, can the below code, in the modify arguments section be made into a few statements?

def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
# modify arguments
# ----------------------
aa = aa.replace (“_” , “”)
bb= bb.replace (“_” , “”)
cc = cc.replace (“_” , “”)
dd = dd.replace (“_” , “”)
ee = ee.replace (“_” , “”)
ff = ff.replace (“_” , “”)
gg = gg.replace (“_” , “”)
hh = hh.replace (“_” , “”)

# use the arguments
# -----------------
# …

, Nov 10, 2012

2. ### Roy SmithGuest

Re: Is there a simpler way to modify all arguments in a function before using the arguments?

In article <>,
wrote:

> Is there a simpler way to modify all arguments in a function before using the
> arguments?
>
> For example, can the below code, in the modify arguments section be made into
> a few statements?
>
> def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
> # modify arguments
> # ----------------------
> aa = aa.replace (³_² , ³²)
> bb= bb.replace (³_² , ³²)
> cc = cc.replace (³_² , ³²)
> dd = dd.replace (³_² , ³²)
> ee = ee.replace (³_² , ³²)
> ff = ff.replace (³_² , ³²)
> gg = gg.replace (³_² , ³²)
> hh = hh.replace (³_² , ³²)
>
> # use the arguments
> # -----------------
> # Š

You could do something like (not error checked)...

def someComputation(*args):
new_args = [arg.replace("_", "") for arg in args]
aa, bb, cc, dd, ee, ff, gg, hh = new_args

but that's pretty weird. I suspect you just want to pass a list instead
of a bunch of discrete arguments.

Roy Smith, Nov 10, 2012

3. ### Steven D'ApranoGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Fri, 09 Nov 2012 20:05:26 -0500, Roy Smith wrote:

> In article <>,
> wrote:
>
>> Is there a simpler way to modify all arguments in a function before
>> using the arguments?
>>
>> For example, can the below code, in the modify arguments section be
>> made into a few statements?
>>
>> def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
>> # modify arguments
>> # ----------------------
>> aa = aa.replace (Â³_Â² , Â³Â²)
>> bb= bb.replace (Â³_Â² , Â³Â²)
>> cc = cc.replace (Â³_Â² , Â³Â²)
>> dd = dd.replace (Â³_Â² , Â³Â²)
>> ee = ee.replace (Â³_Â² , Â³Â²)
>> ff = ff.replace (Â³_Â² , Â³Â²)
>> gg = gg.replace (Â³_Â² , Â³Â²)
>> hh = hh.replace (Â³_Â² , Â³Â²)
>>
>> # use the arguments
>> # -----------------
>> # ÂŠ

>
> You could do something like (not error checked)...
>
> def someComputation(*args):
> new_args = [arg.replace("_", "") for arg in args] aa, bb, cc, dd,
> ee, ff, gg, hh = new_args
>
> but that's pretty weird. I suspect you just want to pass a list instead
> of a bunch of discrete arguments.

I agree with everything you say except that it is pretty weird. As far as
I am concerned, it isn't weird at all.

If you need named parameters:

def someComputation(aa, bb, cc, dd, ee, ff, gg, hh):
aa, bb, cc, dd, ee, ff, gg, hh = [arg.replace("_", "")
for arg in (aa. bb, cc, dd, ee, ff, gg, hh)]
...

--
Steven

Steven D'Aprano, Nov 10, 2012
4. ### Paul RubinGuest

Re: Is there a simpler way to modify all arguments in a function before using the arguments?

writes:
> Is there a simpler way to modify all arguments in a function before
> using the arguments?

Why do you want to do that?

> For example, can the below code, in the modify arguments section be
> made into a few statements?

Whenever someone uses that many variables one always has to ask whether
a table would be better. But, for

> def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
> # modify arguments
> # ----------------------
> aa = aa.replace (â€œ_â€ , â€œâ€)
> bb= bb.replace (â€œ_â€ , â€œâ€)
> cc = cc.replace (â€œ_â€ , â€œâ€)
> dd = dd.replace (â€œ_â€ , â€œâ€)
> ee = ee.replace (â€œ_â€ , â€œâ€)
> ff = ff.replace (â€œ_â€ , â€œâ€)
> gg = gg.replace (â€œ_â€ , â€œâ€)
> hh = hh.replace (â€œ_â€ , â€œâ€)

you could write (untested):

def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
def modify(s): return s.replace('_', '')
aa,bb,cc,dd,ee,ff,gg,hh = \
map(modify,[aa,bb,cc,dd,ee,ff,gg,hh])

Paul Rubin, Nov 10, 2012
5. ### Chris AngelicoGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Sat, Nov 10, 2012 at 1:52 PM, Paul Rubin <> wrote:
> writes:
>> Is there a simpler way to modify all arguments in a function before
>> using the arguments?

>
> Why do you want to do that?
>

Contrived example:

def send_email(from, to, subj, body, whatever, other, headers, you, like):
# Okay, now translate all those into the appropriate encoding and
with special characters escaped
# We need to translate each one separately so that, for instance,

ChrisA

Chris Angelico, Nov 10, 2012
6. ### Paul RubinGuest

Re: Is there a simpler way to modify all arguments in a function before using the arguments?

Chris Angelico <> writes:
> Contrived example:
> def send_email(from, to, subj, body, whatever, other, headers, you, like):

That should be a dictionary with the header names as indexes. In fact
there are already some email handling modules in the stdlib that

Paul Rubin, Nov 10, 2012
7. ### Miki TebekaGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

> Is there a simpler way to modify all arguments in a function before using the arguments?
You can use a decorator:

from functools import wraps

def fix_args(fn):
@wraps(fn)
def wrapper(*args):
args = (arg.replace('_', '') for arg in args)
return fn(*args)

return wrapper

@fix_args
def foo(x, y):
print(x)
print(y)

Miki Tebeka, Nov 10, 2012
8. ### Peter OttenGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

Miki Tebeka wrote:

>> Is there a simpler way to modify all arguments in a function before using
>> the arguments?

> You can use a decorator:
>
> from functools import wraps
>
> def fix_args(fn):
> @wraps(fn)
> def wrapper(*args):
> args = (arg.replace('_', '') for arg in args)
> return fn(*args)
>
> return wrapper
>
> @fix_args
> def foo(x, y):
> print(x)
> print(y)

I was tempted to post that myself, but he said /simpler/

Peter Otten, Nov 10, 2012
9. ### Chris AngelicoGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Sat, Nov 10, 2012 at 3:05 PM, Paul Rubin <> wrote:
> Chris Angelico <> writes:
>> Contrived example:
>> def send_email(from, to, subj, body, whatever, other, headers, you, like):

>
> That should be a dictionary with the header names as indexes. In fact
> there are already some email handling modules in the stdlib that

That's also plausible, but keyword arguments do make sense. And this
was a top-of-the-head contrived example; I'm sure there are plenty of
good use-cases.

ChrisA

Chris Angelico, Nov 10, 2012
10. ### Guest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Friday, November 9, 2012 8:16:12 PM UTC-5, Steven D'Aprano wrote:
> On Fri, 09 Nov 2012 20:05:26 -0500, Roy Smith wrote:
>
>
>
> > In article <>,

>
> > wrote:

>
> >

>
> >> Is there a simpler way to modify all arguments in a function before

>
> >> using the arguments?

>
> >>

>
> >> For example, can the below code, in the modify arguments section be

>
> >> made into a few statements?

>
> >>

>
> >> def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):

>
> >> # modify arguments

>
> >> # ----------------------

>
> >> aa = aa.replace (³_² , ³²)

>
> >> bb= bb.replace (³_² , ³²)

>
> >> cc = cc.replace (³_² , ³²)

>
> >> dd = dd.replace (³_² , ³²)

>
> >> ee = ee.replace (³_² , ³²)

>
> >> ff = ff.replace (³_² , ³²)

>
> >> gg = gg.replace (³_² , ³²)

>
> >> hh = hh.replace (³_² , ³²)

>
> >>

>
> >> # use the arguments

>
> >> # -----------------

>
> >> # Š

>
> >

>
> > You could do something like (not error checked)...

>
> >

>
> > def someComputation(*args):

>
> > new_args = [arg.replace("_", "") for arg in args] aa, bb, cc, dd,

>
> > ee, ff, gg, hh = new_args

>
> >

>
> > but that's pretty weird. I suspect you just want to pass a list instead

>
> > of a bunch of discrete arguments.

>
>
>
>
>
> I agree with everything you say except that it is pretty weird. As far as
>
> I am concerned, it isn't weird at all.
>
>
>
> If you need named parameters:
>
>
>
> def someComputation(aa, bb, cc, dd, ee, ff, gg, hh):
>
> aa, bb, cc, dd, ee, ff, gg, hh = [arg.replace("_", "")
>
> for arg in (aa. bb, cc, dd, ee, ff, gg, hh)]
>
> ...
>
>
>
>
>
>
>
> --
>
> Steven

Thanks to all.
Steve's example is the one I will try next week.
Passing in lists, will work but it requires extra coding from the calling routines to build the list.
Discrete arguments make sense.
Also, what is the problem passing in 7 or more arguments?

Thanks,
Bruce

, Nov 10, 2012
11. ### AahzGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

In article <>,
Peter Otten <> wrote:
>Miki Tebeka wrote:
>
>>> Is there a simpler way to modify all arguments in a function before using
>>> the arguments?

>>
>> You can use a decorator:
>>
>> from functools import wraps
>>
>> def fix_args(fn):
>> @wraps(fn)
>> def wrapper(*args):
>> args = (arg.replace('_', '') for arg in args)
>> return fn(*args)
>>
>> return wrapper
>>
>> @fix_args
>> def foo(x, y):
>> print(x)
>> print(y)

>
>I was tempted to post that myself, but he said /simpler/

From my POV, that *is* simpler. When you change the parameters for foo,
you don't need to change the arg pre-processing. Also allows code reuse,
probably any program needing this kind of processing once will need it
again.
--
Aahz () <*> http://www.pythoncraft.com/

"....Normal is what cuts off your sixth finger and your tail..." --Siobhan

Aahz, Nov 10, 2012
12. ### Guest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

All,

I never used decorators before. I saw Miki Tebeka's sample code and your rationale (Aahz) and I like it. For my application problem, decorators seem like a good solution.

Thanks to all,
Bruce

On Saturday, November 10, 2012 10:35:12 AM UTC-5, Aahz wrote:
> In article <>,
>
> Peter Otten <> wrote:
>
> >Miki Tebeka wrote:

>
> >

>
> >>> Is there a simpler way to modify all arguments in a function before using

>
> >>> the arguments?

>
> >>

>
> >> You can use a decorator:

>
> >>

>
> >> from functools import wraps

>
> >>

>
> >> def fix_args(fn):

>
> >> @wraps(fn)

>
> >> def wrapper(*args):

>
> >> args = (arg.replace('_', '') for arg in args)

>
> >> return fn(*args)

>
> >>

>
> >> return wrapper

>
> >>

>
> >> @fix_args

>
> >> def foo(x, y):

>
> >> print(x)

>
> >> print(y)

>
> >

>
> >I was tempted to post that myself, but he said /simpler/

>
>
>
> From my POV, that *is* simpler. When you change the parameters for foo,
>
> you don't need to change the arg pre-processing. Also allows code reuse,
>
> probably any program needing this kind of processing once will need it
>
> again.
>
> --
>
> Aahz () <*> http://www.pythoncraft.com/
>
>
>
> "....Normal is what cuts off your sixth finger and your tail..." --Siobhan

, Nov 10, 2012
13. ### Chris AngelicoGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Sun, Nov 11, 2012 at 12:15 AM, <> wrote:
> Thanks to all.
> Steve's example is the one I will try next week.
> Passing in lists, will work but it requires extra coding from the calling routines to build the list.

Not necessarily! Watch:

def foo(*args):
print(repr(args))

foo("Hello","world","!")

('Hello', 'world', '!')

Okay, that's not technically a list, it's a tuple, but same diff. Your
callers still see you as taking separate arguments, but you take them
as a single collection.

ChrisA

Chris Angelico, Nov 10, 2012
14. ### Peter OttenGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

Aahz wrote:

> In article <>,
> Peter Otten <> wrote:
>>Miki Tebeka wrote:
>>
>>>> Is there a simpler way to modify all arguments in a function before
>>>> using the arguments?
>>>
>>> You can use a decorator:
>>>
>>> from functools import wraps
>>>
>>> def fix_args(fn):
>>> @wraps(fn)
>>> def wrapper(*args):
>>> args = (arg.replace('_', '') for arg in args)
>>> return fn(*args)
>>>
>>> return wrapper
>>>
>>> @fix_args
>>> def foo(x, y):
>>> print(x)
>>> print(y)

>>
>>I was tempted to post that myself, but he said /simpler/

>
> From my POV, that *is* simpler. When you change the parameters for foo,
> you don't need to change the arg pre-processing. Also allows code reuse,
> probably any program needing this kind of processing once will need it
> again.

Typical changes would be

@fix_args
def bar(x, y=None):
print(x)
print(y)

@fix_args
def baz(file, x, y):
print(s, file=file)

Do you find it obvious what

bar("a_b")
bar("a_b", y="c_d")

print? Do you find the traceback produced by the latter helpful?
Moving complexity into a helper function often makes client code simpler
because if the helper is well-tested and preferrably maintained by someone
else the part that you have to deal with becomes simpler, but the overall
complexity still increases.
A fix_args() decorator is worthwhile only if you need it more than once or
twice, and because it is hard to generalise I expect that yagni.

Peter Otten, Nov 11, 2012
15. ### Steve HowellGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Nov 9, 4:48 pm, wrote:
> Is there a simpler way to modify all arguments in a function before usingthe arguments?
>
> For example, can the below code, in the modify arguments section be made into a few statements?
>
>     def someComputation (aa, bb, cc, dd, ee, ff, gg, hh):
>        # modify arguments
>        # ----------------------
>         aa = aa.replace (“_” , “”)
>         bb=  bb.replace (“_” , “”)
>         cc = cc.replace (“_” , “”)
>         dd = dd.replace (“_” , “”)
>         ee = ee.replace (“_” , “”)
>         ff = ff.replace (“_” , “”)
>         gg = gg.replace (“_” , “”)
>         hh = hh.replace (“_” , “”)
>
>        # use the arguments
>        # -----------------
>        # …

I would couch this problem in a little more specific terms than trying
to make this "simpler."

The word "simple" is a dangerous term, because it's so broad and
subjective. By my mind, the code is already simple, but that's just
my own two cents.

The real problem with the code that it's a maintenance trap, because a
careless developer could add the ii parameter and forget to clean the
output. So the problem statement here might be more like "How do I
make sure future developers don't forget to fix the underscores in
future args?". That's still a controversial question, but at least
it's a little more specific.

The other problem with the current code is that all the boilerplate
distracts from the real logic of the function. That's a valid
concern, although it's likely that most maintainers of the code would
simply page down past the boilerplate without too much complaint.

Steve Howell, Nov 11, 2012
16. ### Guest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Saturday, November 10, 2012 10:35:12 AM UTC-5, Aahz wrote:
> In article <>,
>
> Peter Otten <> wrote:
>
> >Miki Tebeka wrote:

>
> >

>
> >>> Is there a simpler way to modify all arguments in a function before using

>
> >>> the arguments?

>
> >>

>
> >> You can use a decorator:

>
> >>

>
> >> from functools import wraps

>
> >>

>
> >> def fix_args(fn):

>
> >> @wraps(fn)

>
> >> def wrapper(*args):

>
> >> args = (arg.replace('_', '') for arg in args)

>
> >> return fn(*args)

>
> >>

>
> >> return wrapper

>
> >>

>
> >> @fix_args

>
> >> def foo(x, y):

>
> >> print(x)

>
> >> print(y)

>
> >

>
> >I was tempted to post that myself, but he said /simpler/

>
>
>
> From my POV, that *is* simpler. When you change the parameters for foo,
>
> you don't need to change the arg pre-processing. Also allows code reuse,
>
> probably any program needing this kind of processing once will need it
>
> again.
>
> --
>
> Aahz () <*> http://www.pythoncraft.com/
>
>
>
> "....Normal is what cuts off your sixth finger and your tail..." --Siobhan

Using a decorator works when named arguments are not used. When named arguments are used, unexpected keyword error is reported. Is there a simple fix?

Thanks to all,
Bruce

Code:
-----

from functools import wraps

def fix_args(fn):
@wraps(fn)
def wrapper(*args):
args = (arg.replace('_', '') for arg in args)
return fn(*args)
return wrapper

@fix_args
def foo(a1="", a2="", b1="", b2=""):
print(a1)
print(a2)
print(b1)
print(b2)

foo ('a1a1_x', 'a2a2_x', 'b1b1_x', 'b2b2_____x')
foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')

Results:
--------
a1a1x
a2a2x
b1b1x
b2b2x
Traceback (most recent call last):
File "C:\WORK\masterDB_Update\argtest.py", line 19, in <module>
foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')
TypeError: wrapper() got an unexpected keyword argument 'a1'

, Nov 15, 2012
17. ### Emile van SebilleGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

wrote:

> Using a decorator works when named arguments are not used. When named arguments are used, unexpected keyword error is reported. Is there a simple fix?

Extend def wrapper(*args) to handle *kwargs as well

Emile

> Code:
> -----
>
> from functools import wraps
>
> def fix_args(fn):
> @wraps(fn)
> def wrapper(*args):
> args = (arg.replace('_', '') for arg in args)
> return fn(*args)
> return wrapper
>
> @fix_args
> def foo(a1="", a2="", b1="", b2=""):
> print(a1)
> print(a2)
> print(b1)
> print(b2)
>
> foo ('a1a1_x', 'a2a2_x', 'b1b1_x', 'b2b2_____x')
> foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')
>
> Results:
> --------
> a1a1x
> a2a2x
> b1b1x
> b2b2x
> Traceback (most recent call last):
> File "C:\WORK\masterDB_Update\argtest.py", line 19, in <module>
> foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')
> TypeError: wrapper() got an unexpected keyword argument 'a1'

Emile van Sebille, Nov 16, 2012
18. ### Ethan FurmanGuest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

Emile van Sebille wrote:
> wrote:
>
>> Using a decorator works when named arguments are not used. When named
>> arguments are used, unexpected keyword error is reported. Is there a
>> simple fix?

>
> Extend def wrapper(*args) to handle *kwargs as well
>
> Emile
>
>> Code:
>> -----
>>
>> from functools import wraps
>>
>> def fix_args(fn):
>> @wraps(fn)
>> def wrapper(*args):

so this line ^ becomes
def wrapper(*args, **kwargs):
>> args = (arg.replace('_', '') for arg in args)

for k, v in kwargs:
kwargs[k] = v.replace('_', '')
>> return fn(*args)

and this line ^ becomes
return fn(*args, **kwargs)
>> return wrapper

~Ethan~

Ethan Furman, Nov 16, 2012
19. ### Guest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Thursday, November 15, 2012 11:16:08 PM UTC-5, Ethan Furman wrote:
> Emile van Sebille wrote:
>
>
> >

>
> >> Using a decorator works when named arguments are not used. When named

>
> >> arguments are used, unexpected keyword error is reported. Is there a

>
> >> simple fix?

>
> >

>
> > Extend def wrapper(*args) to handle *kwargs as well

>
> >

>
> > Emile

>
> >

>
> >> Code:

>
> >> -----

>
> >>

>
> >> from functools import wraps

>
> >>

>
> >> def fix_args(fn):

>
> >> @wraps(fn)

>
> >> def wrapper(*args):

>
> so this line ^ becomes
>
> def wrapper(*args, **kwargs):
>
> >> args = (arg.replace('_', '') for arg in args)

>
>
> for k, v in kwargs:
>
> kwargs[k] = v.replace('_', '')
>
> >> return fn(*args)

>
> and this line ^ becomes
>
> return fn(*args, **kwargs)
>
> >> return wrapper

>
>
>
> ~Ethan~

Ethan,

I tried you code suggestions but got errors.
However, this works:

from functools import wraps

def fix_args(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
args = (arg.replace('_', '') for arg in args)
for kv in kwargs:
kwargs[kv] = kwargs[kv].replace('_', '')
return fn(*args, **kwargs)
return wrapper

@fix_args
def foo(a1="", a2="", b1="", b2=""):
print(a1)
print(a2)
print(b1)
print(b2)
print ""

foo ('a1a1_x', 'a2a2_x', 'b1b1_x', 'b2b2_____x')
foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')
foo ('a1a1_x', 'a2a2_x', b1='b1b1_x', b2='b2b2_____x')

Bruce

, Nov 16, 2012
20. ### Guest

Re: Is there a simpler way to modify all arguments in a functionbefore using the arguments?

On Thursday, November 15, 2012 11:16:08 PM UTC-5, Ethan Furman wrote:
> Emile van Sebille wrote:
>
>
> >

>
> >> Using a decorator works when named arguments are not used. When named

>
> >> arguments are used, unexpected keyword error is reported. Is there a

>
> >> simple fix?

>
> >

>
> > Extend def wrapper(*args) to handle *kwargs as well

>
> >

>
> > Emile

>
> >

>
> >> Code:

>
> >> -----

>
> >>

>
> >> from functools import wraps

>
> >>

>
> >> def fix_args(fn):

>
> >> @wraps(fn)

>
> >> def wrapper(*args):

>
> so this line ^ becomes
>
> def wrapper(*args, **kwargs):
>
> >> args = (arg.replace('_', '') for arg in args)

>
>
> for k, v in kwargs:
>
> kwargs[k] = v.replace('_', '')
>
> >> return fn(*args)

>
> and this line ^ becomes
>
> return fn(*args, **kwargs)
>
> >> return wrapper

>
>
>
> ~Ethan~

Ethan,

I tried you code suggestions but got errors.
However, this works:

from functools import wraps

def fix_args(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
args = (arg.replace('_', '') for arg in args)
for kv in kwargs:
kwargs[kv] = kwargs[kv].replace('_', '')
return fn(*args, **kwargs)
return wrapper

@fix_args
def foo(a1="", a2="", b1="", b2=""):
print(a1)
print(a2)
print(b1)
print(b2)
print ""

foo ('a1a1_x', 'a2a2_x', 'b1b1_x', 'b2b2_____x')
foo (a1='a1a1_x', a2='a2a2_x', b1='b1b1_x', b2='b2b2_____x')
foo ('a1a1_x', 'a2a2_x', b1='b1b1_x', b2='b2b2_____x')

Bruce

, Nov 16, 2012