Variable with name `None` - python

I need to have a variable with name None:
class QAbstractPrintDialog(QDialog):
None = int() # QAbstractPrintDialog.PrintDialogOption enum
PrintToFile = int() # QAbstractPrintDialog.PrintDialogOption enum
PrintSelection = int() # QAbstractPrintDialog.PrintDialogOption enum
...
But:
syntax error: cannot assign to None
I need the name to be None. I thought this will work:
QAbstractPrintDialog.None = int() # QAbstractPrintDialog.PrintDialogOption enum
But it didn't. Is there a workaround to not have a syntax error?
Solutions like setattr don't work for me - this code will be parsed to extract classes, functions, arguments, etc.
Python 2.6, 2.7
EDIT:
I am helping a guy to write pseudo-Python modules which contain description of Qt classes. QAbstractPrintDialog is one of the classes and it has enum QAbstractPrintDialog::PrintDialogOption (http://doc.trolltech.com/latest/qabstractprintdialog.html). One of the enums is None. I can easily reference a None attribute via QAbstractPrintDialog.None but i can not set it. int() means the type of the attribute.
See here: http://scummos.blogspot.com/2011/06/kdevelop-python-language-support-plugin.html

In python None is a reserved word and cannot be used as a variable name.
Quoting python documentation:
Changed in version 2.4: Assignments to None are illegal and raise a SyntaxError.

You cannot. None is a Python built-in constant.
To do what you are makes no more sense than:
class = struct
"Assignments to None are illegal and raise a SyntaxError."
--The documentation
Pick another variable name: nil, none, nothing, zilch, not_a_sausage, no_votes, zero, ...
I agree with you that this is a little inconsistent with other built-in constants, viz:
>>> class Foo:
... def __init__(self):
... self.False = True
... self.True = False
... self.None = 'Something'
...
File "<stdin>", line 5
SyntaxError: assignment to None
...but then...
>>> class Foo:
... def __init__(self):
... self.False = True
... self.True = False
...
>>> f = Foo()
>>> f.True
False
>>> f.False
True
>>> f.None
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: Foo instance has no attribute 'None'
...of course that kind of naming and assignment could only ever lead to trouble!

Call it something distinct like __INSTEADOF_None then strip off all instances of '_INSTEADOF' in a pre-processing step prior to parsing.

It's against the rules to assign to None which has a very special meaning in Python. Choose a different name.

You can try next approach:
>>> class A():pass
>>> a = A()
>>> a.None = 2
SyntaxError: assignment to None
>>> a.__dict__['None'] = 2
>>> a.None
2
>>> dir(a)
['None', '__doc__', '__module__']
But still - idea to use None as object field is really bad.

Related

Is there a way to create SimpleNamespace with boolean value false?

I am trying to create a SimpleNamespace with false value, but it is not working for me.
EMPTY = types.SimpleNamespace(__bool__=lambda self: False)
assert bool(EMPTY) == False # raises error!!
Is there a way to create SimpleNamespace with boolean value false?
It is not possible to give custom, "real" methods to individual instances of a class. In the original code, EMPTY.__bool__ is not a method, but an ordinary function. You can see this by trying to invoke it explicitly:
>>> EMPTY = types.SimpleNamespace(__bool__=lambda self: False)
>>> EMPTY.__bool__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: <lambda>() missing 1 required positional argument: 'self'
See also Adding a Method to an Existing Object Instance. While it's possible - following the advice there - to make EMPTY.__bool__ behave like a method:
>>> EMPTY = types.SimpleNamespace()
>>> EMPTY.__bool__ = types.MethodType(lambda self: False, EMPTY)
>>> EMPTY.__bool__()
False
that will still be ignored by bool:
>>> bool(EMPTY)
True
The implementation of bool looks up __bool__ directly on the class, because it has no reason to expect an instance to have such an attribute.
Instead, we need to have our own class, with an actual method named __bool__ that does the right thing. Thus:
class PossiblyEmptyNamespace(types.SimpleNamespace):
"""A namespace that is falsey when it doesn't contain anything."""
def __bool__(self):
return bool(vars(self))
Now we can test that:
>>> EMPTY = PossiblyEmptyNamespace()
>>> bool(EMPTY)
False
>>> EMPTY.foo = 'bar'
>>> bool(EMPTY) # oops, not actually empty any more.
True
As mentioned in the comments, you'll need to make a subclass. Dunder methods like __bool__ are generally looked up on the class, not the specific instance, so setting a field on an instance will do you no good in this case.
from types import SimpleNamespace
class FalsyNamespace(SimpleNamespace):
def __bool__(self):
return False
EMPTY = FalsyNamespace()
assert bool(EMPTY) == False

getattr and unicode attributes

Since it has become possible to use unicode characters in identifiers for class, methods, variables, I use them more and more. I don't know, if this is A Good Idea, but it makes the code more readable (e.g. you can now use import numpy as np; π = np.pi; area = r**2 * π!)
Now I noticed the following behaviour (in Python 3.8.5):
I can define a class A the following way:
>>> class A:
... def x(self):
... print('x')
... def ξ(self):
... print('ξ')
... def yₓ(self):
... print('yₓ')
and can access all methods:
>>> a = A()
>>> a.x()
x
>>> a.ξ()
ξ
>>> a.yₓ()
yₓ
The problem arises, if I want to use getattr() to access them:
>>> attr = getattr(a, 'x')
>>> attr()
x
>>> attr = getattr(a, 'ξ')
>>> attr()
ξ
>>> attr = getattr(a, 'yₓ')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'yₓ'
'A' object has no attribute 'yₓ'
Why does getattr(a,'ξ') work, but getattr(a, 'yₓ') does not?
I noticed
>>> dir(a)
[…, 'x', 'yx', 'ξ']
Why is 'ξ' kept, but 'yₓ' silently converted to 'yx'? Which are the "safe" characters, which can be used, so that getattr() succeeds?
Is there a way, so that I can use yₓ?
BTW, yₓ can be used, but y₂ gives a SyntaxError: invalid character in identifier
Why can't I use y₂ at all?
I know, the workaround is, to not use any of those fancy characters, but some of them make the code really more readable (at least in my view!) …
Non-ASCII identifiers are defined in PEP 3131. In it, it says that:
The entire UTF-8 string is passed to a function to normalize the string to NFKC
You can test this for yourself with unicodedata.normalize:
unicodedata.normalize("NFKC", 'ξ') # 'ξ'
unicodedata.normalize("NFKC", 'yₓ') # 'yx'
NFKC is very complicated, but you should be able to find safe characters with a loop.

Redefining python built-in function

I'm working on a python program and the author has written a function that looks like this
def blah():
str = "asdf asdf asdf"
doStuff(str)
This seems to work, even though str is a built in function and shouldn't be used as a variable.
What is actually happening here? My guess is str will no longer be usable as a function, but only in the scope of the blah() function he's written. Is that correct? This won't redefine str globally, right?
Internally, the function's local variable table will contain an entry for str, which will be local to that function. You can still access the builtin class within the function by doing builtins.str in Py3 and __builtin__.str in Py2. Any code outside the function will not see any of the function's local variables, so the builtin class will be safe to use elsewhere.
There is another caveat/corner case here, which is described in this question. The local table entry is created at compile-time, not at runtime, so you could not use the global definition of str in the function even before you assign "asdf asdf asdf" to it:
def blah():
x = str(12)
str = "asdf asdf asdf"
doStuff(str)
will fail with an UnboundLocalError.
This seems to work, even though str is a built in function and shouldn't be used as a variable.
Yes, that is true. Python doesn't stop you from shooting yourself in the foot. It's up to you as the developer to make sure your not overwriting builtin names.
What is actually happening here? My guess is str will no longer be usable as a function, but only in the scope of the blah() function he's written. Is that correct? This won't redefine str globally, right?
Your are partially correct here as well. If the value of str is overwritten local, then only the current scope is affected. The global value of str remains unchanged. However, if str is over written in the global scope, then it affects all sub-scopes. The reason behind this is how the Python interpreter compiles values at run-time. This behavior can be observed using a simple example:
>>> def foo():
... str = 0
... return str
...
>>> foo()
0
>>> str(0)
'0'
>>>
The first example works because str is only overwritten in the scope of foo(). This second example fails however because str is overwritten globally:
>>> str = 0
>>> def foo():
... return str(0)
...
>>> foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in foo
TypeError: 'int' object is not callable
>>>
You can always import builtins(__builtins__ in Python 2) though, and reset the value of str to its original meaning:
>>> str = 0
>>> str
0
>>> import __builtins__
>>> str = __builtins__.str
>>> str
<type 'str'>
>>> str(0)
'0'
>>>
Also, as #Brad Solomon stated, you can simply use del str to recover the builtin str value:
>>> str = 0
>>> str
0
>>> del str
>>> str
<class 'str'>
>>>
In your case, str is just a variable and nothing prevents you from the usual use of str() outside that function:
>>> str = 'Hello world!'
>>> print str
Hello world!
str(str)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object is not callable
EDIT:
Here is a simple demo:
def salut():
str = 'Hello world!'
return str
if __name__ == '__main__':
s = salut()
print str(s) #nothing prevents you from using 'str' outside 'salut()'

Is it possible to use a class as a dictionary key in Python 3?

I'm trying to reduce copy/paste in my code and have stumbled upon this problem. I've googled for the answer but all answers use an instance of a class as the key, I can't find anything on using a class definition itself as the key (I don't know if it's possible).
My code is this:
# All chunkFuncs keys are class definitions, all values are functions
chunkFuncs = {Math_EXP : Math_EXPChunk, Assignment : AssignmentChunk, Function : FunctionChunk}
def Chunker(chunk, localScope):
for chunkType in chunkFuncs:
if isinstance(chunk,chunkType):
# The next line is where the error is raised
localScope = chunkFuncs[chunk](chunk,localScope)
return localScope
and the error is this
TypeError: unhashable type: 'Assignment'
Here are the class definitions:
class Math_EXP(pyPeg.List):
grammar = [Number,Symbol],pyPeg.maybe_some(Math_OP,[Number,Symbol])
class Assignment(pyPeg.List):
grammar = Symbol,'=',[Math_EXP,Number]
class Function(pyPeg.List):
grammar = Symbol,'(',pyPeg.optional(pyPeg.csl([Symbol,Number])),')'
Are there any alternative methods I could use to get the same effect?
Thanks.
OK, the comments are getting out of hand ;-)
It seems certain now that the class object isn't the problem. If it were, the error would have triggered on the first line, when the dict was first constructed:
chunkFuncs = {Math_EXP : Math_EXPChunk, Assignment : AssignmentChunk, Function : FunctionChunk}
If you try to construct a dict with an unhashable key, the dict creation fails at once:
>>> {[]: 3}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
But you got beyond that line, and Assignment is a key in the dict you constructed. So the error is in this line:
localScope = chunkFuncs[chunk](chunk,localScope)
Best guess is that it's an instance of Assignment that's unhashable:
>>> class mylist(list):
... pass
...
>>> hash(mylist)
2582159
>>> hash(mylist())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'mylist'
See? mylist is hashable, but the instance mylist() is not.
Later: best guess is that you're not going to be able to worm around this. Why? Because of the name of the base class, pyPeg.List. If it's mutable like a Python list, then instances won't be hashable - and shouldn't be (mutable objects are always dangerous as dict keys). You could still index a dict by id(the_instance), but whether that's semantically correct is something I can't guess without knowing a lot more about your code.
You should be able to, yes, but you might need an extra type call:
>>> class X:
... pass
...
>>> class_map = {X: 5}
>>> my_x = X()
>>> class_map[type(my_x)]
5

Iterating class object

It's not a real world program but I would like to know why it can't be done.
I was thinking about numpy.r_ object and tried to do something similar but just making a class and not instantiating it.
a simple code (has some flaws) for integers could be:
class r_:
#classmethod
def __getitem__(clc, sl):
try:
return range(sl)
except TypeError:
sl = sl.start, sl.stop, sl.step
return range(*(i for i in sl if i is not None))
but as I try to do r_[1:10] i receive TypeError: 'type' object is not subscriptable.
Of course the code works with r_.__getitem__(slice(1,10)) but that's not what I want.
Is there something I can do in this case instead of using r_()[1:10]?
The protocol for resolving obj[index] is to look for a __getitem__ method in the type of obj, not to directly look up a method on obj (which would normally fall back to looking up a method on the type if obj didn't have an instance attribute with the name __getitem__).
This can be easily verified.
>>> class Foo(object):
pass
>>> def __getitem__(self, index):
return index
>>> f = Foo()
>>> f.__getitem__ = __getitem__
>>> f[3]
Traceback (most recent call last):
File "<pyshell#8>", line 1, in <module>
f[3]
TypeError: 'Foo' object does not support indexing
>>> Foo.__getitem__ = __getitem__
>>> f[3]
3
I don't know why exactly it works this way, but I would guess that at least part of the reason is exactly to prevent what you're trying to do; it would be surprising if every class that defined __getitem__ so that its instances were indexable accidentally gained the ability to be indexed itself. In the overwhelming majority of cases, code that tries to index a class will be a bug, so if the __getitem__ method happened to be able to return something, it would be bad if that didn't get caught.
Why don't you just call the class something else, and bind an instance of it to the name r_? Then you'd be able to do r_[1:10].
What you are trying to do is like list[1:5] or set[1:5] =) The special __getitem__ method only works on instances.
What one would normally do is just create a single ("singleton") instance of the class:
class r_class(object):
...
r_ = r_class()
Now you can do:
r_[1:5]
You can also use metaclasses, but that may be more than is necessary.
"No, my question was about getitem in the class, not in the instance"
Then you do need metaclasses.
class r_meta(type):
def __getitem__(cls, key):
return range(key)
class r_(object, metaclass=r_meta):
pass
Demo:
>>> r_[5]
range(0, 5)
If you pass in r_[1:5] you will get a slice object. Do help(slice) for more info; you can access values like key.stop if isinstance(key,slice) else key.
Define __getitem__() as a normal method in r_'s metaclass.
The reason for this behavior lies in the way how special methods like __getitem__() are lookup up.
Attributes are looked up first in the objects __dict__, and, if not found there, in the class __dict__. That's why e.g. this works:
>>> class Test1(object):
... x = 'hello'
...
>>> t = Test1()
>>> t.__dict__
{}
>>> t.x
'hello'
Methods that are defined in the class body are stored in the class __dict__:
>>> class Test2(object):
... def foo(self):
... print 'hello'
...
>>> t = Test2()
>>> t.foo()
hello
>>> Test2.foo()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unbound method foo() must be called with Test2 instance as first argument (got nothing
instead)
So far there's nothing surprising here. When it comes to special methods however, Python's behavior is a little (or very) different:
>>> class Test3(object):
... def __getitem__(self, key):
... return 1
...
>>> t = Test3()
>>> t.__getitem__('a key')
1
>>> Test3['a key']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'type' object is unsubscriptable
The error messages are very different. With Test2, Python complains about an unbound method call, whereas with Test3 it complains about the unsubscriptability.
If you try to invoke a special method - by way of using it's associated operator - on an object, Python doesn't try to find it in the objects __dict__ but goes straight to the __dict__ of the object's class, which, if the object is itself a class, is a metaclass. So that's where you have to define it:
>>> class Test4(object):
... class __metaclass__(type):
... def __getitem__(cls, key):
... return 1
...
>>> Test4['a key']
1
There's no other way. To quote PEP20: There should be one-- and preferably only one --obvious way to do it.

Categories

Resources