how to get the ordinal number in list

Chris Angelico rosuav at gmail.com
Tue Aug 12 21:31:59 EDT 2014


On Wed, Aug 13, 2014 at 10:47 AM, Steven D'Aprano
<steve+comp.lang.python at pearwood.info> wrote:
> Chris Angelico wrote:
>
>> On Mon, Aug 11, 2014 at 7:44 PM, Steven D'Aprano <steve at pearwood.info>
>> wrote:
>>> I think this is why both declarative and functional programming idioms
>>> will remain niche (although important niches). Most tasks are inherently
>>> imperative to at least some degree, and often a *great* degree.
>>
>> Maybe that's true as a whole, but there are certainly ways in which
>> certain declarative or functional elements can be extremely useful to
>> an otherwise-imperative program.
>
> Oh yes! I think that using functional idioms is *very* valuable. List comps
> and similar are great, but more than that, the idea of writing idempotent
> functions with no side-effects (except IO) is (I believe) vital for good
> programming. Relying on argument passing rather communicating by global
> variables (or the OO equivalent, instance attributes) is likewise vital.
> ...
> (It is my belief that inappropriate coupling is the great evil in
> programming. Having too much coupling between parts of your code which
> ought to be independent is like Ebola for reliable code, contagious and
> deadly. I'm always looking for ways to reduce coupling between parts of my
> code, and functional idioms are good for that.)

There are times when coupling is unavoidable, but yes, it's usually
detrimental to the code. Sometimes the alternatives are worse, but
coupling is still bad. I have TODOs against certain pieces of code
where I can't think of a clean way to decouple them...

>> I've sometimes done some extremely declarative coding in places; my
>> MUD client builds its menus by looking for specially-named functions
>> and getting some metadata from them to work out what the menu item
>> name should be. An approximate Python equivalent would be:
>>
>> @filemenu("E_xit")
>> def exit():
>>     prompt("Do you really want to exit?")
>>
>> where the presence of the function is what causes the menu item to
>> exist. In this case, the 'filemenu' decorator is probably imperative
>> code that adds the menu item to the File menu, but if you're reading
>> through a source file that has a bunch of functions like that, you'd
>> have to agree that that's a declarative style of coding. And it's a
>> style that works well for this kind of thing.
>
> I don't think I would agree that's declarative style. I think that's a form
> of imperative programming, where the syntax is:
>
>     @ make menu
>     def function: ...
>
> rather than:
>
>     def function: ...
>     make menu (function)
>
> but I wouldn't start a Holy War over it :-)

In a sense, yes. That's partly because Python doesn't really have the
concept that I'm using here. Here's the actual code (it's Pike):

constant file_closewindow="E_xit";
int closewindow()
{
... actual body of function isn't significant ...
}

The key here is the module-level constant which is "file_" followed by
the name of a function. So a more direct translation into Python would
be:

file_closewindow="E_xit"
def closewindow():
    ... blah blah ...

but since Python code tends to have uppercase constants, this would be
frowned on. Also, it's hard in Python to "enumerate constants", as
there's no such thing (Pike's constants are available at a slightly
different level, which makes them easy to find).

What might make it more declarative than imperative, even in Python,
is that the *order* of items on the menu is alphabetical by function
name, and thus has nothing to do with their position in the file. If
the decorator actually added the items to the menu immediately, their
positions would be based on order in the file; to do them
alphabetically by function name, you basically need to collect them
all up and create them all at the end. That's how the code works in
Pike - a quick loop in the initialization code runs over the constants
and adds the menu items, which means the constants are completely
non-executable.

It really is hard to draw the line. Ultimately, the CPU (at least, if
it's of any architecture I've worked with) doesn't execute declarative
or functional code, just as it doesn't execute callbacks or subthread
multiplexing or anything like that. You need to have, somewhere, a bit
of imperative code (usually a simple loop) that deals with the other
types... which might be called an interpreter. In fact, *all* high
level code is, in a sense, declarations to a lower level interpreter -
consider the distinctions between various Python interpreters (even
some that run inside your web browser), and how they all obey the same
declarations, but implement them completely differently.

> [ quoting FOLDOC ]
>    An example of an imperative (but non-procedural) language is a
>    data manipulation language for a relational database
>    management system.  This specifies changes to the database
>    but does not necessarily require anyone to specify a sequence
>    of steps.
>
>    Both contrast with declarative languages, which specify
>    neither explicit state manipulation nor a sequence of steps.
> [end quote]
>
> You'll note that it suggests SQL would count as an imperative language, but
> Wikipedia's article on declarative languages gives SQL as a paragon of
> declarative languages!
>
> http://en.wikipedia.org/wiki/Declarative_programming

Yeah, it's hard to draw the line. I like to look at SQL as a language
that specifies an end result without specifying how to get there [1]
and Python as a language that specifies exactly what to do. According
to FOLDOC's definition, both of those are imperative languages, but
the techniques for developing and debugging them vary significantly.

Actually, that's probably the most useful way to distinguish,
especially since it's easy to slide from one paradigm to another in
the same language, even in the same program (your event handler is
triggered by the magic of callbacks, but inside it, your code is
strictly imperative). How do you go about debugging a piece of code?
If you reorder things inside the code itself with the expectation that
it'll have a clear and simple effect on the code's behaviour, that's
imperative. If you tweak the external algorithms or change
non-executable code in order to achieve what you want, that's
declarative.

> In Python terms, we might consider "import" to be declarative, since it
> specifies what to do (load a name from a module) but not how to perform
> it. "import spam" might find spam anywhere, in any form (source code, byte
> code, machine code, in a zip file, somewhere on the disk, inside the Python
> executable itself), which to my mind suggests a declarative idiom. Or such
> things as test discovery, where unittest and doctest will automatically
> locate and run tests. (The tests themselves are typically written in a
> procedural paradigm.) Otherwise, Python doesn't really have a lot to offer
> in the declarative paradigm.

It's just as declarative as 'def' or 'class'. Technically, they're all
executable statements; when the interpreter reaches one of them, it
goes off and does what you asked it to do, and then continues on. But
practically, they're usually used declaratively - "if I put this code
in my file, I will have a function with this name". Most people will
happily write Python functions with 'def' in the same way they'd write
C functions, or PHP functions, or anything else, and the significance
of def being executable is only seen when you have nested functions
etc. Even order of execution is almost never a problem, except for
class inheritance - and frankly, I've never seen anyone define a
superclass lower in a file than its subclasses, in *any* language.
When was the last time you needed to be aware that any of these three
(import/def/class) was truly executable?

ChrisA

[1] There are exceptions - the CREATE INDEX command in various engines
lets you do a lot more specification, and there are abominations in a
popular low-end database that let you stipulate how a SELECT statement
is to be processed, but the intent of SQL is to specify only the end
result.



More information about the Python-list mailing list