Redefining python built-in function - python

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()'

Related

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.

Functions, methods, and how many arguments do I have to give them?

Why do the following lines give me the same result?
str.upper('hello')
and
'hello'.upper()
I tried to do the same with list.append but got a TypeError.
list.append([1])
Is the str type in Python overloaded? How can this be achieved by writing a class/function? I would appreciate an example.
list.append takes two arguments - the list to modify and the element to append. So you need to do it like this:
ls = [1]
list.append(ls, 2)
which is equivalent to the much more popular:
ls.append(2)
str.upper and list.append are both functions.
str.upper takes one argument.
>>> str.upper('test')
'TEST'
list.append takes two arguments.
>>> my_list = []
>>> list.append(my_list, 1)
>>> my_list
[1]
str.upper and list.append (like other functions) are also non-data-descriptors with a __get__ method which in this context has two implications:
When you access the function through the class via the dot notation (str.upper, list.append) the function's __get__ method (i.e. string.upper.__get__ and list.append.__get__) is called but it returns just the function itself.
When you access the function through an instance (my_string.upper, my_list.append) the function's __get__ method is called and it will return a new callable acting like the original function, but with whatever was "in front of the dot" automatically passed as the first argument. .
That's why you need to pass 1 - 1 = 0 arguments when calling my_string.upper() and 2 - 1 = 1 argument when calling my_list.append(1).
>>> 'my_string'.upper()
'MY_STRING'
>>>
>>> my_list = []
>>> my_list.append(1)
>>> my_list
[1]
You could even get these modified callables (methods) by explicitly calling __get__ and passing the argument to be bound (what has been before the dot) as its argument.
>>> my_string = 'my_string'
>>> upper_maker = str.upper.__get__(my_string)
>>> upper_maker()
'MY_STRING'
>>>
>>> my_list = []
>>> appender = list.append.__get__(my_list)
>>> appender(1)
>>> my_list
[1]
Finally, here's a short example demonstrating how descriptor instances can detect whether they are being accessed via their owner-class or via an instance.
class Descriptor:
def __get__(self, instance, owner_class):
if instance is None:
print('accessed through class')
# list.append.__get__ would return list.append here
else:
print('accessed through instance')
# list.append.__get__ would build a new callable here
# that takes one argument x and that internally calls
# list.append(instance, x)
class Class:
attribute = Descriptor()
Class.attribute # prints 'accessed through class'
instance = Class()
instance.attribute # prints 'accessed through instance'
Quoting Dave Kirbys answer from Relationship between string module and str:
There is some overlap between the string module and the str type,
mainly for historical reasons. In early versions of Python str objects
did not have methods, so all string manipulation was done with
functions from the string module. When methods were added to the str
type (in Python 1.5?) the functions were left in the string module for
compatibility, but now just forward to the equivalent str method.
However the string module also contains constants and functions that
are not methods on str, such as formatting, character translation etc.
There is nothing at all magical going on with str (except that we have a nice syntactic shortcut to creating one using ""). You can write a class that behaves like str and list to see more clearly what is happening here.
class MyClass():
def __init__(self, arg):
self.val=str(arg)
def do_thing(self):
self.val = "asdf"
def do_thing_with_arg(self, arg):
self.val = "asdf " + str(arg)
def __repr__(self):
return self.val
my_thing = MyClass("qwerty")
# this is like 'hello'.upper()
my_thing.do_thing()
print(my_thing)
# it prints 'asdf'
my_thing = MyClass("qwerty")
# this is like str.upper('hello')
MyClass.do_thing(my_thing)
print(my_thing)
# it prints 'asdf'
my_thing = MyClass("qwerty")
# this is like my_list.append('qwerty')
my_thing.do_thing_with_arg('zxcv')
print(my_thing)
# it prints 'asdf zxcv'
my_thing = MyClass("qwerty")
# this is like list.append(my_list, 'qwerty')
MyClass.do_thing_with_arg(my_thing, 'zxcv')
print(my_thing)
# it prints 'asdf zxcv'
The short version is, you're invoking what looks like an "instance method" on a class, but you are supplying the instance ('self') yourself as the first argument to the function call.

Str is already defined as a global variable

I noticed something really strange while working with functions. It looks like the variable name 'str' is already defined as a global variable. Take a look:
def Example(x):
str = input()
return str
print (Example(str))
#When typing 'Hello!' Output --> Hello!
The variable str is defined in the function Example. So why is there no NameError: name 'str' is not defined?
When I call the variable x or something else ( In this case 'bar'):
def Example(x):
bar = input()
return bar
print (Example(bar))
#Output: NameError: name 'bar'is not defined
Why does a variable with the name 'str' act as a global variable?
In python, str() is the string constructor. It is used to cast an object to a string.
You can use it locally, but it will override the access to the function. You will not be able to use str() anymore.
for reference:
https://docs.python.org/2/library/functions.html#str
class str(object='')
Return a string containing a nicely printable representation of an
object. For strings, this returns the string itself. The difference
with repr(object) is that str(object) does not always attempt to
return a string that is acceptable to eval(); its goal is to return a
printable string. If no argument is given, returns the empty string,
''.
For general knowledge purpose, you can get back you constructor if you delete your variable. For example:
test = 1
str(test)
>>>'1'
str = 2
str(test)
>>>TypeError: 'int' object is not callable
del str
str(test)
>>>'1'
The reason this fails:
def Example(x):
bar = input()
return bar
print (Example(bar))
#Output: NameError: name 'bar'is not defined
Is because you're attempting to pass the variable bar to the Example() method, but bar was never defined anywhere prior to the call.
I'm not really sure what it is you want to accomplish with this method anyhow, since you pass a variable but don't use it at all.
Comment Response:
str is not a built-in function (albeit listed on the page), but rather it is the constructor for the built-in type str. To show that you are simply reassigning the method associated with the keyword (not necessarily reserved, but it is a keyword nonetheless), consider the following:
>>> str
<class 'str'>
>>> abs
<built-in function abs>
>>> str = abs
>>> str
<built-in function abs>
Thus you've essentially overwritten the assignment to the str class constructor. I used abs in this example, but the same applies (with a twist) for input:
>>> str
<class 'str'>
>>> input
<built-in function input>
>>> str = input
>>> str
<built-in function input>
>>> str = input()
hello world
>>> str
'hello world'
Difference here is you assign a string (of type str) to the keyword str. So you can never use str(10) to get '10' because that would now be like calling hello world(10) which fails.
If you want to use a keyword as a variable name, by convention a single trailing underscore is used to avoid conflicts with Python keywords, like so:
single_trailing_underscore_
Cf. PEP 8 -- Style Guide for Python Codes

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.

Add custom method to string object [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Can I add custom methods/attributes to built-in Python types?
In Ruby you can override any built-in object class with custom method, like this:
class String
def sayHello
return self+" is saying hello!"
end
end
puts 'JOHN'.downcase.sayHello # >>> 'john is saying hello!'
How can i do that in python? Is there a normally way or just hacks?
You can't because the builtin-types are coded in C. What you can do is subclass the type:
class string(str):
def sayHello(self):
print(self, "is saying 'hello'")
Test:
>>> x = string("test")
>>> x
'test'
>>> x.sayHello()
test is saying 'hello'
You could also overwrite the str-type with class str(str):, but that doesn't mean you can use the literal "test", because it is linking to the builtin str.
>>> x = "hello"
>>> x.sayHello()
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
x.sayHello()
AttributeError: 'str' object has no attribute 'sayHello'
>>> x = str("hello")
>>> x.sayHello()
hello is saying 'hello'
The normal Python equivalent to this is to write a function that takes a string as it's first argument:
def sayhello(name):
return "{} is saying hello".format(name)
>>> sayhello('JOHN'.lower())
'john is saying hello'
Simple clean and easy. Not everything has to be a method call.

Categories

Resources