This question already has an answer here:
Can't dynamically bind __repr__/__str__ to a class created with type [duplicate]
(1 answer)
Closed 3 years ago.
I'm curious how repr works. It can't be exactly
def repr_(x):
return x.__repr__()
since that does not work on classes, namely
repr_(int)
causes an error since int's repr expects an int object as the first argument. I know that I can customize a class's repr by creating a metaclass with a desired __repr__, but I want to know how does Python's built in repr work? And how does it specifically handle the case of having a class passed into it.
Does it do something like a try catch where it first tries what my repr_ does and then looks up the MRO for other reprs? Or something else?
Figured it out. If we inspect how Python internally computes repr, which we can see in the source file object.c, we can see that repr is essentially
def repr_(x):
return x.__class__.__repr__(x)
import datetime
today=datetime.date.today()
print(repr(today))
for objects of classes, repr basically displays unambiguous output when obj call is their.
Documentation https://www.cmi.ac.in/~madhavan/courses/prog2-2015/docs/python-3.4.2-docs-html/library/functions.html#repr
Return a string containing a printable representation of an object.
For many types, this function makes an attempt to return a string that
would yield an object with the same value when passed to eval(),
otherwise the representation is a string enclosed in angle brackets
that contains the name of the type of the object together with
additional information often including the name and address of the
object. A class can control what this function returns for its
instances by defining a repr() method.
Related
This question already has answers here:
What does it mean when the parentheses are omitted from a function or method call?
(6 answers)
Closed 2 years ago.
I'm a beginner to Python and programming in general. Right now, I'm having trouble understanding the function of empty parentheses at the end of method names, built-in or user-created. For example, if I write:
print "This string will now be uppercase".upper()
...why is there an empty pair of parentheses after "upper?" Does it do anything? Is there a situation in which one would put something in there? Thanks!
Because without those you are only referencing the method object. With them you tell Python you wanted to call the method.
In Python, functions and methods are first-order objects. You can store the method for later use without calling it, for example:
>>> "This string will now be uppercase".upper
<built-in method upper of str object at 0x1046c4270>
>>> get_uppercase = "This string will now be uppercase".upper
>>> get_uppercase()
'THIS STRING WILL NOW BE UPPERCASE'
Here get_uppercase stores a reference to the bound str.upper method of your string. Only when we then add () after the reference is the method actually called.
That the method takes no arguments here makes no difference. You still need to tell Python to do the actual call.
The (...) part then, is called a Call expression, listed explicitly as a separate type of expression in the Python documentation:
A call calls a callable object (e.g., a function) with a possibly empty series of arguments.
the parentheses indicate that you want to call the method
upper() returns the value of the method applied to the string
if you simply say upper, then it returns a method, not the value you get when the method is applied
>>> print "This string will now be uppercase".upper
<built-in method upper of str object at 0x7ff41585fe40>
>>>
upper() is a command asking the upper method to run, while upper is a reference to the method itself. For example,
upper2 = 'Michael'.upper
upper2() # does the same thing as 'Michael'.upper() !
I am new in Python. I have written the below code --
class AF:
def __repr__(self):
return {'name':1, 'age':44}
c = AF()
print(c.__repr__())
print(repr(c))
When I run this, it is generating below error --
{'name': 1, 'age': 44}
print(repr(c))
TypeError: __repr__ returned non-string (type dict)
I read in Python documentation that repr should return string, OK got it, then why the first print statement ran successfully and printed the dictionary and the second print generated error? Shouldnot both the calls have failed? Trying to understand what is happening internally here.
It seems likely that the built-in repr function is performing an additional check on the return type of the instance's __repr__ function and raising an error if it is not a str as expected, whereas the __repr__ function when called directly, as any other function, can return any value
The __repr__ isn't just an ordinary method, it's a special built-in function that looks a lot like operators. These operators offer more than any method can offer.
When you called c.__repr__() you are calling the method part. On the other hand, when you called repr(c), you have called the operator. Same with __add__ operator. It can be called as a normal method a.__add__(b) or it can be used as an operator (which would require more assertions) like so a + b
This question already has answers here:
How to get a function name as a string?
(14 answers)
Closed 6 years ago.
I'm using format to test a function in Python. I would like the output of a function
def test(f,k):
print "{0}({1})={2}".format(f,k,f(k))
given
test(Sqrt,4)
to be
Sqrt(4)=2
But format is giving back the type 'function' and a memory address inside angle braces. Is there a neat way to shorten the output to get what I'm after?
You are looking to use __name__:
def test(f,k):
print("{0}({1})={2}".format(f.__name__,k,f(k)))
test(sqrt, 2)
Output:
sqrt(2)=1.4142135623730951
From the "Callable types" section of the Data Model docs here , __name__ is simply:
__name__ func_name : The function’s name.
Read the documentation carefully to understand what is available to you when wanting to use these types of attributes. Typically, this will be available to callable types (e.g. when defining a method or class, the __name__ attribute will be available to you). But if you simply define a non-callable, something like:
x = 5
and try to call x.__name__, you will be met with an AttributeError
Unlike most objects in Python, functions have a __name__ attribute set to the name they were defined with. You could use that:
print "{0}({1})={2}".format(f.__name__, k, f(k))
Classes also have a __name__, but most other callables don't. If f is some other kind of callable, you'll have to deal with it differently, in a manner that will depend on what kind of callable it is and whether you control its implementation.
This question already has answers here:
Why does Python code use len() function instead of a length method?
(7 answers)
Closed 8 years ago.
Just starting out with Python
Could anyone explain the reasoning behind why some built in string functions take arguments within their brackets like this:
length = len("This is a string")
whilst some other functions seem to just be "chained" on to the end of the string that they are operating on for example:
uppercase = "lowercase string".upper()
Probably a silly question but just wondered if there was a reason behind this that I'm unaware of.
len() is a built in function, it returns length of a sequence, that is you can pass lists, tuples to len() not only strings. For example:
foo = (1,2,3)
len(foo)
>>> 3
bar = ['a', 'b', 'c', 'd']
len(bar)
>>> 4
And about brackets - in your example what is between brackets is a string. You can also do this:
foo = "This is a string"
len(foo)
And the
"lowercase string".upper()
Is calling a method of a string object, which returns uppercase of that string. You can do the same with:
foo = "lowercase string"
uppercase = foo.upper()
the function len() is a buildin-function in the language. len() docs
and the .upper() function that your using is part of the string class. str.upper() docs
Len is a function, a built-in function, so using len (something) you apply a transformation to your input and obtain an output, something like Y=f(X).
"some string".upper() is a Method of the instance "some string"; "some string" belongs to the class String and has its methods.
Pay attention that "some string" written like that is an object and has all it's methods, you can see this if you type:
>>type("some string")
str
In summary: len is a function and is defined externally, .upper() is a method defined within the object itself
In the first case len is a function which you're calling within the current namespace, and you're passing a parameter to it. In the second, calling xyz.upper() means you are calling the method .upper() on the String object "lowercase string".
The len() function calls the __len__() method on the object passed in to it, so really it is just a shortcut for calling that method. Some other users have already posted links to the reasoning behind this (thank you for the correction larsmans).
This question already has answers here:
What is the best (idiomatic) way to check the type of a Python variable? [duplicate]
(10 answers)
Closed 5 years ago.
Sometimes checking of arguments in Python is necessary. e.g. I have a function which accepts either the address of other node in the network as the raw string address or class Node which encapsulates the other node's information.
I use type() function as in:
if type(n) == type(Node):
do this
elif type(n) == type(str)
do this
Is this a good way to do this?
Update 1: Python 3 has annotation for function parameters. These can be used for type checks using tool: http://mypy-lang.org/
Use isinstance(). Sample:
if isinstance(n, unicode):
# do this
elif isinstance(n, Node):
# do that
...
>>> isinstance('a', str)
True
>>> isinstance(n, Node)
True
Sounds like you're after a "generic function" - one which behaves differently based on the arguments given. It's a bit like how you'll get a different function when you call a method on a different object, but rather than just using the first argument (the object/self) to lookup the function you instead use all of the arguments.
Turbogears uses something like this for deciding how to convert objects to JSON - if I recall correctly.
There's an article from IBM on using the dispatcher package for this sort of thing:
From that article:
import dispatch
#dispatch.generic()
def doIt(foo, other):
"Base generic function of 'doIt()'"
#doIt.when("isinstance(foo,int) and isinstance(other,str)")
def doIt(foo, other):
print "foo is an unrestricted int |", foo, other
#doIt.when("isinstance(foo,str) and isinstance(other,int)")
def doIt(foo, other):
print "foo is str, other an int |", foo, other
#doIt.when("isinstance(foo,int) and 3<=foo<=17 and isinstance(other,str)")
def doIt(foo, other):
print "foo is between 3 and 17 |", foo, other
#doIt.when("isinstance(foo,int) and 0<=foo<=1000 and isinstance(other,str)")
def doIt(foo, other):
print "foo is between 0 and 1000 |", foo, other
You can also use a try catch to type check if necessary:
def my_function(this_node):
try:
# call a method/attribute for the Node object
if this_node.address:
# more code here
pass
except AttributeError, e:
# either this is not a Node or maybe it's a string,
# so behavior accordingly
pass
You can see an example of this in Beginning Python in the second about generators (page 197 in my edition) and I believe in the Python Cookbook. Many times catching an AttributeError or TypeError is simpler and apparently faster. Also, it may work best in this manner because then you are not tied to a particular inheritance tree (e.g., your object could be a Node or it could be something other object that has the same behavior as a Node).
No, typechecking arguments in Python is not necessary. It is never
necessary.
If your code accepts addresses as rawstring or as a Node object, your
design is broken.
That comes from the fact that if you don't know already the type of an
object in your own program, then you're doing something wrong already.
Typechecking hurts code reuse and reduces performance. Having a function
that performs different things depending on the type of the object passed
is bug-prone and has a behavior harder to understand and maintain.
You have following saner options:
Make a Node object constructor that accepts rawstrings, or a function
that converts strings in Node objects. Make your function assume the
argument passed is a Node object. That way, if you need to pass a
string to the function, you just do:
myfunction(Node(some_string))
That's your best option, it is clean, easy to understand and maintain.
Anyone reading the code immediatelly understands what is happening,
and you don't have to typecheck.
Make two functions, one that accepts Node objects and one that accepts
rawstrings. You can make one call the other internally, in the most
convenient way (myfunction_str can create a Node object and call
myfunction_node, or the other way around).
Make Node objects have a __str__ method and inside your function,
call str() on the received argument. That way you always get a string
by coercion.
In any case, don't typecheck. It is completely unnecessary and has only
downsides. Refactor your code instead in a way you don't need to typecheck.
You only get benefits in doing so, both in short and long run.