473,385 Members | 1,192 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,385 software developers and data experts.

Need a better understanding on how MRO works?

Given the following code: (I hope it's as simple as possible) :-)
#! /usr/bin/python
import new
class BASE:
def __init__( self ):
print 'Hello from BASE init'
def m1( self ):
print 'M1 Base: Self = ', self

def m1replace( self ):
print 'm1replace:Self = ', self

class D1(BASE):
def __init__(self):
BASE.__init__(self)

def __InitDS101Classes():
name = 'C1'
nclass = new.classobj(name,(D1,),globals())
globals()[name] = nclass
name = 'C2'
nclass = new.classobj(name,(D1,),globals())
globals()[name] = nclass
globals()[name].m1 = m1replace

__InitDS101Classes()

s = C1()
s.m1()
t = C2()
t.m1()

I get the following output:

1100 ./foo1.py
Hello from BASE init
m1replace:Self = <__main__.C1 instance at 0xb7e637cc>
Hello from BASE init
m1replace:Self = <__main__.C2 instance at 0xb7e6388c>

But if I make BASE inherit from object
class BASE(object):
then I get this:

1100 ./foo1.py
Hello from BASE init
m1replace:Self = <__main__.NewClass instance at 0xb7f5070c>
Hello from BASE init
M1 Base: Self = <__main__.D1 instance at 0xb7f5088c>

Can someone please explain why the assignment to C2.m1 would overwrite
BASE.m1?

TIA

--
Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net
Aug 25 '07 #1
6 1391
Steven W. Orr <st****@syslang.netwrote:
...
name = 'C1'
nclass = new.classobj(name,(D1,),globals())
globals()[name] = nclass
Here, you're creating a VERY anomalous class C1 whose __dict__ is
globals(), i.e. the dict of this module object;
name = 'C2'
nclass = new.classobj(name,(D1,),globals())
globals()[name] = nclass
and here you're creating another class with the SAME __dict__;
globals()[name].m1 = m1replace
So of course this assignment affects the 'm1' entries in the dict of
both classes, since they have the SAME dict object (a la Borg) -- that
is, IF they're old-style classes (i.e. if D1 is old-style), since in
that case a class's __dict__ is in fact a dict object, plain and simple.

However, if D1 is new-style, then C1.__dict__ and C2.__dict__ are in
fact instances of <dictproxy-- each with a copy of the entries that
were in globals() when you called new.classobj, but DISTINCT from each
other and from globals(), so that further changes in one (or globals)
don't affect globals (nor the other).

I guess this might be a decent interview question if somebody claims to
be a "Python guru": if they can make head or tails out of this mess, boy
the *ARE* a Python guru indeed (in fact I'd accord minor guruhood even
to somebody who can get a glimmer of understanding of this with ten
minutes at a Python interactive prompt or the like, as opposed to
needing to understand it "on paper" without the ability to explore:-).

Among the several "don't"s to learn from this: don't use old-style
classes, don't try to make two classes share the same dictionary, and
don't ask about MRO in a question that has nothing to do with MRO
(though I admit that was a decent attempt at misdirection, it wouldn't
slow down even the minor-guru in any appreciable way:-).
Alex
Aug 26 '07 #2
On Saturday, Aug 25th 2007 at 17:19 -0700, quoth Alex Martelli:

=>Steven W. Orr <st****@syslang.netwrote:
= ...
=> name = 'C1'
=> nclass = new.classobj(name,(D1,),globals())
=> globals()[name] = nclass
=>
=>Here, you're creating a VERY anomalous class C1 whose __dict__ is
=>globals(), i.e. the dict of this module object;
=>
=> name = 'C2'
=> nclass = new.classobj(name,(D1,),globals())
=> globals()[name] = nclass
=>
=>and here you're creating another class with the SAME __dict__;
=>
=> globals()[name].m1 = m1replace
=>
=>So of course this assignment affects the 'm1' entries in the dict of
=>both classes, since they have the SAME dict object (a la Borg) -- that
=>is, IF they're old-style classes (i.e. if D1 is old-style), since in
=>that case a class's __dict__ is in fact a dict object, plain and simple.
=>
=>However, if D1 is new-style, then C1.__dict__ and C2.__dict__ are in
=>fact instances of <dictproxy-- each with a copy of the entries that
=>were in globals() when you called new.classobj, but DISTINCT from each
=>other and from globals(), so that further changes in one (or globals)
=>don't affect globals (nor the other).
=>
=>I guess this might be a decent interview question if somebody claims to
=>be a "Python guru": if they can make head or tails out of this mess, boy
=>the *ARE* a Python guru indeed (in fact I'd accord minor guruhood even
=>to somebody who can get a glimmer of understanding of this with ten
=>minutes at a Python interactive prompt or the like, as opposed to
=>needing to understand it "on paper" without the ability to explore:-).
=>
=>Among the several "don't"s to learn from this: don't use old-style
=>classes, don't try to make two classes share the same dictionary, and
=>don't ask about MRO in a question that has nothing to do with MRO
=>(though I admit that was a decent attempt at misdirection, it wouldn't
=>slow down even the minor-guru in any appreciable way:-).
=>
=>
=>Alex
=>--
=>http://mail.python.org/mailman/listinfo/python-list
=>

Thanks Alex. I am humbled, though I was before I started.
I really don't have a lot of understanding of what you're saying so I'll
probably have to study this for about a year or so.

* (I need to look up what dictproxy is.) I don't have any idea what the
ramifications are of your use of the word DISTINCT. Are you somehow
suggesting that new.classobj does a deep copy of the globals copy that's
passed to it?

* Also, I'd like to understand what the difference is between
nclass = new.classobj(name,(D1,),globals())
vs.
def classfactory():
class somename(object):
def somestuff():
pass
return somename
G1 = classfactory()
globals()[name] = G1

Does new.classobj do anything special?

I appreciate your time.

--
Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net
Aug 26 '07 #3
Steven W. Orr <st****@syslang.netwrote:
...
Thanks Alex. I am humbled, though I was before I started.
I really don't have a lot of understanding of what you're saying so I'll
probably have to study this for about a year or so.

* (I need to look up what dictproxy is.) I don't have any idea what the
ramifications are of your use of the word DISTINCT. Are you somehow
suggesting that new.classobj does a deep copy of the globals copy that's
passed to it?
No, most definitely NOT deep!!!, but type.__new__ does "a little" of
what you've said (a shallow copy, which is not quite "a copy" because it
embeds [some of] the entries in slots). new.classobj determines the
metaclass (from the bases, or a __metaclass__ entry in the dictionary)
and calls it to generate the new class. For modern style classes, the
class is type; for old-style legacy classes, it's types.ClassType, and
they're not exactly identical in behavior (of course not, or there would
no point in having both:-).
>
* Also, I'd like to understand what the difference is between
nclass = new.classobj(name,(D1,),globals())
vs.
def classfactory():
class somename(object):
def somestuff():
pass
return somename
G1 = classfactory()
globals()[name] = G1

Does new.classobj do anything special?
No, new.classobj does essentially the same thing that Python does after
evaluating a class statement to prepare the class's name, bases and
dictionary: finds the metaclass and calls it with these arguments.

A key difference of course is that a class statement prepares the class
dictionary as a new, ordinary, distinct dictionary, while new.classobj
accepts whatever dictionary you give it (so you can, though shouldn't,
do strange things such as pass globals()...:-).
Alex
Aug 26 '07 #4
On Saturday, Aug 25th 2007 at 22:14 -0700, quoth Alex Martelli:

=>Steven W. Orr <st****@syslang.netwrote:

=>* Also, I'd like to understand what the difference is between
=> nclass = new.classobj(name,(D1,),globals())
=>vs.
=> def classfactory():
=> class somename(object):
=> def somestuff():
=> pass
=> return somename
=> G1 = classfactory()
=> globals()[name] = G1
=>>
=>Does new.classobj do anything special?
=>
=>No, new.classobj does essentially the same thing that Python does after
=>evaluating a class statement to prepare the class's name, bases and
=>dictionary: finds the metaclass and calls it with these arguments.
=>
=>A key difference of course is that a class statement prepares the class
=>dictionary as a new, ordinary, distinct dictionary, while new.classobj
=>accepts whatever dictionary you give it (so you can, though shouldn't,
=>do strange things such as pass globals()...:-).

In fact, I wanted to make a common routine that could be called from
multiple modules. I have classes that need to be created from those
multiple modules. I did run into trouble when I created a common routine
even though I passed globals() as one of the args. The """though
shouldn't""" is prompting me to ask why, and where I might be able to read
more.

--
Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net
Aug 26 '07 #5
Steven W. Orr <st****@syslang.netwrote:
...
=>accepts whatever dictionary you give it (so you can, though shouldn't,
=>do strange things such as pass globals()...:-).

In fact, I wanted to make a common routine that could be called from
multiple modules. I have classes that need to be created from those
multiple modules. I did run into trouble when I created a common routine
even though I passed globals() as one of the args. The """though
shouldn't""" is prompting me to ask why, and where I might be able to read
more.
The dictionary you pass to new.classobj should be specifically
constructed for the purpose -- globals() will contains all sort of odds
and ends that have nothing much to do with the case.

You appear to be trying to embody lot of black magic in your "common
routine", making it communicate with its callers by covert channels; the
way you use globals() to give that routine subtle "side effects" (making
the routine stick entries there) as well as pass it an opaque,
amorphous, unknown blobs of input information, strongly suggests that
the magic is running away with you (a good general reference about that
is <http://video.google.com/videoplay?docid=4611491525028588899>).

"Explicit is better than implicit", "simple is better than complex",
etc, can be read by typing ``import this'' at an interactive Python
prompt.

The best book I know about the do's and don't's of large-scale software
architecture is Lakos' "Large-Scale C++ Software Design",
<http://www.amazon.com/Large-Scale-So...kos/dp/0201633
620-- very C++ specific, but even though some of the issues only apply
to C++ itself, many of its crucial lessons will help with large scale SW
architecture in just about any language, Python included.

What I had to say about the lures and pitfalls of black magic in Python
specifically is spread through the Python Cookbook 2nd edition (and, to
a lesser extent, Python in a Nutshell).
Alex
Aug 26 '07 #6
On Sun, 26 Aug 2007 07:55:39 -0400, Steven W. Orr wrote:
In fact, I wanted to make a common routine that could be called from
multiple modules. I have classes that need to be created from those
multiple modules. I did run into trouble when I created a common routine
even though I passed globals() as one of the args.
I'm thinking that you should cross out "even though" and insert
"because" :-)

Perhaps I'm misunderstanding exactly what you're trying to accomplish,
but if you want to call a routine (a function? class?) from multiple
modules, the simplest way is the best: create the routine in one module,
then import it into all the others.

--
Steven.
Aug 26 '07 #7

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

Similar topics

9
by: netpurpose | last post by:
I need to extract data from this table to find the lowest prices of each product as of today. The product will be listed/grouped by the name only, discarding the product code - I use...
4
by: Muhd | last post by:
It seems like im missing something, what i want to do is select the last row from a table that relates to a specific person. My table and select statement follow, the select statement works fine,...
19
by: James Fortune | last post by:
I have a lot of respect for David Fenton and Allen Browne, but I don't understand why people who know how to write code to completely replace a front end do not write something that will automate...
7
by: Buck Rogers | last post by:
Hi all! Newbie here. Below is an example from Teach Yourself C in 21 Days. My apologies if it is a bit long. What I don't understand is how the "get_data" function can call the...
5
by: Y2J | last post by:
I am working through this book on C++ programming, the author is speaking of using linked lists. He gave and example which I found confusing to say the least. So I rewrote the example in a way that...
22
by: JoeC | last post by:
I am working on another game project and it is comming along. It is an improvment over a previous version I wrote. I am trying to write better programs and often wonder how to get better at...
9
by: sam_cit | last post by:
Hi Everyone, I have the following structure and i have a function that will work(modify/edit) the members of the structure, please tell me which is a better apprach considering both time and...
15
RMWChaos
by: RMWChaos | last post by:
In my ongoing effort to produce shorter, more efficient code, I have created a "chicken and egg" / "catch-22" problem. I can think of several ways to fix this, none of them elegant. I want my code...
1
by: CloudSolutions | last post by:
Introduction: For many beginners and individual users, requiring a credit card and email registration may pose a barrier when starting to use cloud servers. However, some cloud server providers now...
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 3 Apr 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 former...
0
by: ryjfgjl | last post by:
In our work, we often need to import Excel data into databases (such as MySQL, SQL Server, Oracle) for data analysis and processing. Usually, we use database tools like Navicat or the Excel import...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: aa123db | last post by:
Variable and constants Use var or let for variables and const fror constants. Var foo ='bar'; Let foo ='bar';const baz ='bar'; Functions function $name$ ($parameters$) { } ...
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...

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.