Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #92534 > unrolled thread

Passing new fields to an object

Started byPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
First post2015-06-12 16:53 +0100
Last post2015-06-13 09:49 +0200
Articles 10 — 4 participants

Back to article view | Back to comp.lang.python


Contents

  Passing new fields to an object Paulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt> - 2015-06-12 16:53 +0100
    Re: Passing new fields to an object gst <g.starck@gmail.com> - 2015-06-12 09:17 -0700
      Re: Passing new fields to an object Paulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt> - 2015-06-12 19:26 +0100
    Re: Passing new fields to an object Peter Otten <__peter__@web.de> - 2015-06-12 18:17 +0200
      Re: Passing new fields to an object Paulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt> - 2015-06-12 19:34 +0100
        Re: Passing new fields to an object Peter Otten <__peter__@web.de> - 2015-06-12 21:12 +0200
          Re: Passing new fields to an object Paulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt> - 2015-06-13 04:29 +0100
    Re: Passing new fields to an object Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2015-06-13 01:25 +0000
      Re: Passing new fields to an object Paulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt> - 2015-06-13 04:33 +0100
      Re: Passing new fields to an object Peter Otten <__peter__@web.de> - 2015-06-13 09:49 +0200

#92534 — Passing new fields to an object

FromPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
Date2015-06-12 16:53 +0100
SubjectPassing new fields to an object
Message-ID<mlev91$4ji$1@speranza.aioe.org>
I would like to do something like this:

class C:
	def __init__(self,**parms):
	...

c=C(f1=1,f2=None)

I want to have, for the object
	self.f1=1
	self.f2=None

for an arbitrary number of parameters.

What is the best way to achieve this?

Thanks

[toc] | [next] | [standalone]


#92536

Fromgst <g.starck@gmail.com>
Date2015-06-12 09:17 -0700
Message-ID<e120ad04-e4f1-4f2c-b004-0c70b85f4047@googlegroups.com>
In reply to#92534
Le vendredi 12 juin 2015 11:53:24 UTC-4, Paulo da Silva a écrit :
> I would like to do something like this:
> 
> class C:
> 	def __init__(self,**parms):
> 	...
> 
> c=C(f1=1,f2=None)
> 
> I want to have, for the object
> 	self.f1=1
> 	self.f2=None
> 
> for an arbitrary number of parameters.
> 
> What is the best way to achieve this?
> 
> Thanks

in the __init__, simply do:

    self.__dict__.update(**parms)

regards,

gst.

[toc] | [prev] | [next] | [standalone]


#92543

FromPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
Date2015-06-12 19:26 +0100
Message-ID<mlf87v$qmk$1@speranza.aioe.org>
In reply to#92536
On 12-06-2015 17:17, gst wrote:
> Le vendredi 12 juin 2015 11:53:24 UTC-4, Paulo da Silva a écrit :

> in the __init__, simply do:
> 
>     self.__dict__.update(**parms)
> 
> regards,
> 
Ok. Thanks.

[toc] | [prev] | [next] | [standalone]


#92537

FromPeter Otten <__peter__@web.de>
Date2015-06-12 18:17 +0200
Message-ID<mailman.429.1434125838.13271.python-list@python.org>
In reply to#92534
Paulo da Silva wrote:

> I would like to do something like this:
> 
> class C:
> def __init__(self,**parms):
> ...
> 
> c=C(f1=1,f2=None)
> 
> I want to have, for the object
> self.f1=1
> self.f2=None
> 
> for an arbitrary number of parameters.
> 
> What is the best way to achieve this?

Use a dict ;)

While I'd recommend that you spell out the possible arguments here is one 
way to not obey my advice:

>>> import types
>>> class C(types.SimpleNamespace):
...     pass
... 
>>> c = C(f1=1, f2=None)
>>> c
C(f1=1, f2=None)

If you want to do it manually you can either use

for name, value in parms.items():
    setattr(self, name, value)

or the less general

self.__dict__.update(parms)

Again, if you don't know the names in advance the appropriate data structure 
is a dict.

[toc] | [prev] | [next] | [standalone]


#92544

FromPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
Date2015-06-12 19:34 +0100
Message-ID<mlf8mu$ro2$1@speranza.aioe.org>
In reply to#92537
On 12-06-2015 17:17, Peter Otten wrote:
> Paulo da Silva wrote:
> 
...

> 
>>>> import types
>>>> class C(types.SimpleNamespace):
> ...     pass
> ... 
>>>> c = C(f1=1, f2=None)
>>>> c
> C(f1=1, f2=None)
> 

Thanks for all your explanations.
This solution works. Would you please detail a little on how it works?
Or just point me out some readings.
I am confused because types.SimpleNamespace seems to be a class!
From docs ...:
class SimpleNamespace:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)
    def __repr__(self):
        keys = sorted(self.__dict__)
        items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys)
        return "{}({})".format(type(self).__name__, ", ".join(items))
    def __eq__(self, other):
        return self.__dict__ == other.__dict__

[toc] | [prev] | [next] | [standalone]


#92548

FromPeter Otten <__peter__@web.de>
Date2015-06-12 21:12 +0200
Message-ID<mailman.436.1434136357.13271.python-list@python.org>
In reply to#92544
Paulo da Silva wrote:

> On 12-06-2015 17:17, Peter Otten wrote:
>> Paulo da Silva wrote:
>> 
> ...
> 
>> 
>>>>> import types
>>>>> class C(types.SimpleNamespace):
>> ...     pass
>> ...
>>>>> c = C(f1=1, f2=None)
>>>>> c
>> C(f1=1, f2=None)
>> 
> 
> Thanks for all your explanations.
> This solution works. Would you please detail a little on how it works?
> Or just point me out some readings.
> I am confused because types.SimpleNamespace seems to be a class!

It *is* a class, and by making C a subclass of SimpleNamespace C inherits 
the initialiser which does the actual work of updating the __dict__ of the C 
instance.

> From docs ...:

> class SimpleNamespace:
>     def __init__(self, **kwargs):
>         self.__dict__.update(kwargs)

The actual implementation is written in C (the language used to implement 
the CPython interpreter), but following the example in the docs you can make 
your own SimpleNamespace...

>>> class MySimpleNamespace:
...     def __init__(self, **parms): self.__dict__.update(parms)
... 
>>> m = MySimpleNamespace(a=1, b=2)
>>> m.a
1
>>> m.b
2

and when you subclass it the subclass inherits the behaviour:

>>> class C(MySimpleNamespace):
...     pass
... 
>>> c = C(x=10, y=20)
>>> c.x
10
>>> c.y
20

[toc] | [prev] | [next] | [standalone]


#92577

FromPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
Date2015-06-13 04:29 +0100
Message-ID<mlg83e$tnr$1@speranza.aioe.org>
In reply to#92548
On 12-06-2015 20:12, Peter Otten wrote:
> Paulo da Silva wrote:
> 
>> On 12-06-2015 17:17, Peter Otten wrote:
>>> Paulo da Silva wrote:
>>>
>> ...
...

> It *is* a class, and by making C a subclass of SimpleNamespace C inherits 
> the initialiser which does the actual work of updating the __dict__ of the C 
> instance.
> 

OK, OK ...
Somehow I "changed" my mind to think SimpleNamespace as an argument of
__init__ and not as a subclass. I should have looked better before
responding.
Sorry.

Thank you very much.

[toc] | [prev] | [next] | [standalone]


#92575

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2015-06-13 01:25 +0000
Message-ID<557b868c$0$11125$c3e8da3@news.astraweb.com>
In reply to#92534
On Fri, 12 Jun 2015 16:53:08 +0100, Paulo da Silva wrote:

> I would like to do something like this:
> 
> class C:
> 	def __init__(self,**parms):
> 	...
> 
> c=C(f1=1,f2=None)
> 
> I want to have, for the object
> 	self.f1=1
> 	self.f2=None
> 
> for an arbitrary number of parameters.
> 
> What is the best way to achieve this?


Others have suggested that you update the instance dict with the keyword 
parameters:

    self.__dict__.update(parms)


But I suggest that you should be very careful with this technique, 
because it can lead to surprising problems and bugs in your code. If your 
class has methods (and what sort of class doesn't have methods?), this 
will override them and lead to mysterious failures in your code:

instance = C(a=1, b=2, method=3)
# much later
result = instance.method(args)  # will raise exception


You should use SimpleNamespace, as Peter suggests, but *not* subclass it. 
If you subclass it and add methods:

class C(SimpleNamespace):
    def foo(self, arg):
        print("called foo")


then you risk overriding foo method, as above. If you don't add methods, 
there is no need to subclass.

Instead, use composition: your class should *contain* a SimpleNamespace, 
not *be* one:

class C:
    def __init__(self, **param):
        self.ns = SimpleNamespace(param)
    def __getattr__(self, attrname):
        return getattr(self.ns, attrname)
    def foo(self, arg):
        print("called foo")


instance = C(a=1, b=2, foo=3)
# later
instance.foo("x")  # prints "called foo"


The special method __getattr__ only runs if the attribute name is not 
found in the usual way, so the method foo will continue to be found and 
not be overridden by the param foo.



-- 
Steve

[toc] | [prev] | [next] | [standalone]


#92578

FromPaulo da Silva <p_s_d_a_s_i_l_v_a_ns@netcabo.pt>
Date2015-06-13 04:33 +0100
Message-ID<mlg8a7$u38$2@speranza.aioe.org>
In reply to#92575
On 13-06-2015 02:25, Steven D'Aprano wrote:
> On Fri, 12 Jun 2015 16:53:08 +0100, Paulo da Silva wrote:
> 
...

> 
> You should use SimpleNamespace, as Peter suggests, but *not* subclass it. 
> If you subclass it and add methods:
> 
> class C(SimpleNamespace):
>     def foo(self, arg):
>         print("called foo")
> 
> 
> then you risk overriding foo method, as above. If you don't add methods, 
> there is no need to subclass.
> 
> Instead, use composition: your class should *contain* a SimpleNamespace, 
> not *be* one:
> 
> class C:
>     def __init__(self, **param):
>         self.ns = SimpleNamespace(param)
>     def __getattr__(self, attrname):
>         return getattr(self.ns, attrname)
>     def foo(self, arg):
>         print("called foo")
> 
> 
> instance = C(a=1, b=2, foo=3)
> # later
> instance.foo("x")  # prints "called foo"
> 
> 
> The special method __getattr__ only runs if the attribute name is not 
> found in the usual way, so the method foo will continue to be found and 
> not be overridden by the param foo.

Always learning!

Thanks a lot.

[toc] | [prev] | [next] | [standalone]


#92585

FromPeter Otten <__peter__@web.de>
Date2015-06-13 09:49 +0200
Message-ID<mailman.453.1434181789.13271.python-list@python.org>
In reply to#92575
Steven D'Aprano wrote:

> On Fri, 12 Jun 2015 16:53:08 +0100, Paulo da Silva wrote:
> 
>> I would like to do something like this:
>> 
>> class C:
>> def __init__(self,**parms):
>> ...
>> 
>> c=C(f1=1,f2=None)
>> 
>> I want to have, for the object
>> self.f1=1
>> self.f2=None
>> 
>> for an arbitrary number of parameters.
>> 
>> What is the best way to achieve this?
> 
> 
> Others have suggested that you update the instance dict with the keyword
> parameters:
> 
>     self.__dict__.update(parms)
> 
> 
> But I suggest that you should be very careful with this technique,
> because it can lead to surprising problems and bugs in your code. If your
> class has methods (and what sort of class doesn't have methods?), this
> will override them and lead to mysterious failures in your code:
> 
> instance = C(a=1, b=2, method=3)
> # much later
> result = instance.method(args)  # will raise exception
> 
> 
> You should use SimpleNamespace, as Peter suggests, but *not* subclass it.
> If you subclass it and add methods:
> 
> class C(SimpleNamespace):
>     def foo(self, arg):
>         print("called foo")
> 
> 
> then you risk overriding foo method, as above. If you don't add methods,
> there is no need to subclass.

I sometimes do it anyway if only to get a meaningful class name.

> Instead, use composition: your class should *contain* a SimpleNamespace,
> not *be* one:
> 
> class C:
>     def __init__(self, **param):
>         self.ns = SimpleNamespace(param)

**param

>     def __getattr__(self, attrname):
>         return getattr(self.ns, attrname)
>     def foo(self, arg):
>         print("called foo")
> 
> 
> instance = C(a=1, b=2, foo=3)
> # later
> instance.foo("x")  # prints "called foo"

>>> c = C(ns=42)
>>> assert c.ns == 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AssertionError

Yes, it's less likely, but now that the OP has two convenient ways to 
produce a name clash I think it's time to repeat that there is one bullet-
proof approach: use a dict ;)

> The special method __getattr__ only runs if the attribute name is not
> found in the usual way, so the method foo will continue to be found and
> not be overridden by the param foo.

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web