[BangPypers] Object Oriented Programming in python

Dhananjay Nene dhananjay.nene at gmail.com
Tue Oct 22 12:21:53 CEST 2013


On Mon, Oct 21, 2013 at 11:40 PM, Saager Mhatre <saager.mhatre at gmail.com> wrote:
> On Mon, Oct 21, 2013 at 7:11 PM, Dhananjay Nene <dhananjay.nene at gmail.com>wrote:
>
>> Since you suggested that "Superior constructs
>> implemented inferiorly." and did not respond to the line which
>> wondered if that was based on syntactic or stylistic differences,
>
>
> I believe I responded to that statement by saying that the difference I
> note is neither syntactic, nor stylistic; it is semantic in that
> metaclasses behave very differently in other platforms by interacting with
> objects at run-time as opposed to just at compile-time. That simple
> difference makes them significantly more powerful to me.

I don't understand the distinction you make between compile time and runtime.

Here's one example
class FooMeta(type):
    def __new__(cls, name, bases, classdict):
        print("I just constructed a {}".format(cls))
        if(getattr(FooMeta,"fubar",None)) :
            classdict["rockband"] = "zeezeetop"
        else:
            classdict["rockband"] = "men at work"
        result = type.__new__(cls, name, bases, dict(classdict))
        return result

class Foo(metaclass=FooMeta):
    def __init__(self,val):
        self.val = val
    def __str__(self):
        return "Foo({})".format(self.val)

f = Foo(5)
print(f)
print(f.rockband)
print(type(f))
print(type(type(f)))


def bar(self) :
    print(self.val)

def buz(self):
    print("Darn, I'm buzzed now")

Foo.bar = bar
Foo.class_level_constant = 99
FooMeta.fubar = 987
FooMeta.buz = buz
f.bar()

print(f.class_level_constant)
print(type(f).fubar)
print(type(f).buz())
try :
    print(f.fubar)
except Exception as e :
    print("Ignoring an exception {}".format(e))

f2 = Foo(9)
print(f2)
print(f2.rockband)

class Bar(metaclass=FooMeta):
    def __init__(self,val):
        self.val = val
    def __str__(self):
        return "Bar({})".format(self.val)

bar = Bar(23)
print(bar)
print(bar.rockband)

I added both a method and a attribute to a class at runtime and was
able to use it via the instance. Let me stress once again - this was
not compile time, this was runtime.

Again when you suggest semantic differences, it is very unclear what
you are specifically referring to.

To be clear in the above scenario, the type of "f" is "Foo", and any
modifcations to "Foo" percolate down to f as appropriate. There is a
fair degree of capabilities one has in being able to modify Foo at
runtime.

Are you getting confused between Foo and FooMeta ? FooMeta is really
the factory for Foo. To restate, the object is "f", the class is
"Foo", Foo is also an object whose class is FooMeta.

Note, I was not only able to add a attribute to Foo, I was also able
to do it to FooMeta

I was not just able to add an attribute to FooMeta, I was also able to
influence how it constructs classes next time a new one is declared
(eg. when Bar gets declared, fubar has been set, so the rockband
attribute gets set to "zeezeetop")

So frankly, when you say python does stuff at compile time, I don't
get it. Perhaps you are referring to the fact that the __new__ of the
metaclass gets called whenever a class is declared ? Maybe. But it is
hardly compile time.
>
>> I presumed that comment was based on one or two examples of scenarios
>> that you had run into where you found python metaprogramming /
>> metaclasses constraining in some particular way. Anyways it seems
>> there aren't any such examples I can elicit from a continuing
>> discussion.
>>
>
> Again, if we re-read the conversation so far (and I just did), I have been
> avoiding a discussion on metaprogramming as that has little to do with
> metaclasses in all the other platforms I mentioned. AFAICT, only Python
> conflates these two[*], YMMV. Any examples of metaprogramming in
> Ruby/Groovy I provide will provide no value in demonstrating the
> capabilities of metaclasses therein.

> As for metaclasses, I find Python's implementation constraining
> specifically for the point I mentioned above in this very note. For a
> whirlwind tour of what Groovy's MetaClass has to offer try the Dynamic
> Groovy <http://groovy.codehaus.org/Dynamic+Groovy> section of the Groovy
> User Guide <http://groovy.codehaus.org/User+Guide>. I could give you more
> contrived examples, but that would only lead to a pissing match where you
> show me how X can be achieved in Python with P + Q - R. But, to really get
> a hang of these features I'll give you the same advice that several
> pythonistas (including yourself) gave me when I started with it and found
> things out of place- give Ruby/Groovy a shot, take them out for a spin
> (preferably a long drive) and then you'll discover the benefits.

I understand. My reason to focus on capabilities rather than style is
pissing matches on style are far harder to close than those on
capabilities. One is a matter of taste, another is a matter of
evidence. You express taste, I may or may not know enough to decide.
Even if I do, I may or may not agree with your taste. Thats human. The
point is that discussion does not really leave anyone wiser. One can
get metacircular about opinions backing up opinions, but they have to
somewhere rest on some reasonable evidence. Else these discussions
cannot reach any reasonable point of either convergence or incremental
increase in wisdom. On the other hands discussions which are focused
on measurable goals are easier to have since I can both conclude, come
out of the discussion a bit more enlightened and even stand corrected
as appropriate without having to worry about taste.

>
> To reiterate, yes, I believe Python's metaclasses (differently implemented
> as they are) are constraining specifically for the point I mentioned above
> in this very note. Python's metaclasses do not allow for the modification
> of the behaviour of a class/object at runtime.

Modifying a python class allows modification of behaviour of the
object at runtime (adding bar and class_level_constant to Foo above)
Modifying a python metaclass allows modification of the corresponding
classes at runtime. (adding fubar and buz above)
Modifying a python metaclass allows modification of constructions of
newer classes in the future (using "fubar" to decide what rockband
should be set to above)


> The way I see it, the best they do is extract boilerplate code from class definitions.

I hope I offered some code which does a bit more than that.

> I can get that
> with class decorators and avoid all the confusion about how Python does
> metaclasses differently as well as how metaclasses wire into the type
> system. To me, Python's metaclasses provide too little value for the
> cognitive load they add, YMMV.

In most cases you don't need to worry about metaclasses. You just
should worry about the classes (ie. Foo, not FooMeta, not f).
Metaclasses at least in the pythonosphere are more frequently useful
as class factories, but they are pretty much programmable should you
want to.

>
> - d
>
> * They really should've stuck to Class Decorators and avoided the
> confusion, or did those come after metaclasses?

I have come to believe differently because class decorator imo is the
80-20 sweet spot. In most cases what you want can get done using class
decorators. But metaclasses help you reach the other 20%


More information about the BangPypers mailing list