getattr and unicode attributes - python

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.

Related

how to convert a string to a variable in python in classes? [duplicate]

Suppose I have a python object x and a string s, how do I set the attribute s on x? So:
>>> x = SomeObject()
>>> attr = 'myAttr'
>>> # magic goes here
>>> x.myAttr
'magic'
What's the magic? The goal of this, incidentally, is to cache calls to x.__getattr__().
setattr(x, attr, 'magic')
For help on it:
>>> help(setattr)
Help on built-in function setattr in module __builtin__:
setattr(...)
setattr(object, name, value)
Set a named attribute on an object; setattr(x, 'y', v) is equivalent to
``x.y = v''.
However, you should note that you can't do that to a "pure" instance of object. But it is likely you have a simple subclass of object where it will work fine. I would strongly urge the O.P. to never make instances of object like that.
Usually, we define classes for this.
class XClass( object ):
def __init__( self ):
self.myAttr= None
x= XClass()
x.myAttr= 'magic'
x.myAttr
However, you can, to an extent, do this with the setattr and getattr built-in functions. However, they don't work on instances of object directly.
>>> a= object()
>>> setattr( a, 'hi', 'mom' )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'hi'
They do, however, work on all kinds of simple classes.
class YClass( object ):
pass
y= YClass()
setattr( y, 'myAttr', 'magic' )
y.myAttr
let x be an object then you can do it two ways
x.attr_name = s
setattr(x, 'attr_name', s)
Also works fine within a class:
def update_property(self, property, value):
setattr(self, property, value)
If you want a filename from an argument:
import sys
filename = sys.argv[1]
file = open(filename, 'r')
contents = file.read()
If you want an argument to show on your terminal (using print()):
import sys
arg = sys.argv[1]
arg1config = print(arg1config)

Instantiating static variable in python

I want to create a static variable in python for a class and instantiate it with the same type i.e.
class TestVarClass():
# this is my static variable here
testVar = None
def __init__(self, value):
# instance variable here
instanceVar = 0
# instantiating the static variable with its own type
TestVarClass.testVar = TestVarClass(1)
Since python is an interpreting language, I cannot instantiate the static object inside the class before init. Hence, I placed it outside the class. But when I debug this in pycharm, the variable testVar comes with infinite nesting like below:
What does this mean? Since the address at every level is same - it
doesn't look like it is allocating multiple times but hen why does
the debugger show the value like this?
I basically want to achieve
creating a static and read-only variable in python and ended up
here.
Why do you see what you see? You have created an instance of TestVarClass and assigned it to testVar class attribute, which is accessible from that class and each of its instances (but is still the same class attribute and refers to the same object). It would be the same as a simplified example of:
>>> class C:
... pass
...
>>> C.a = C()
>>> C.a
<__main__.C instance at 0x7f14d6b936c8>
>>> C.a.a
<__main__.C instance at 0x7f14d6b936c8>
class C now having attribute a itself being instance of C. I can access C.a and since that is instance of C and I can access its C.a (or C.a.a). And so on. It's still the very same object though.
Python doesn't really have static variables. Well, it sort of does, but as a side effect of default argument values being assigned once when a function is being defined. Combine that with behavior (and in-place modification) of mutable objects. And you essentially get the same behavior you'd expect form a static variable in other languages. Take the following example:
>>> def f(a=[]):
... a.append('x')
... return id(a), a
...
>>> f()
(139727478487952, ['x'])
>>> f()
(139727478487952, ['x', 'x'])
>>>
I am not entirely sure what exactly are you after. Once assigned, class attribute lives with the class and hence could be considered static in that respect. So I presume assign only once behavior interests you? Or to expose the class attribute in instances without being able to assign to it instances themselves? Such as:
>>> class C:
... _a = None
... #property
... def a(self):
... return self._a
...
>>> C._a = C()
>>> c = C()
>>> print(c.a)
<__main__.C object at 0x7f454bccda10>
>>> c.a = 'new'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
Or if you wanted to still use a in both class and instance?
>>> class C:
... a = None
... def __setattr__(self, name, value):
... if name == 'a':
... raise TypeError("Instance cannot assign to 'a'")
... super().__setattr__(name, value)
...
>>> C.a = C()
>>> c = C()
>>> c.a
<__main__.C object at 0x7f454bccdc10>
>>> C.a
<__main__.C object at 0x7f454bccdc10>
>>> c.a = 'new_val'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __setattr__
TypeError: Instance cannot assign to 'a'
Essentially read-only variable (static or not) already sounds a bit like a contradictio in adiecto (not really as much of a variable), but (long story short) I guess the question really is, what is it that you're trying to do (problem you're trying to solve) in a context... and perhaps based on that we could try to come up with a reasonable way to express the idea in Python, but as given without further qualification, Python does not have anything it'd call static read-only variables.

Change recordorder in python in loop [duplicate]

Suppose I have a python object x and a string s, how do I set the attribute s on x? So:
>>> x = SomeObject()
>>> attr = 'myAttr'
>>> # magic goes here
>>> x.myAttr
'magic'
What's the magic? The goal of this, incidentally, is to cache calls to x.__getattr__().
setattr(x, attr, 'magic')
For help on it:
>>> help(setattr)
Help on built-in function setattr in module __builtin__:
setattr(...)
setattr(object, name, value)
Set a named attribute on an object; setattr(x, 'y', v) is equivalent to
``x.y = v''.
However, you should note that you can't do that to a "pure" instance of object. But it is likely you have a simple subclass of object where it will work fine. I would strongly urge the O.P. to never make instances of object like that.
Usually, we define classes for this.
class XClass( object ):
def __init__( self ):
self.myAttr= None
x= XClass()
x.myAttr= 'magic'
x.myAttr
However, you can, to an extent, do this with the setattr and getattr built-in functions. However, they don't work on instances of object directly.
>>> a= object()
>>> setattr( a, 'hi', 'mom' )
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'hi'
They do, however, work on all kinds of simple classes.
class YClass( object ):
pass
y= YClass()
setattr( y, 'myAttr', 'magic' )
y.myAttr
let x be an object then you can do it two ways
x.attr_name = s
setattr(x, 'attr_name', s)
Also works fine within a class:
def update_property(self, property, value):
setattr(self, property, value)
If you want a filename from an argument:
import sys
filename = sys.argv[1]
file = open(filename, 'r')
contents = file.read()
If you want an argument to show on your terminal (using print()):
import sys
arg = sys.argv[1]
arg1config = print(arg1config)

Variable with name `None`

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.

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