Inserting class namespace into method scope

Discussion in 'Python' started by Steven D'Aprano, Nov 20, 2010.

  1. I find myself having need of a class where the class scope is included in
    the scope of methods in the class. A simple example from Python 3.1:

    x = "outside"

    class Magic:
    x = "inside"
    def method(self):
    return x


    I would like Magic().method() to return "inside" rather than "outside".

    Now, I understand why this is not Python's usual behaviour, and I agree
    with those reasons -- this is NOT a complaint that Python's normal
    behaviour is to exclude the class namespace from the method's scope.

    I also understand that the usual way of getting this would be to return
    self.x or self.__class__.x from method, instead of x. Again, normally I
    would do this.

    But in this specific case I have reasons for wanting to avoid both of the
    normal behaviours. Do not judge me, please accept that I have a good
    reason for wanting this, or at least allow me to shoot myself in the foot
    this way *wink*. In Python 3, is there some way to get this unusual
    behaviour?



    --
    Steven
     
    Steven D'Aprano, Nov 20, 2010
    #1
    1. Advertising

  2. Steven D'Aprano <> wrote:

    >I find myself having need of a class where the class scope is included in
    >the scope of methods in the class. A simple example from Python 3.1:
    >
    >x = "outside"
    >
    >class Magic:
    > x = "inside"
    > def method(self):
    > return x
    >
    >
    >I would like Magic().method() to return "inside" rather than "outside".


    Try this instead:
    return self.x



    Best regards,

    Günther
     
    Günther Dietrich, Nov 20, 2010
    #2
    1. Advertising

  3. On 11/20/2010 6:59 AM Steven D'Aprano said...
    > I find myself having need of a class where the class scope is included in
    > the scope of methods in the class. A simple example from Python 3.1:
    >
    > x = "outside"
    >
    > class Magic:
    > x = "inside"
    > def method(self):
    > return x
    >
    >
    > I would like Magic().method() to return "inside" rather than "outside".
    >
    > Now, I understand why this is not Python's usual behaviour, and I agree
    > with those reasons -- this is NOT a complaint that Python's normal
    > behaviour is to exclude the class namespace from the method's scope.
    >
    > I also understand that the usual way of getting this would be to return
    > self.x or self.__class__.x from method, instead of x. Again, normally I
    > would do this.
    >
    > But in this specific case I have reasons for wanting to avoid both of the
    > normal behaviours. Do not judge me, please accept that I have a good
    > reason for wanting this, or at least allow me to shoot myself in the foot
    > this way *wink*. In Python 3, is there some way to get this unusual
    > behaviour?
    >


    As it's easy to return self.x but you're restricting that option, what
    kind of change options must you work within?

    Emile
     
    Emile van Sebille, Nov 20, 2010
    #3
  4. On Sun, 21 Nov 2010 08:59:30 +1100, Ben Finney wrote:

    > C'mon, Steven, you know the drill. If you want us to help you solve a
    > problem, don't start with “I want to use this behaviour that seems
    > loony, and I won't say whyâ€. Instead, help us by telling us what problem
    > you're trying to solve.


    Well, I tried the TL;DR version. Now you have to read the full version.

    Inspired by the last maxim of the Zen:

    "Namespaces are one honking great idea -- let's do more of those!"

    I'm looking to apply this to my code. I have a bunch of related functions
    and objects which are private to a module, with a single public function
    that acts as the API to those functions. I'd like to have these private
    functions in a namespace, separate from the rest of the module. Ignore
    the fact that they are private functions -- I can deal with that by the
    usual naming convention. Focus on the "separate namespace" aspect.

    What I want is the ability to write this:

    create Namespace:
    def function(x):
    return x

    def func(y):
    return function("spam") + "'n'" + y

    dispatch = {1: func, 2: function}

    def another_func(z):
    return len(dispatch[2](z))


    func("eggs") # raises NameError
    Namespace.func("eggs") # returns "spam'n'eggs"

    Namespace.dispatch[1]("cheese") # returns "spam'n'cheese"


    etc. But of course we can't do that.

    So other options include:

    (1) Give up the dream and just place the private functions in the global
    namespace like everyone else does. So much for the Zen.

    (2) Place them in a separate module, and import the module, similar to
    the way that the os module imports path. This is certainly possible, and
    it works well, but it splits code into two files when it should be in
    one. It pollutes the module namespace, and Guido has recently expressed
    mild objection to new code doing what os does. Or at least he suggested
    that we shouldn't *encourage* doing what os does.

    (3) Redesign my module to use a full package structure, and place the
    functions in a separate module in the package. It's overkill to have a
    package for just two namespaces (modules).

    (4) Use a class to hold the functions, instantiate the class to get an
    instance, and deal with the fact that functions in such an instance are
    automatically turned into methods. There are various ways of dealing with
    it, including the obvious: write the functions as methods.

    But this is too Java-like for my liking... I don't need the ability to
    make multiple instances with independent state, nor do I want to waste
    time turning it into a singleton or borg class. Worse, it complicates the
    dispatch table, because I have to deal with bound methods versus unbound
    methods, or staticmethod/classmethod descriptors... it gets *messy* and
    *ugly* real fast.

    (5) Use a class to hold the functions, but avoid instantiating it, so
    that the functions remain functions. I've done this, and it works great
    unless the functions need to refer to each other. So in the above
    example, Namespace.function("spam") is fine, but Namespace.func("eggs")
    is not.

    Simple solution: Namespace.func could internally call Namespace.function
    instead of just function. That's doable now, without any magic, but it
    feels less than ideal.

    (6) Do something with nested functions, although I'm not entirely sure
    what yet. See below.

    (7) Create a module on the fly, then populate it with the functions:

    Namespace = type(sys)('Namespace')

    def function(x):
    return x

    def func(y):
    return function("spam") + "'n'" + y

    dispatch = {1: func, 2: function}

    Namespace.function = function
    Namespace.func = func
    Namespace.dispatch = dispatch
    del function, func, dispatch


    (8) Something else.

    There's always something else.


    I've tried (1) through (5), with varying levels of success. (6) is next
    on my list to try. I haven't tried (7), and I don't think I will bother.
    It seriously breaks "Don't repeat yourself", and fails to visually set
    the Namespace functions apart from the global namespace. While I expect
    it will work, it's too ugly to consider.

    So I have considered many options, and will look at others, but right now
    I've set myself the task of exploring (5) and finding out whether or not
    there is any way to hammer the class namespace into what I want. Duncan
    suggested a way, but it's messy and fragile.


    TL;DR. See my first post :p



    --
    Steven
     
    Steven D'Aprano, Nov 21, 2010
    #4
  5. On 11/20/2010 4:59 PM Steven D'Aprano said...
    > On Sun, 21 Nov 2010 08:59:30 +1100, Ben Finney wrote:
    >
    >> C'mon, Steven, you know the drill. If you want us to help you solve a
    >> problem, don't start with “I want to use this behaviour that seems
    >> loony, and I won't say whyâ€. Instead, help us by telling us what problem
    >> you're trying to solve.

    >
    > Well, I tried the TL;DR version. Now you have to read the full version.
    >
    > Inspired by the last maxim of the Zen:
    >
    > "Namespaces are one honking great idea -- let's do more of those!"


    Hmm... while playing with various takes on globals and code blocks I
    came across this that may be of interest.

    http://www.voidspace.org.uk/python/articles/code_blocks.shtml

    Emile
     
    Emile van Sebille, Nov 21, 2010
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anonymous
    Replies:
    3
    Views:
    560
    Ron Natalie
    Aug 18, 2003
  2. Jason Heyes
    Replies:
    1
    Views:
    468
    Woebegone
    Nov 19, 2004
  3. Steven T. Hatton
    Replies:
    9
    Views:
    517
  4. Sebastia
    Replies:
    4
    Views:
    134
  5. Chuck Remes
    Replies:
    3
    Views:
    210
    hemant
    Aug 12, 2010
Loading...

Share This Page