simple instantiations of python classes - python

Can you please explain why 'hello world' isn't returned below? What do I need to modify for it to be expressed properly when called? Thanks.
>>> class MyClass:
... i=12345
... def f(self):
... return 'hello world'
...
>>> x=MyClass()
>>> x.i
12345
>>> x.f
<bound method MyClass.f of <__main__.MyClass instance at 0x060100F8>>

f is a method, so you need to call it. i.e. x.f()
It's no different than if you define a function without the class:
def f():
return 'something'
If you just refer to f, you'll get the function itself
print f
yields <function f at 0xdcc2a8>, while
print f()
yields "something".

When inside the REPL (or the Python console, or whatever) the value returned by the last statement will always be printed. If it is just a value the value will be printed:
>>> 1
1
If it is an assignment, then nothing will be printed:
>>> a = 1
But, watch this:
>>> a = 1
>>> a
1
Ok, so in your code above:
>>> x=MyClass()
>>> x # I'm adding this :-). The number below may be different, it refers to a
# position in memory which is occupied by the variable x
<__main__.MyClass instance at 0x060100F8>
So, the value of x is an instance of MyClass located at a spot in memory.
>>> x.i
12345
The value of x.i is 12345, so it will be printed as above.
>>> x.f
<bound method MyClass.f of <__main__.MyClass instance at 0x060100F8>>
The value of f is a method of x (that's what it means to have def in front of something, it is a method). Now, since it is a method, let's call it by adding the () after it:
>>> x.f()
'hello world'
The value returned by f method on the MyClass instance in the variable x is 'hello world'! But wait! There are quotes. Let's get rid of them by using the print function:
>>> print(x.f()) # this may be print x.f() (note the number of parens)
# based on different versions of Python.
hello world

Related

What is the specific name of this output?

I have made a function named 'function' as below.
>>> def function():
return 'hello world'
>>> function
<function function at 0x7fac99db3048> #this is the output
What is this output exactly? It's specific name? And it's significance?
I know it gives info about memory location. But I need more information about this output.
Do the higher-order function return similar data while they are returning function?
In python function is an object and thus when you call function it returns you the memory address. The higher-order functions behave the same way. However there some differences:
def a():
print("Hello, World!")
def b():
return a
>>> a
<function a at 0x7f8bd15ce668>
>>> b
<function b at 0x7f8bd15ce6e0>
c = b
>>>c
<function b at 0x7f8bd15ce6e0>
c = b()
<function a at 0x7f8bd15ce668>
Note what the function c returns in different situations.
In order to call the function, you need to call it with (). Without that you are seeing reference to the function function stored at 0x7fac99db3048. You may also store it in another variable as:
>>> my_new = function # store function object in different variable
>>> function
<function function at 0x10502bc80>
# ^ memory address of my system
>>> my_new
<function function at 0x10502bc80>
# ^ same as above
>>> my_new() # performs same task
'hello world'
Let's see the content displayed for another function with name other than function:
>>> def hello_world():
... print 'hello world'
...
>>> hello_world
# v Name of function
<function hello_world at 0x105027758>
# ^ says object of type 'function'|^- memory address of function
# (for eg: for class says 'class')|

Python closures using lambda

I saw this below piece of code in a tutorial and wondering how it works.
Generally, the lambda takes a input and returns something but here it does not take anything and still it works.
>>> for i in range(3):
... a.append(lambda:i)
...
>>> a
[<function <lambda> at 0x028930B0>, <function <lambda> at 0x02893030>, <function
<lambda> at 0x028930F0>]
lambda:i defines the constant function that returns i.
Try this:
>>> f = lambda:3
>>> f()
You get the value 3.
But there's something more going on. Try this:
>>> a = 4
>>> g = lambda:a
>>> g()
gives you 4. But after a = 5, g() returns 5. Python functions "remember" the environment in which they're executed. This environment is called a "closure". By modifying the data in the closure (e.g. the variable a in the second example) you can change the behavior of the functions defined in that closure.
In this case a is a list of function objects defined in the loop.
Each of which will return 2.
>>> a[0]()
2
To make these function objects remember i values sequentially you should rewrite the code to
>>> for i in range(3):
... a.append(lambda x=i:x)
...
that will give you
>>> a[0]()
0
>>> a[1]()
1
>>> a[2]()
2
but in this case you get side effect that allows you to not to use remembered value
>>> a[0](42)
42
I'm not sure what you mean by "it works". It appears that it doesn't work at all. In the case you have presented, i is a global variable. It changes every time the loop iterates, so after the loop, i == 2. Now, since each lambda function simply says lambda:i each function call will simply return the most recent value of i. For example:
>>> a = []
>>> for i in range(3):
a.append(lambda:1)
>>> print a[0]()
2
>>> print a[1]()
2
>>> print a[2]()
In other words, this does not likely do what you expect it to do.
lambda defines an anonymous inline function. These functions are limited compared to the full functions you can define with def - they can't do assignments, and they just return a result. However, you can run into interesting issues with them, as defining an ordinary function inside a loop is not common, but lambda functions are often put into loops. This can create closure issues.
The following:
>>> a = []
>>> for i in range(3):
... a.append(lambda:i)
adds three functions (which are first-class objects in Python) to a. These functions return the value of i. However, they use the definition of i as it existed at the end of the loop. Therefore, you can call any of these functions:
>>> a[0]()
2
>>> a[1]()
2
>>> a[2]()
2
and they will each return 2, the last iteration of the range object. If you want each to return a different number, use a default argument:
>>> for i in range(3):
... a.append(lambda i=i:i)
This will forcibly give each function an i as it was at that specific point during execution.
>>> a[0]()
0
>>> a[1]()
1
>>> a[2]()
2
Of course, since we're now able to pass an argument to that function, we can do this:
>>> b[0](5)
5
>>> b[0](range(3))
range(0, 3)
It all depends on what you're planning to do with it.

Method inside a method in Python

I have seen source code where more than one methods are called on an object eg x.y().z() Can someone please explain this to me, does this mean that z() is inside y() or what?
This calls the method y() on object x, then the method z() is called on the result of y() and that entire line is the result of method z().
For example
friendsFavePizzaToping = person.getBestFriend().getFavoritePizzaTopping()
This would result in friendsFavePizzaTopping would be the person's best friend's favorite pizza topping.
Important to note: getBestFriend() must return an object that has the method getFavoritePizzaTopping(). If it does not, an AttributeError will be thrown.
Each method is evaluated in turn, left to right. Consider:
>>> s='HELLO'
>>> s.lower()
'hello'
>>> s='HELLO '
>>> s.lower()
'hello '
>>> s.lower().strip()
'hello'
>>> s.lower().strip().upper()
'HELLO'
>>> s.lower().strip().upper().replace('H', 'h')
'hELLO'
The requirement is that the object to the left in the chain has to have availability of the method on the right. Often that means that the objects are similar types -- or at least share compatible methods or an understood cast.
As an example, consider this class:
class Foo:
def __init__(self, name):
self.name=name
def m1(self):
return Foo(self.name+'=>m1')
def m2(self):
return Foo(self.name+'=>m2')
def __repr__(self):
return '{}: {}'.format(id(self), self.name)
def m3(self):
return .25 # return is no longer a Foo
Notice that as a type of immutable, each return from Foo is a new object (either a new Foo for m1, m2 or a new float). Now try those methods:
>>> foo
4463545376: init
>>> foo.m1()
4463545304: init=>m1
^^^^ different object id
>>> foo
4463545376: init
^^^^ foo still the same because you need to assign it to change
Now assign:
>>> foo=foo.m1().m2()
>>> foo
4464102576: init=>m1=>m2
Now use m3() and it will be a float; not a Foo anymore:
>>> foo=foo.m1().m2().m3()
>>> foo
.25
Now a float -- can't use foo methods anymore:
>>> foo.m1()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'float' object has no attribute 'm1'
But you can use float methods:
>>> foo.as_integer_ratio()
(1, 4)
In the case of:
x.y().z()
You're almost always looking at immutable objects. Mutable objects don't return anything that would HAVE a function like that (for the most part, but I'm simplifying). For instance...
class x:
def __init__(self):
self.y_done = False
self.z_done = False
def y(self):
new_x = x()
new_x.y_done = True
return new_x
def z(self):
new_x = x()
new_x.z_done = True
return new_x
You can see that each of x.y and x.z returns an x object. That object is used to make the consecutive call, e.g. in x.y().z(), x.z is not called on x, but on x.y().
x.y().z() =>
tmp = x.y()
result = tmp.z()
In #dawg's excellent example, he's using strings (which are immutable in Python) whose methods return strings.
string = 'hello'
string.upper() # returns a NEW string with value "HELLO"
string.upper().replace("E","O") # returns a NEW string that's based off "HELLO"
string.upper().replace("E","O") + "W"
# "HOLLOW"
The . "operator" is Python syntax for attribute access. x.y is (nearly) identical to
getattr(x, 'y')
so x.y() is (nearly) identical to
getattr(x, 'y')()
(I say "nearly identical" because it's possible to customize attribute access for a user-defined class. From here on out, I'll assume no such customization is done, and you can assume that x.y is in fact identical to getattr(x, 'y').)
If the thing that x.y() returns has an attribute z such that
foo = getattr(x, 'y')
bar = getattr(foo(), 'z')
is legal, then you can chain the calls together without needing the name foo in the middle:
bar = getattr(getattr(x, 'y')(), 'z')
Converting back to dot notation gives you
bar = getattr(x.y(), 'z')
or simply
bar = x.y().z()
x.y().z() means that the x object has the method y() and the result of x.y() object has the method z() . Now if you first want to apply the method y() on x and then on the result want to apply the z() method, you will write x.y().z(). This is like,
val = x.y()
result = val.z()
Example:
my_dict = {'key':'value'}
my_dict is a dict type object. my_dict.get('key') returns 'value' which is a str type object. now I can apply any method of str type object on it. which will be like,
my_dict.get('key').upper()
This will return 'VALUE'.
That is (sometimes a sign of) bad code.
It violates The law of Demeter. Here is a quote from Wikipedia explaining what is meant:
Each unit should have only limited knowledge about other units: only units "closely" related to the current unit.
Each unit should only talk to its friends; don't talk to strangers.
Only talk to your immediate friends.
Suppose you have a car, which itself has an engine:
class Car:
def __init__(self):
self._engine=None
#property
def engine(self):
return self._engine
#engine.setter
def engine(self, value):
self._engine = value
class Porsche_engine:
def start(self):
print("starting")
So if you make a new car and set the engine to Porsche you could do the following:
>>> from car import *
>>> c=Car()
>>> e=Porsche_engine()
>>> c.engine=e
>>> c.engine.start()
starting
If you are maing this call from an Object, it has not only knowledge of a Car object, but has too knowledge of Engine, which is bad design.
Additionally: if you do not know whether a Car has an engine, calling directly start
>>> c=Car()
>>> c.engine.start()
May result in an Error
AttributeError: 'NoneType' object has no attribute 'start'
Edit:
To avoid (further) misunterstandings and misreadings, from what I am saying.
There are two usages:
1) as I pointed out, Objects calling methods on other objects, returned from a third object is a violation of LoD. This is one way to read the question.
2) an exception to that is method chaining, which is not bad design.
And a better design would be, if the Car itself had a start()-Method which delegates to the engine.

Python behavior for immutable default parameter values

>>> def a():
... print "a executed"
... return []
...
>>>
>>> def b(x=a()):
... x.append(5)
... print x
...
a executed
>>> b()
[5]
>>> b()
[5, 5]
x is bound to an empty list object when the function b is first defined. the empty list object gets modified each time b is called because b is bound to the object.
What I don't get is when this happens to immutable objects:
>>> def a():
... print "a executed"
... return 0
...
>>>
>>> def b(x=a()):
... x = x + 2
... print x
...
a executed
>>> b()
2
>>> b()
2
From my POV, x is bound to the int object 0 when the function b is first defined. Then, x is modified when b() is called. Therefore subsequent calls to b() should re-bind x to 2, 4, 6, and so on. Why doesn't this occur? I am obviously missing something important here!
Thx :)
When you do x = you're not modifying the object that x references, you're just changing the reference x to point to a different object, in this case, another int. In this case it's event irrelevant whether x points to an immutable object. If you would do x = x + [5] with lists, it would also remain unchanged. Note the difference:
def b1(x = []):
x = x + [5]
print(x)
def b2(x = []):
x.append(5)
print(x)
print("b1:")
b1()
print("b1:")
b1()
print("b2:")
b2()
print("b2:")
b2()
Gives:
b1:
[5]
b1:
[5]
b2:
[5]
b2:
[5, 5]
When the function is being executed, you're working on a local variable x that either was initialized using the default value, or provided by the caller. So what gets rebound is the local variable x, not the default value for the parameter.
You may want to also read about the difference between formal and actual parameters. It's only slightly related to this problem, but may help you understand this better. An example explanation can be found here.
Careful, there's a huge difference between:
x.append(5)
and:
x = x + 1
Namely, the first mutates the object referenced by x whereas the second creates a new object which is the result of x + 1 and rebinds it to the name x.
Of course, this is a bit of an over-simplification -- e.g. what if you had used += ...
It really falls back on how __add__ and __iadd__ are defined in the first place, but this should get the point across ...
To go a little deeper, you can think of a function as an object or an instance of a class. It has some special attributes which you can even look at if you want to:
>>> def foo(x = lst): pass
...
>>> foo.func_defaults
([],)
>>> foo.func_defaults[0] is lst
True
When the function is defined, func_defaults1 gets set. Every time the function gets called, python looks at the defaults and the stuff which was present in the call and it figures out which defaults to pass into the function and which ones were provided already. The take away is that this is why, when you append to the list in the first case, the change persists -- You're actually changing the value in func_defaults too. In the second case where you use x = x + 1, you're not actually doing anything to change func_defaults -- You're just creating something new and putting it into the function's namespace.
1the attribute is just __defaults__ in python3.x

What's the difference between assigning a function with and without parentheses?

What's the difference in python between
value = getValue()
and
value = getValue
?
Using parenthesis calls the function where as not using them creates a reference to that function.
See below:
>>> def t():
... return "Hi"
...
>>> a = t
>>> a
<function t at 0x01BECA70>
>>> a = t()
>>> a
'Hi'
>>>
Here is a good link to explain further: http://docs.python.org/2/tutorial/controlflow.html (scroll down to the "defining functions" part).
value = getValue() is a function call and assignment of the return value. It means "call function getValue with no arguments and make value refer to whatever it returns".
value = getValue says "make value refer to the same function that getValue refers to".

Categories

Resources