Add custom method to string object [duplicate] - python

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.

Related

What kind of method is this in Python? [duplicate]

This question already has answers here:
Inner class function without self
(5 answers)
Closed 2 years ago.
I was reading about instance, static, and class methods, and found the following.
This:
class A:
def a(self, num):
print("A.a(): ", num)
#staticmethod
def aa(num):
print("A.aa(): ", num)
works exactly as expected:
>>> A.a(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a() missing 1 required positional argument: 'num'
# I understand that this happens since `a()` is an instance method
>>> A.aa(1)
A.aa(): 1
>>> A().a(1)
A.a(): 1
However, if I modify A.a() to remove self from its parameters, i.e.:
class A:
def a(num):
print("A.a(): ", num)
#staticmethod
def aa(num):
print("A.aa(): ", num)
this happens:
>>> A.a(1)
A.a(): 1
# I don't understand why this works
>>> A.aa(1)
A.aa(): 1
>>> A().a(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: a() takes 1 positional argument but 2 were given
# I understand that this happens because the first argument
# being given to `a()` is the instance of A
What exactly happened here? If I don't pass self to the a() method, what kind of a method is it? Why does it work without an instance of the class?
This is a static method. It will work, but it will not be able to access any of the other properties/methods that the class has. For example, suppose you have the following class.
class newClass:
b = 9
def print_b():
print(b)
newClass.print_b()
This will throw an error, since the function can not access the variable b. Hope this helps.
Similarly, you can not do the following, because when you call a method like this, you automatically pass an instance of the class into the function. Consequently, the function will throw an error saying it expects 0 positional arguments, but you have passed one.
x = newClass()
x.print_b()

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

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