473,765 Members | 2,061 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

macro FAQ

Here's a proposed Q&A for the FAQ based on a couple recent
threads. Appropriate comments appreciated

X.Y: Why doesn't Python have macros like in Lisp or Scheme?

Before answering that, a clarification on what 'macro' means.
A Lisp macro is a way of modifying code when that code is first
defined. It can rearrange the structure of the code, and add and
remove parts of it. Unlike C's #define macro language, Lisp
macros understand the structure of the expression and the
context (or "closure") in which it is found.

Here's a simple example of what a macro might do for Python.
A complaint about Python is that constructors for simple data
types require typing the parameter names three times, as in

class Country:
def __init__(self, name, capitol):
self.name = name
self.capitol = capitol

Suppose you could create a new way to create functions, which
looked at the argument list and automatically set the corresponding
member. This would let you replace the above with something
more like

class Country:
def __init__(self, name, capitol) [arg_assign]:
pass

where the 'arg_assign' would use the function definition
and code to make a new function used in place of the
existing one and with the 'self.name = name' and
'self.capitol = capitol' code automatically added to
the front of the code.

This is a very powerful technique and especially nice for
high-performance code where the macro can optimize
code before it is actually evaluated. Macros work well in
Lisp or Scheme, where the code is the data, all written
pretty much as a parse tree.

The first problem with implementing a macro system in Python
is coming up with a readable syntax; that is, how it's "spelled."
The example shown above, using the [] after the function
definition, was taken from a proposed syntax for adding
function modifiers like 'staticmethod' and 'classmethod' to
Python.

The second problem is that Python's code blocks do not
store the original parse tree, so there's nothing to manipulate.
If you use 'dir()' or the inspect module you'll see some fields
like the list of argument names and the default value to use
for the fields. Nowhere will you find the original parse tree.
(The C implementation of Python does give access to the
Python byte code, but this is not part of the language
specification and Java implementation doesn't support it.)

These problems can be resolved, and Dylan shows that
an infix-based/Algol-like language can support macros
similar to those used in Lisp.

The deeper question is, should Python include macros?

People with a Lisp background might have a problem
understanding this viewpoint. Macros add flexibility, and
more flexibilty lets programmers be more productive; or
so the argument goes.

Those against including macros in Python point out that
Python has a different focus. It has a broad target audience.
Beginners can pick it up pretty easily yet advanced
developers also enjoy working in the language. New features,
like new builtin functions, additional core types, expanding
the standard libraries, list comprensions, metaclasses and
deriving from object, and macros, all make it harder to
learn how to use Python well and shifts the balance more
towards advanced programmers.

More importantly, the detractors -- including those
with plenty of experience using macros in Lisp -- argue that
macros cause dialects to form. Macros can modify other code to
make it fit the problem better, while functions only use other
code but make no modifications. This makes them very
powerful but means that understanding a section of code
requires also knowing about any macros which might use the
code. In an extreme case which wouldn't be used in real
projects, every * could be replaced with a +.

(As an aside, some proponents argue that macros and
functions are essentially the same. Alex Martelli made
an interesting observation about one difference: it's often
worthwhile to turn a set of code into a function even if it
is only called from one place, because it helps simplify
the code into smaller chucks which are easier to understand.
Macros, on the other hand, should almost never be used
unless they are used many times.)

With only one or a small group of people working together
on a project there is little problem. Macros help in developing
idioms specific to the problem and group. When groups
share code, they also share idioms, and anyone who has had
to deal with UK vs. US English knows the effect idioms have
in mututal understanding.

Those against macros say their benefits do not outweigh
the likelihood that the Python community will be broken up
into distinct subsets, where people from one group find it
hard to use code from another.

The proponents for macros say this has not been a problem
in Lisp. Macros are misused, but so are functions and classes.
The same community feedback which encourages people to
use proper coding styles also encourages people to use macros
correctly. Those against reassert that not only can it be a
problem but it's happened to them personally.

At this point the discussion usually breaks down, with the
Lispers pulling out the old canard about Python (and every
other language) being a half-complete, poor reimplementatio n
of Lisp, while Pythonistas trot out the expression "Lisp is like
a ball of mud. You can add any amount of mud to it and it
still looks like a ball of mud."

Those interested in actual language improvements then ask for
concrete examples of how macros might be used for Python.
So far, the examples given are ones which could equally well
be done in Python using metaclasses, properties, and other
existing mechanisms. For example, the arg_assign example
given above could, I think, be done with a modified__new__ .

The problem at this point seems to be that the two languages
have different enough object models and accepted best
practices that it's hard for an intuition based on Lisp to
know immediately how to apply that intuition to Python.

If you want to encourage Python to have macros, you must
therefore propose a syntax for it and give solid examples of
what the result would look like when applied to real Python
code. Simply stating that macros are needed is not good
enough nor are examples showing how macros are useful
for Lisp code. (Besides, believe it or not but some of us
don't know enough Lisp to follow your examples ;)

In the meanwhile, if you want to experiment with manipulating
code trees, you can use decompyle to turn byte code back
into Python source and the compiler module to turn source into
an AST and thence into byte code.

Andrew Dalke
da***@dalkescie ntific.com
Jul 18 '05
25 3256
Christos "TZOTZIOY" Georgiou <tz**@sil-tec.gr> writes:
On 24 Aug 2003 16:34:08 +0200, rumours say that Jacek Generowicz
<ja************ **@cern.ch> might have written:
The first thing you might try to do in Python is to add the fubar
method to the class source code, and re-evaluate it ... only to find
that your existing instances know nothing about the new method ... so
you have to go through the hassle of re-creating a gazillion of them,
before you can continue with what you were doing.


##### code starts here #####
class A(object): pass
a= A()
a.test() Traceback (most recent call last):
File "<pyshell#2 1>", line 1, in ?
a.test()
AttributeError: 'A' object has no attribute 'test' def test(self): print id(self)

A.test = test
a.test()

13111376

##### code ends here #####


No, you are missing the point. The point is that you want your source
code to be in sync with your program state, and you want your source
code to look natural. By "natural" I mean that you want your source
code to look like this:

class A(object):
def test(self):
print id(self)

rather than like this:

class A(object):
pass

def test(self):
print id(self)

A.test = test

If you still don't understand the motivation, please read the original
thread; there's no point in repeating the arguments all over again in
this thread, which is about something completely different.
Jul 18 '05 #21
Jacek Generowicz <ja************ **@cern.ch> writes:
jj*@pobox.com (John J. Lee) writes:
I'm sure you're capable of understanding this position, but the
argument has started going round in circles.
As I've said repeatedly:

- I do _not_ necessarily advocate the inclusion of macros in Python.


But you do advocate them in other languages, right? And that was a
significant part of the argument.

- I merely wish to dispel the myth that macros make code less
readable[*]: they _ease_ understanding of the code.
[*] And they don't fragment languages either.

John
Jul 18 '05 #22
jj*@pobox.com (John J. Lee) writes:
Jacek Generowicz <ja************ **@cern.ch> writes:
- I do _not_ necessarily advocate the inclusion of macros in Python.


But you do advocate them in other languages, right? And that was a
significant part of the argument.


You've lost me.

What I advocate is that, in the process of constructing an FAQ or
article about macros in Python, one should try to exclude material
which sounds like this:

Q: What is static typing, and why isn't it included in Python?

A: Static typing is the requirement that the programmer write his
code while standing up. Some people believe that this causes
infertility.

Or, to make a closer analogy:

Q: What are functions, and why aren't they included in Assembler ?

A: Functions are a very powerful means of creating
abstarctions. Some people believe that functions make a program
more difficult to understand. Functions also cause languages to
split, as evidenced by the existence of many different languages
which support functions. If any programmer on your project writes
a function, random parts of the code _you_ wrote will stop working;
shortly thereafter frogs will rain from the sky for forty days.

Put another way, I advocate avoiding FUD.

To this end, I have tried to provide information which would help
readers of this list, who are unfamiliar with Lisp-style macros, to
understand what Lisp-style macros are.

If I am involved in an argument, then it is an argument about what
Lisp-style macros _are_ and what they can or can't do ... completely
independently of any language in which they may or may not be
available, now or in the future.

I offer no opinion on whether Lisp-style macros are a good idea. I
would like people to form their own opinions on the matter, but I
would like those opinions to be based on fact rather than on FUD.

Now, what is it that _you_ are arguing ?
Jul 18 '05 #23
Jacek Generowicz <ja************ **@cern.ch> wrote in message news:<ty******* ******@lxplus01 4.cern.ch>...
==== Example 1: a debugging aid =============== =============== ==
=== Example 2: Alexander Schmolck's updating classes ===============


Here's another example of a real life situation
where I thought it'd be good to have macros in Python.
I was writing a GUI system and I had to define lots of
code twice, both for the x-axis and y-axis. Such
as
if y > self.y - bs and y < self.y + bs + self.height:
return (abs(x - self.x) < bs,
abs(x - (self.x + self.width)) < bs)
else:
return False, False
and then
if x > self.x - bs and x < self.x + bs + self.width:
return (abs(y - self.y) < bs,
abs(y - (self.y + self.height)) < bs)
else:
return False, False
Obviously this was quite unsatisfactory. I ended up
putting the axis code in a separate class so I could
use them interchangeably . I.e. If I passed
func(self.y, self.x)
and then
func(self.x, self.y)

I would get the same effect on both axises. But this
would've been an excellent place for macros IMO (unless
there's a more clever solution as a whole). Using macros
that combine both function call and "code block" syntax,
I could've written a simple function like this:

defBoth getSize(self):
return self.size

And it would've been expanded to

def getWidth(self):
return self.width

def getHeight(self) :
return self.height

The macro would've had to change all "size" to either
"width" or "height", and also change "pos" to either "x"
or "y" and so on.

This way, I could've got no duplicated code but
also a more intuitive interface than I currently have
(to get width, one needs to type obj.x.getSize() instead
of obj.getWidth()) . And it's obvious this kind of "defBoth"
wouldn't be added as a language level construct -- Thus
macros are the only good solution.
Jul 18 '05 #24
ha******@yahoo. com.au (Hannu Kankaanpää) writes:

if y > self.y - bs and y < self.y + bs + self.height:
return (abs(x - self.x) < bs,
abs(x - (self.x + self.width)) < bs)
else:
return False, False
and then
if x > self.x - bs and x < self.x + bs + self.width:
return (abs(y - self.y) < bs,
abs(y - (self.y + self.height)) < bs)
else:
return False, False

Obviously this was quite unsatisfactory. I ended up
putting the axis code in a separate class
Do you mean "function" rather than "class" ?
so I could
use them interchangeably . I.e. If I passed
func(self.y, self.x)
and then
func(self.x, self.y)

I would get the same effect on both axises. But this
would've been an excellent place for macros IMO
I don't see what you gain by using a macro, wrt to using a function in
_this_ case. As no Python macro system exists, I cannot form an
opinion of what the two approaches would look like in Python, but in
Lisp the calls to the macro would look just like the calls to the
function, I think. The only difference would be in the definition of
the macro/function, and the macro would be no simpler, so you wouldn't
really gain anything.
Using macros
that combine both function call and "code block" syntax,
I could've written a simple function like this:

defBoth getSize(self):
return self.size

And it would've been expanded to

def getWidth(self):
return self.width

def getHeight(self) :
return self.height

The macro would've had to change all "size" to either
"width" or "height", and also change "pos" to either "x"
or "y" and so on.
So you would not only replace whole symbols, but even fragments of
symbols (getSize -> getHeight), and thus macically/implicitly create
new symbols. Many people consider this bad practice. The objection
being that readers of the code come across a symbol in the source, go
off and search for its definition, and tricks like this mean that they
end up wasting their time.

The defstruct macro does this sort of thing; (defstruct foo ... )
would "magically" define a constructor called "make-foo" (and other
stuff). IIRC, the experience with defstruct led the designers of CLOS
to explicitly avoid doing this in CLOS' defclass macro (but I'm far
from the world's leading authority on Lisp history).

Incidentally, in this case, having a string based code representation
would make your job much easier than the structured representation
which Lisp uses. In a string you'd merely do a search and replace; in
an s-expression you would have to recursively search for all symbols
in all sub-expressions, and then do the search and replace within the
name of each symbol you find.
This way, I could've got no duplicated code but
also a more intuitive interface than I currently have
(to get width, one needs to type obj.x.getSize() instead
of obj.getWidth()) . And it's obvious this kind of "defBoth"
wouldn't be added as a language level construct -- Thus
macros are the only good solution.


Cue metaclass solution ... :-)

(I suspect that even with metaclasses, you wouldn't be able to avoid
eval ... and that amounts to "informally " writing a macro)
Jul 18 '05 #25
Jacek Generowicz <ja************ **@cern.ch> wrote in message news:<ty******* ******@pcepsft0 01.cern.ch>...
ha******@yahoo. com.au (Hannu Kankaanpää) writes:
Obviously this was quite unsatisfactory. I ended up
putting the axis code in a separate class
Do you mean "function" rather than "class" ?


Actually, I did mean class. Normally I'd have

class Widget:
def __init__(self):
self.x = 0
self.y = 0
self.width = 0
self.height = 0

def getWidth(self):
return self.width # normally they wouldn't be this empty!

def getHeight(self) :
return self.height

But by wrapping it inside a new class, I could get rid of
the duplication (partly, at least):

class Widget:
def __init__(self):
self.x = Widget.Axis(0, 0)
self.y = Widget.Axis(0, 0)

class Axis:
def __init__(self, pos, size)
self.pos = pos
self.size = size

def getSize(self): # this is only once here now
return self.size

While this tiny example doesn't show decrease in code
size, it shows that I have a common definition for all
"Axis"-specific code inside the appropriate Axis class.
Rest of the Widget methods would be in the widget class.
Thus self.x.getSize( ) instead of self.getWidth() .
so I could
use them interchangeably . I.e. If I passed
func(self.y, self.x)
and then
func(self.x, self.y)

I would get the same effect on both axises. But this
would've been an excellent place for macros IMO


I don't see what you gain by using a macro, wrt to using a function in
_this_ case.


Ok, it was a bad example. I hope the code above shows
a bit more clearly what I wanted. Anyway, without the code
in the axis-class, I would've had to often say

self.x = func(self.x, self.y, self.width, self.height)
self.y = func(self.y, self.x, self.height, self.width)

Instead of

func(self.x, self.y)
func(self.y, self.x)

Which could modify the axis-specific stuff within the
func()tion. (self.x is no longer a non-modifiable number,
but a modifiable class)
So you would not only replace whole symbols, but even fragments of
symbols (getSize -> getHeight), and thus macically/implicitly create
new symbols. Many people consider this bad practice.
Well, I don't, really. Like any macro that could do something
weird, it just needs to be properly understood by anyone who
wishes to read the code.
Incidentally, in this case, having a string based code representation
would make your job much easier than the structured representation
which Lisp uses. In a string you'd merely do a search and replace; in
an s-expression you would have to recursively search for all symbols
in all sub-expressions, and then do the search and replace within the
name of each symbol you find.


Well, such a recursive search isn't a problem - With help from
a macro ;)
This way, I could've got no duplicated code but
also a more intuitive interface than I currently have
(to get width, one needs to type obj.x.getSize() instead
of obj.getWidth()) . And it's obvious this kind of "defBoth"
wouldn't be added as a language level construct -- Thus
macros are the only good solution.


Cue metaclass solution ... :-)


How could metaclasses help? I'm quite inexperienced with them.
Anyway, if I take the eval route, I might as well do

defBoth('''getS ize():
return size''')

,retreive appropriate locals() from the stack and modify it
to include the new functions. I'd rather not, though :-)
Jul 18 '05 #26

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

699
34119
by: mike420 | last post by:
I think everyone who used Python will agree that its syntax is the best thing going for it. It is very readable and easy for everyone to learn. But, Python does not a have very good macro capabilities, unfortunately. I'd like to know if it may be possible to add a powerful macro system to Python, while keeping its amazing syntax, and if it could be possible to add Pythonistic syntax to Lisp or Scheme, while keeping all of the...
2
3491
by: Pete | last post by:
In Access 95/97 I used to be able to create pull down menus (File,Edit ...) from a macro. It seems there used to be some wizard for that. However in Access 2000 it seems you have to build your menus by customizing a toolbar. With this method you have to create a separate macro for every single menu and sub menu. The old method would allow me to include several menus (File/ print/ page setup ...) all within one macro. Now it seems I...
7
23555
by: Newbie_sw2003 | last post by:
Where should I use them? I am giving you my understandings. Please correct me if I am wrong: MACRO: e.g.:#define ref-name 99 The code is substituted by the MACRO ref-name. So no overhead. Execution is faster. Where will it be stotred?(Is it in bss/stack/?) FUNCTION:
3
8483
by: Alexander Ulyanov | last post by:
Hi all. Is it possible to pass the whole blocks of code (possibly including " and ,) as macro parameters? I want to do something like: MACRO(FOO, "Foo", "return "Foobar";", "foo(); bar();")
8
10865
by: lasek | last post by:
Hi...in some posts i've read...something about using macro rather then function...but difference ??. Best regards....
12
6537
by: Laurent Deniau | last post by:
I was playing a bit with the preprocessor of gcc (4.1.1). The following macros expand to: #define A(...) __VA_ARGS__ #define B(x,...) __VA_ARGS__ A() -nothing, *no warning* A(x) -x B() -nothing, *warning ISO C99 requires rest arguments to be used*
6
6437
by: Takeadoe | last post by:
Dear NG, Can someone assist me with writing the little code that is needed to run an update table query each time the database is opened? From what I've been able to glean from this group, the Autoexec Macro looks like the way to go. Could someone please assist? Thank you very much! Mike
5
3489
by: Bill | last post by:
This database has no forms. I am viewing an Access table in datasheet view. I'd like to execute a macro to execute a function (using "runcode"). In the function, I'll reading data from the record the cursor was on in the datasheet at the time I executed the macro. So, the questions are: 1) In the macro, how to I get my hands on the record key or record data of the record the cursor was on in the datasheet at the time I executed the...
0
2053
by: =?Utf-8?B?TGV0emRvXzF0?= | last post by:
I'd like to create a Macro that will sort some raw data, apprx 20k lines, remove some lines based upon a condition in a certain column. Then copy this data into a new spreadsheet and sort the data again and delete the unwanted data and repeat few more times in new sheets. End product will be apprximately 7 or 8 sheets - 1 for Active Customers, Inactive Customers, Pending Installs, Etc... I'm getting hung up I believe with naming...
0
9404
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10168
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
10008
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven tapestry of website design and digital marketing. It's not merely about having a website; it's about crafting an immersive digital experience that captivates audiences and drives business growth. The Art of Business Website Design Your website is...
1
9959
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
9837
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
1
7381
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5279
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
2
3532
muto222
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.
3
2806
bsmnconsultancy
by: bsmnconsultancy | last post by:
In today's digital era, a well-designed website is crucial for businesses looking to succeed. Whether you're a small business owner or a large corporation in Toronto, having a strong online presence can significantly impact your brand's success. BSMN Consultancy, a leader in Website Development in Toronto offers valuable insights into creating effective websites that not only look great but also perform exceptionally well. In this comprehensive...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.