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

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.

Related

Creating classes and variable assignment

I'm trying to understand how classes work a bit better "under the hood" of python.
If I create a class Foo like so
class Foo:
bar = True
Foo is then directly accessible, such as print(Foo) or print(Foo.bar)
However, if I dynamically create create a class and don't set it to a variable like so
type('Foo',(),{'bar':True})
If done in the interpreter it shows <class '__main__.Foo'>. However, when I try to print Foo it's undefined...NameError: name 'Foo' is not defined
Does this mean that when a class is created the "traditional" way (the first Foo class above), that python automatically sets a variable for the class of the same name? Sort of like this
# I realize this is not valid, just to convey the idea
Foo = class Foo:
bar = True
If so, then why doesn't python also create a variable named Foo set to class Foo when using type() to create it?
let's compare your problem with function statements and lambdas (because they play the same role here), consider this function f :
def f ():
return 1
the above snippet of code is not an expression at all, it is a python statement that creates a function named f returning 1 upon calling it.
let's now do the same thing, but in a different way :
f = lambda : 1
the above snippet of code is a python expression (an assignment) that assigns the symbol f to the lambda expression (which is our function) lambda : 1. if we didn't do the assignment, the lambda expression would be lost, it is the same as writing >>> 1 in the python REPL and then trying after that to reference it.
Using type with 3 argument is analogous to using the lambda to create a function. Without assignment the evaluated expression is garbage collected.
However, just you can still create an instance of the class, just like you can immediately call a lambda function.
>>> lambda x: True
<function <lambda> at 0x0000022FF95AB598>
>>> type('Test', (), {'x': True})
<class '__main__.Test'>
You can also create an instance of the class, just like you can immediately call a function
>>> t = type('Test', (), {'x': True})()
>>> t.x
True
>>> type('Test2', (), {'y': 123})().y
123
>>> (lambda x: True)(1000) # any input returns True
True
From documentation
class type(name, bases, dict)
With three arguments, return a new type object. This is essentially a dynamic form of the class statement. The name string is the class name and becomes the name attribute; the bases tuple itemizes the base classes and becomes the bases attribute; and the dict dictionary is the namespace containing definitions for class body and becomes the dict attribute. For example, the following two statements create identical type objects:
class X(object):
a = 1
X = type('X', (object,), dict(a=1))
So yes, I think you have the right idea. type() does create a class but a dynamic form.
I think you're making this too complicated. If you don't assign a value / object to a symbol, it is always "lost". Doesn't matter if the value / object is a class or something else. Example:
x = 2 + 2
That assigns the value 4 to the symbol x. Compare to:
2 + 2
The operation is carried out but the result 4 isn't assigned to a symbol.
Exact situation you have with classes.

In Python, how does one override the behavior of a class instance typed on a line by itself

Without print (which I believe invokes str()) what happens when a variable is on a line by itself.
This is a bit contrived, I know, but I ran into this in a Jupyter notebook when testing a class I'm creating and now I'm curious. I can't seem to find the right set of Google search terms to find the answer in the docs.
I defined a class thusly:
class ExceptionList(BaseException):
pass
# I've implemented, in very standard ways, the following methods
# __str__()
# __getitem__()
# __delitem__()
# __repr__()
# I doubt any other specifics of the class are pertinent
EDIT
Here is the repr() implementation:
def __repr__(self):
return "{}({})".format(self.__class__.__name__, repr(self.__exception_list))
P.S. I coded that method based on http://brennerm.github.io/posts/python-str-vs-repr.html
EDIT
My implementation of repr() causes this behavior:
e = ExceptionList(["Oh, no"])
e
"ExceptionList(['Oh, no'])"
So consider:
e1 = Exception("Oh no!")
e2 = ExceptionList("Oh no!")
In separate notebook cells:
e1
Exception('Oh no!')
e2
__main__.ExceptionList()
Incidentally (maybe?) the output of:
e2.__class__
is close:
__main__.ExceptionList
Does it just have something to do with the scope in which the class was defined? Is it some special behavior of builtins?
Is this behavior this result of invoking some method that I'm unaware of? I tried implementing all of the methods produced with dir() though I'm willing to bet that's not exhaustive.
It probably doesn't matter for my implementation but now I need to know!
Boilerplate Hater Deterrent:
I don't know anything.
I'm a terrible programmer.
"I thought a python was a snake..."
I'm barely qualified to use a toaster.
Please forgive this post's pathetic usage of SO disk space.
If the sole content of a line is a variable or object, then that line is evaluated and the variable or object is returned and not stored to a variable.
a = 5 + 2 # 5+2 is evaluated and stored in a
5 + 2 # 5+2 is evaluated
a # a is evaluated
class SomeCustomClass:
def __init__(self, *args):
pass
scc = SomeCustomClass()
scc # returns a reference to this instance, but ref is not stored
Many python interfaces like Jupyter, IPython, IDLE will display the evaluation of the line.
>>> 5+2
7
>>> a=5+2
[Nothing]
>>> a
7
>>> scc
<__main__.SomeCustomClass instance at 0x7fb6d5943d40>
The <__main__.SomeCustomClass instance at 0x7fb6d5943d40> is called a representation of the class. If you look at Python's Data Model you will see that this representation is specified by the object's __repr__ method.
Modifying SomeCustomClass:
class SomeCustomClass:
def __init__(self, *args):
pass
def __repr__(self):
return "SomeCustomClass repr"
>>> scc = SomeCustomClass()
>>> scc
SomeCustomClass repr
>>> s = str(scc) #implicit call to __repr__
>>> s
SomeCustomClass repr
Now adding __str__ method:
class SomeCustomClass:
def __init__(self, *args):
pass
def __repr__(self):
return "SomeCustomClass repr"
def __str__(self):
return "SomeCustomClass str"
>>> scc = SomeCustomClass()
>>> scc
SomeCustomClass repr
>>> s = str(scc) #explicit call to __str__
>>> s
SomeCustomClass str

what is the significance of `__repr__` function over normal function [duplicate]

This question already has answers here:
Purpose of __repr__ method?
(6 answers)
Closed 5 years ago.
I am trying to learn python with my own and i stucked at __repr__ function. Though i have read lots of post on __repr__ along with the python document. so i have decided to ask this Question here. The code bellow explains my confusion.
class Point:
def __init__(self,x,y):
self.x, self.y = x,y
def __repr__(self):
return 'Point(x=%s, y=%s)'%(self.x, self.y)
def print_class(self):
return 'Point(x=%s, y=%s)'%(self.x, self.y)
p = Point(1,2)
print p
print p.print_class()
Point(x=1, y=2)
Point(x=1, y=2)
If a normal function can also perform similar task then what is the extra advantage of __repr__ over print_class() (in my case a normal function) function.
The __repr__ function is called by repr() internally. repr() is called when you are printing the object directly , and the class does not define a __str__() . From documentation -
object.__repr__(self)
Called by the repr() built-in function and by string conversions (reverse quotes) to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment). If this is not possible, a string of the form <...some useful description...> should be returned. The return value must be a string object. If a class defines __repr__() but not __str__(), then __repr__() is also used when an “informal” string representation of instances of that class is required.
In your case for print_class() , you have to specifically call the method when printing the object. But in case of __repr__() , it gets internally called by print .
This is especially useful, when you are mixing different classes/types . For Example lets take a list which can have numbers and objects of your point class, now you want to print the elements of the list.
If you do not define the __repr__() or __str__() , you would have to first check the instance , whether its of type Point if so call print_class() , or if not directly print the number.
But when your class defines the __repr__() or __str__() , you can just directly call print on all the elements of the list, print statement would internally take care of printing the correct values.
Example , Lets assume a class which has print_class() method, but no __repr__() or __str__() , code -
>>> class CA:
... def __init__(self,x):
... self.x = x
... def print_class(self):
... return self.x
...
>>> l = [1,2,3,CA(4),CA(5)]
>>> for i in l:
... print(i)
...
1
2
3
<__main__.CA object at 0x00590F10>
<__main__.CA object at 0x005A5070>
SyntaxError: invalid syntax
>>> for i in l:
... if isinstance(i, CA):
... print(i.print_class())
... else:
... print(i)
...
1
2
3
4
5
As you can see, when we mix numbers and objects of type CA in the list, and then when we just did print(i) , it did not print what we wanted. For this to work correctly, we had to check the type of i and call the appropriate method (as done in second case).
Now lets assume a class that implements __repr__() instead of print_class() -
>>> class CA:
... def __init__(self,x):
... self.x = x
... def __repr__(self):
... return str(self.x)
...
>>>
>>> l = [1,2,3,CA(4),CA(5)]
>>> for i in l:
... print(i)
...
1
2
3
4
5
As you can see in second case, simply printing worked, since print internally calls __str__() first, and as that did not exist fell back to __repr__() .
And not just this, when we do str(list) , internally each list's element's __repr__() is called. Example -
First case (without __repr__() ) -
>>> str(l)
'[1, 2, 3, <__main__.CA object at 0x005AB3D0>, <__main__.CA object at 0x005AB410>]'
Second case (with __repr__() ) -
>>> str(l)
'[1, 2, 3, 4, 5]'
Also, in interactive interpreter, when you are directly using the object, it shows you the output of repr() function, Example -
>>> class CA:
... def __repr__(self):
... return "CA instance"
...
>>>
>>> c = CA()
>>> c
CA instance
The difference is that the __repr__ function is automatically called by Python in certain contexts, and is part of a predefined API with specific requirements. For instance, if you enter p by itself(not print p) in the interactive shell after creating your p object, its __repr__ will be called. It will also be used for print p if you don't define a __str__on p. (That is, you had to write print p.print_class(), but you didn't have to write print p.__repr__(); Python called __repr__ automatically for you.) The requirements for __repr__ are described in the documentation:
Called by the repr() built-in function and by string conversions (reverse quotes) to compute the “official” string representation of an object. If at all possible, this should look like a valid Python expression that could be used to recreate an object with the same value (given an appropriate environment). If this is not possible, a string of the form <...some useful description...> should be returned.
In short, if you write your own method called print_class you can make it do whatever you want and tell people how to use it, because it's your API. If you use __repr__ you're supposed to follow the conventions of Python's API. Either one may make sense depending on the context.
It helps you do more efficient coding work. even though you get same result using user define method like 'print_class()' as repr, but you don't need to type in '.print_class()' by repr method.

Overriding special methods on builtin types

Can magic methods be overridden outside of a class?
When I do something like this
def __int__(x):
return x + 5
a = 5
print(int(a))
it prints '5' instead of '10'. Do I do something wrong or magic methods just can't be overridden outside of a class?
Short answer; not really.
You cannot arbitrarily change the behaviour of int() a builtin function (*which internally calls __int__()) on arbitrary builtin types such as int(s).
You can however change the behaviour of custom objects like this:
Example:
class Foo(object):
def __init__(self, value):
self.value = value
def __add__(self, other):
self.value += other
def __repr__(self):
return "<Foo(value={0:d})>".format(self.value)
Demo:
>>> x = Foo(5)
>>> x + 5
>>> x
<Foo(value=10)>
This overrides two things here and implements two special methods:
__repr__() which get called by repr()
__add__() which get called by the + operator.
Update: As per the comments above; techincally you can redefine the builtin function int; Example:
def int(x):
return x + 5
int(5) # returns 10
However this is not recommended and does not change the overall behaviour of the object x.
Update #2: The reason you cannot change the behaviour of bultin types (without modifying the underlying source or using Cuthon or ctypes) is because builtin types in Python are not exposed or mutable to the user unlike Homoiconic Languages (See: Homoiconicity). -- Even then I'm not really sure you can with Cython/ctypes; but the reason question is "Why do you want to do this?"
Update #3: See Python's documentation on Data Model (object.__complex__ for example).
You can redefine a top-level __int__ function, but nobody ever calls that.
As implied in the Data Model documentation, when you write int(x), that calls x.__int__(), not __int__(x).
And even that isn't really true. First, __int__ is a special method, meaning it's allowed to call type(x).__int__(x) rather than x.__int__(), but that doesn't matter here. Second, it's not required to call __int__ unless you give it something that isn't already an int (and call it with the one-argument form). So, it could be as if it's was written like this:
def int(x, base=None):
if base is not None:
return do_basey_stuff(x, base)
if isinstance(x, int):
return x
return type(x).__int__(x)
So, there is no way to change what int(5) will do… short of just shadowing the builtin int function with a different builtin/global/local function of the same name, of course.
But what if you wanted to, say, change int(5.5)? That's not an int, so it's going to call float.__int__(5.5). So, all we have to do is monkeypatch that, right?
Well, yes, except that Python allows builtin types to be immutable, and most of the builtin types in CPython are. So, if you try it:
>>> _real_float_int = float.__int__
>>> def _float_int(self):
... return _real_float_int(self) + 5
>>> _float_int(5.5)
10
>>> float.__int__ = _float_int
TypeError: can't set attributes of built-in/extension type 'float'
However, if you're defining your own types, that's a different story:
>>> class MyFloat(float):
... def __int__(self):
... return super().__int__() + 5
>>> f = MyFloat(5.5)
>>> int(f)
10

Are functions first class objects in python?

I am learning a tutorial on python.It is explaining how functions are first class objects in Python.
def foo():
pass
print(foo.__class__)
print(issubclass(foo.__class__,object))
The output that I get for the above code is
<type 'function'>
True
This program is supposed to demonstrate that functions are first class objects in python? My questions are as follows.
How does the above code prove that functions are fist class objects?
What are the attributes of a first class object?
what does function.__class__ signify? It returns a tuple <type,function> which doesn't mean much?
Here's what Guido says about first class objects in his blog:
One of my goals for Python was to make it so that all objects were "first class." By this, I meant that I wanted all objects that could be named in the language (e.g., integers, strings, functions, classes, modules, methods, etc.) to have equal status. That is, they can be assigned to variables, placed in lists, stored in dictionaries, passed as arguments, and so forth.
The whole blog post is worth reading.
In the example you posted, the tutorial may be making the point that first class objects are generally descendents of the "object" class.
First-class simply means that functions can be treated as a value -- that is you can assign them to variables, return them from functions, as well as pass them in as a parameter. That is you can do code like:
>>> def say_hi():
print "hi"
>>> def say_bye():
print "bye"
>>> f = say_hi
>>> f()
hi
>>> f = say_bye
>>> f()
bye
This is useful as you can now assign functions to variables like any ordinary variable:
>>> for f in (say_hi, say_bye):
f()
hi
bye
Or write higher order functions (that take functions as parameters):
>>> def call_func_n_times(f, n):
for i in range(n):
f()
>>> call_func_n_times(say_hi, 3)
hi
hi
hi
>>> call_func_n_times(say_bye, 2)
bye
bye
About __class__ in python tells what type of object you have. E.g., if you define an list object in python: a = [1,2,3], then a.__class__ will be <type 'list'>. If you have a datetime (from datetime import datetime and then d = datetime.now(), then the type of d instance will be <type 'datetime.datetime'>. They were just showing that in python a function is not a brand new concept. It's just an ordinary object of <type 'function'>.
You proved that functions are first class objects because you were allowed to pass foo as an argument to a method.
The attributes of first class objects was nicely summarised in this post: https://stackoverflow.com/a/245208/3248346
Depending on the language, this can
imply:
being expressible as an anonymous literal value
being storable in variables
being storable in data structures
having an intrinsic identity (independent of any given name)
being comparable for equality with other entities
being passable as a parameter to a procedure/function
being returnable as the result of a procedure/function
being constructible at runtime
being printable
being readable
being transmissible among distributed processes
being storable outside running processes
Regarding your third question, <type 'function'> isn't a tuple. Python's tuple notation is (a,b), not angle brackets.
foo.__class__ returns a class object, that is, an object which represents the class to which foo belongs; class objects happen to produce descriptive strings in the interpreter, in this case telling you that the class of foo is the type called 'function'. (Classes and types are basically the same in modern Python.)
It doesn't mean a whole lot other than that, like any other object, functions have a type:
>>> x = 1
>>> x.__class__
<type 'int'>
>>> y = "bar"
>>> y.__class__
<type 'str'>
>>> def foo(): pass
...
>>> foo.__class__
<type 'function'>
Regarding your comment to #I.K.s answer, f_at_2() in the following would be the method.
def f_at_2(f):
return f(2)
def foo(n):
return n ** n
def bar(n):
return n * n
def baz(n):
return n / 2
funcs = [foo, bar, baz]
for f in funcs:
print f.func_name, f_at_2(f)
...
>>>
foo 4
bar 4
baz 1
>>>
A method is a function of/in a class, but the concept also applies to a function (outside of a class). The functions (as objects) are contained in a data structure and passed to another object.

Categories

Resources