From: WANG Cong on

Hi, list!

I have a doubt about the design of dynamic attribute creation by
assignments in Python.

As we know, in Python, we are able to create a new attribute of
a class dynamically by an assignment:

>>> class test: pass
....
>>> test.a = "hello"
>>> test.a
'hello'
>>>

However, I still don't get the points why Python designs it like this.

My points are:

1) Modifying a class attribute is metaprogramming, and this is modifying
a class, i.e. adding a new attribute to it, thus this should belong
to metaprogramming. (I know, strictly speaking, maybe my definition of
"metaprogramming" here is incorrect, I _do_ welcome someone could
correct me if I am really wrong, but that is not the main point here,
please don't go off-topic.)

2) Metaprogramming should be distinguished with non-meta programming,
like templates in C++, it is obvious to see if you are using template
metaprogramming in C++.

3) Thus, allowing dynamic attribute creation by assignment _by default_
is not a good design for me. It is not obvious at all to see if I am
doing metaprogramming at a first glance.

4) Also, this will _somewhat_ violate the OOP princples, in OOP,
this is and should be implemented by inherence.

5) This could hide errors silently, for example, when I do:

>>>test.typooooo = "blah"

I am expecting Python will compllain that "Hey! You have a typo in the
attribute name!". Also, this could make code worse to read, if I
add a new attribute in one place, and add another one in the another
place, and so on, what attributes the hell do I have finally?!

I know someone will say you can change this by overriding the
__set_attr__ function, like Recipe 6.3 in Python Cookbook.
However, this is not default. In my points of view, a better design
should be:

1) Disallow dynamic attribute creations by assignments _by default_,
thus I expect an error when I do:

>>> foo.new_attr = "blah"
AttributeError:

by default.

2) For people who want to add a new attribute at runtime,
but not to override __set_attr__, he/she should switch to:

>>> setattr(foo, "new_attr", "blah")

This will be more like doing metaprogramming rather than non-meta
programming, at least more obvious than using an assignment.

3) Allow users who don't like this to change by __set_attr__,
of course.

Someone argued with me that Python is a dynamic language,
allowing this is natural. True, I do understand that attributes in
Python are stored in an internal dictionary (__dict__), allowing
assignments to an non-existing key is natural. However, this will be
a little different when we talk about classes attributes, simple
assignments could have side-effects, besides the traditional assignments
effect, like in C, that is, creating a new attribute silently. So even
from a view of beauty, this is not a good design.

I hope someone could teach me more about why Python design it like
it is. Any reply is more than welcome.

Thanks for your time!

--
Live like a child, think like the god.

From: Richard Thomas on
On Jun 25, 2:15 pm, WANG Cong <xiyou.wangc...(a)gmail.com> wrote:
> Hi, list!
>
> I have a doubt about the design of dynamic attribute creation by
> assignments in Python.
>
> As we know, in Python, we are able to create a new attribute of
> a class dynamically by an assignment:
>
>
>
> >>> class test: pass
> ...
> >>> test.a = "hello"
> >>> test.a
> 'hello'
>
> However, I still don't get the points why Python designs it like this.
>
> My points are:
>
> 1) Modifying a class attribute is metaprogramming, and this is modifying
> a class, i.e. adding a new attribute to it, thus this should belong
> to metaprogramming. (I know, strictly speaking, maybe my definition of
> "metaprogramming" here is incorrect, I _do_ welcome someone could
> correct me if I am really wrong, but that is not the main point here,
> please don't go off-topic.)
>
> 2) Metaprogramming should be distinguished with non-meta programming,
> like templates in C++, it is obvious to see if you are using template
> metaprogramming in C++.
>
> 3) Thus, allowing dynamic attribute creation by assignment _by default_
> is not a good design for me. It is not obvious at all to see if I am
> doing metaprogramming at a first glance.
>
> 4) Also, this will _somewhat_ violate the OOP princples, in OOP,
> this is and should be implemented by inherence.
>
> 5) This could hide errors silently, for example, when I do:
>
> >>>test.typooooo = "blah"
>
> I am expecting Python will compllain that "Hey! You have a typo in the
> attribute name!". Also, this could make code worse to read, if I
> add a new attribute in one place, and add another one in the another
> place, and so on, what attributes the hell do I have finally?!
>
> I know someone will say you can change this by overriding the
> __set_attr__ function, like Recipe 6.3 in Python Cookbook.
> However, this is not default. In my points of view, a better design
> should be:
>
> 1) Disallow dynamic attribute creations by assignments _by default_,
> thus I expect an error when I do:
>
> >>> foo.new_attr = "blah"
>
> AttributeError:
>
> by default.
>
> 2) For people who want to add a new attribute at runtime,
> but not to override __set_attr__, he/she should switch to:
>
> >>> setattr(foo, "new_attr", "blah")
>
> This will be more like doing metaprogramming rather than non-meta
> programming, at least more obvious than using an assignment.
>
> 3) Allow users who don't like this to change by __set_attr__,
> of course.
>
> Someone argued with me that Python is a dynamic language,
> allowing this is natural. True, I do understand that attributes in
> Python are stored in an internal dictionary (__dict__), allowing
> assignments to an non-existing key is natural. However, this will be
> a little different when we talk about classes attributes, simple
> assignments could have side-effects, besides the traditional assignments
> effect, like in C, that is, creating a new attribute silently. So even
> from a view of beauty, this is not a good design.
>
> I hope someone could teach me more about why Python design it like
> it is. Any reply is more than welcome.
>
> Thanks for your time!
>
> --
> Live like a child, think like the god.

If you desperately want to limit the attribute assignments that can be
performed on an object you can set the __slots__ attribute of its
type. However, the Python ethos has always been to restrict as little
as necessary to provide the tools it needs. Performing additional
checks every time an attribute assignment is performed is completely
unnecessary. Remember that unlike C these checks would have to be
performed at run-time.

Richard.
From: Bruno Desthuilliers on
WANG Cong a �crit :
> Hi, list!
>
> I have a doubt about the design of dynamic attribute creation by
> assignments in Python.
>
> As we know, in Python, we are able to create a new attribute of
> a class dynamically by an assignment:
>
>>>> class test: pass
> ...
>>>> test.a = "hello"
>>>> test.a
> 'hello'
>
> However, I still don't get the points why Python designs it like this.
>
> My points are:
>
(snip)

Python's classes are plain objects, and like any other object are
created at runtime. Having to special-case them would break the
simplicity and uniformity of Python for no good reason. Just like
there's no good reason to make setattr() working differently for class
and non-class objects.

FWIW, what you call "metaprogramming" is just ordinary programming - at
least in Python. All your fears and concerns about Python's dynamism are
just a priori learned from the "mainstream" B&D culture. From
experience, these are non-issues - unless of course misused by some
fool, but then there's no way to prevent stupids from doing stupid
things. So, yes, Python rely quite a lot on programmer's common sense
and discipline. Now the good news is that is JustWork(tm).





From: Steven D'Aprano on
On Fri, 25 Jun 2010 14:15:12 +0100, WANG Cong wrote:

> Hi, list!
>
> I have a doubt about the design of dynamic attribute creation by
> assignments in Python.
>
> As we know, in Python, we are able to create a new attribute of a class
> dynamically by an assignment:
>
>>>> class test: pass
> ...
>>>> test.a = "hello"
>>>> test.a
> 'hello'
>>>>
>>>>
> However, I still don't get the points why Python designs it like this.
>
> My points are:
>
> 1) Modifying a class attribute is metaprogramming, and this is modifying
> a class, i.e. adding a new attribute to it, thus this should belong to
> metaprogramming.

Yes, isn't it wonderful? In other languages, metaprogramming is deepest
black magic, or even completely impossible. In Python it is so easy that
anyone can do it, and it is something beginners learn.


> 2) Metaprogramming should be distinguished with non-meta programming,
> like templates in C++, it is obvious to see if you are using template
> metaprogramming in C++.

Why should it be?


> 3) Thus, allowing dynamic attribute creation by assignment _by default_
> is not a good design for me. It is not obvious at all to see if I am
> doing metaprogramming at a first glance.

Why do you care if you are doing metaprogramming? Perhaps other languages
make it seem difficult and scary, but in Python it is not. It is simple
and easy.


> 4) Also, this will _somewhat_ violate the OOP princples, in OOP, this is
> and should be implemented by inherence.

Perhaps, and perhaps not. But Python has never pretended to slavishly
follow OOP "principles". Python does what works, not necessarily what is
a "pure" design. Python has functional programming, procedural
programming, and OO programming, and happily mixes them all together.


> 5) This could hide errors silently, for example, when I do:
>
>>>>test.typooooo = "blah"

Yes, that is one downside to Python's dynamicism. The solutions are:

* Unit tests, unit tests, unit tests. Then more unit tests.
(You're writing them anyway, aren't you?)
* Run PyChecker or PyLint to check the source code for errors.
* Don't make typos. *smiles*


> I am expecting Python will compllain that "Hey! You have a typo in the
> attribute name!". Also, this could make code worse to read, if I add a
> new attribute in one place, and add another one in the another place,
> and so on, what attributes the hell do I have finally?!

Then don't do that.


> I know someone will say you can change this by overriding the
> __set_attr__ function, like Recipe 6.3 in Python Cookbook. However, this
> is not default. In my points of view, a better design should be:
>
> 1) Disallow dynamic attribute creations by assignments _by default_,

There are many languages that do that. Python is not one of them. Python
is *designed* to be a dynamic language. If you don't like dynamic
languages, then you have many, many, many other choices. Perhaps such a
language is better for *you*. Perhaps such non-dynamic languages are
better for huge applications written by thousands of developers. But
Python is designed to be a rapid prototyping language, and as such,
dynamicism is a feature, not a bug.



--
Steven
From: WANG Cong on
On 06/25/10 17:25, Steven D'Aprano <steve(a)REMOVE-THIS-cybersource.com.au> wrote:

> On Fri, 25 Jun 2010 14:15:12 +0100, WANG Cong wrote:
>
>> Hi, list!
>>
>> I have a doubt about the design of dynamic attribute creation by
>> assignments in Python.
>>
>> As we know, in Python, we are able to create a new attribute of a class
>> dynamically by an assignment:
>>
>>>>> class test: pass
>> ...
>>>>> test.a = "hello"
>>>>> test.a
>> 'hello'
>>>>>
>>>>>
>> However, I still don't get the points why Python designs it like this.
>>
>> My points are:
>>
>> 1) Modifying a class attribute is metaprogramming, and this is modifying
>> a class, i.e. adding a new attribute to it, thus this should belong to
>> metaprogramming.
>

(Thanks for your reply.)

> Yes, isn't it wonderful? In other languages, metaprogramming is deepest
> black magic, or even completely impossible. In Python it is so easy that
> anyone can do it, and it is something beginners learn.
>


The point is why making metaprogramming easy is wonderful? AND, even if
it were wonderful, why only this one, i.e. creating attributes by
assignments, not other things?

In my points of view, a programming language is wonderful only when it
is designed so, there is no other things like this one in Python, AFAIK,
are as simple as this one, thus making this one really odd to me. :-)

>
>> 2) Metaprogramming should be distinguished with non-meta programming,
>> like templates in C++, it is obvious to see if you are using template
>> metaprogramming in C++.
>
> Why should it be?


It is, if you consider other things of metaprogramming in Python. For
example, deleting an attribute.

>
>
>> 3) Thus, allowing dynamic attribute creation by assignment _by default_
>> is not a good design for me. It is not obvious at all to see if I am
>> doing metaprogramming at a first glance.
>
> Why do you care if you are doing metaprogramming? Perhaps other languages
> make it seem difficult and scary, but in Python it is not. It is simple
> and easy.
>


I do care, programming for a class is quite different from programming
for a non-class, even from a historical reason. They sit in different
levels of programming.

>
>> 4) Also, this will _somewhat_ violate the OOP princples, in OOP, this is
>> and should be implemented by inherence.
>
> Perhaps, and perhaps not. But Python has never pretended to slavishly
> follow OOP "principles". Python does what works, not necessarily what is
> a "pure" design. Python has functional programming, procedural
> programming, and OO programming, and happily mixes them all together.
>

"Happily mixes them all together" doesn't mean it is elegant. :)


>
>> 5) This could hide errors silently, for example, when I do:
>>
>>>>>test.typooooo = "blah"
>
> Yes, that is one downside to Python's dynamicism. The solutions are:
>
> * Unit tests, unit tests, unit tests. Then more unit tests.
> (You're writing them anyway, aren't you?)
> * Run PyChecker or PyLint to check the source code for errors.
> * Don't make typos. *smiles*
>


Well, I am talking in the language design level, if we could solve
this problem in the language design level, why do we need to bother
these things?

>
>> I am expecting Python will compllain that "Hey! You have a typo in the
>> attribute name!". Also, this could make code worse to read, if I add a
>> new attribute in one place, and add another one in the another place,
>> and so on, what attributes the hell do I have finally?!
>
> Then don't do that.
>

Yeah, "don't do that" is one thing, "Python allows to do that" is
another thing.


>
>> I know someone will say you can change this by overriding the
>> __set_attr__ function, like Recipe 6.3 in Python Cookbook. However, this
>> is not default. In my points of view, a better design should be:
>>
>> 1) Disallow dynamic attribute creations by assignments _by default_,
>
> There are many languages that do that. Python is not one of them. Python
> is *designed* to be a dynamic language. If you don't like dynamic
> languages, then you have many, many, many other choices. Perhaps such a
> language is better for *you*. Perhaps such non-dynamic languages are
> better for huge applications written by thousands of developers. But
> Python is designed to be a rapid prototyping language, and as such,
> dynamicism is a feature, not a bug.

Such as?

As I said in the previous email, this is not so much related with
dynamic programmin or not. Using 'setattr(xxxx)' could also prove Python
is a dynamic programming, but Python doesn't choose this by default.

Thanks!

--
Live like a child, think like the god.