1

I have the following code (shortened to leave just the essentials):

class Strange():
    def setter(self, val):
         self._val = val

    val = property(lambda: self._val, setter)

PyDev in Eclipse Helios barks that self is not visible, which I think should be true and agrees with the explicit philosophy of Python. However the code is running fine in the ipython 2.7 and is used in the codebase.

Is this a security hole, a lexical scoping quirk? Or is there a PEP or documentation explaining this and it's just PyDev missing something?

EDIT: Answering the comments: It works on my machine, maybe your version of Python and OS differs. But thanks, this somehow answers my question about it not being the standard behaviour.

Here is the console output in my case:

barszcz:~ $ uname -a
Linux barszcz 3.4.9-1-ARCH #1 SMP PREEMPT Wed Aug 15 18:59:31 CEST 2012 x86_64 GNU/Linux
barszcz:~ $ ipython2
Python 2.7.3 (default, Apr 24 2012, 00:00:54) 
Type "copyright", "credits" or "license" for more information.

IPython 0.13 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop or use Ctrl-D.
:class Strange():
:    def setter(self, val):
:         self._val = val
:
:    val = property(lambda: self._val, setter)
:
:<EOF>

In [2]: Strange
Out[2]: __main__.Strange

In [3]: Strange()
Out[3]: <__main__.Strange instance at 0x26425f0>

EDIT2: Ok, so I get an error on calling Strange().val, just as Martijn suggested. But the strange thing it is a runtime error not a bytecode compilation error:

In [4]: Strange().val
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-88f3db8b81d0> in <module>()
----> 1 Strange().val

TypeError: <lambda>() takes no arguments (1 given)

I would expect the content of the lambda to be run on executing Strange definition already... If somebody gets the error on definition already, please let me know in the comments.

dhill
  • 3,327
  • 2
  • 19
  • 18
  • 1
    `val` will be set on an instance, therefore `self` will exist at the time. – SilentGhost Nov 14 '12 at 13:02
  • 8
    I get `TypeError: () takes no arguments (1 given)` when reproducing your case. You missed a `self` parameter for the lambda there. If this is your actual code, PyDev is correct. – Martijn Pieters Nov 14 '12 at 13:04
  • You're not showing real code. This doesn't work unless `self` is passed as an argument to `lambda`. – Fred Foo Nov 14 '12 at 13:04
  • 1
    in your interactive session, you never actually do a `StrangeI().val`, you never call the lambda anywhere. – SingleNegationElimination Nov 15 '12 at 12:36
  • @SilentGhost, so you suggest that the lambda definition is not evaluated when running class definition, only on runtime, when the property is called? The error from Martijn would suggest that my Python also doesn't check function parameters on lambdas. The self would be passed implicitly with the lexical scope. When searching SO before asking I found [question](http://stackoverflow.com/questions/7349785/eval-calling-lambda-dont-see-self) suggesting it shouldn't work. – dhill Nov 15 '12 at 12:43
  • @larsmans, this was kind'a offensive, but I understand trusting Python interpreter more than some random guy at SO :) – dhill Nov 15 '12 at 12:44
  • @TokenMacGuy, I realised that just after writing the comment... By being used in the codebase I meant: "It's there, the module is imported, PyDev says it's an error.", but probably nobody called it anywhere. – dhill Nov 15 '12 at 12:54
  • I was confused about name binding. What looked to me like a lazy evaluation is actually no different from `def a(): print b`, without `b` in the surrounding context. The definition will stand and even run just fine after you set `b`. PyDev is actually wrong with showing error, it should be a warning (though it would be extremely bad practice to have a variable named self outside method definition). – dhill Nov 20 '12 at 17:29

1 Answers1

3

Your code is incorrect.

It parses, and you can instantiate the class - and you can even set val, but you will get a TypeError if you try to access val from there.

Actually, there is another error in your code: you don't inherit from object - that makes your class an "old style class" in Python 2, and properties simply don't work with them.

Attributing and getting values from val on our snippet won't show you an obvious error, because the setter will be bypassed entirely when attributing.

The only thing missing there, though is the self parameter on the lambda expression itself (and, of course, have it as a new style class):

class Strange(object):
    def setter(self, val):
         self._val = val

    val = property(lambda self: self._val, setter)
Community
  • 1
  • 1
jsbueno
  • 99,910
  • 10
  • 151
  • 209
  • Thanks for noticing the new style class problem, I thought new style became default already. – dhill Nov 20 '12 at 17:28