 # how smart is lazy evaluation len(obj) == 1 will it count all?

• Last Update :
• Techknowledgy :

If you define a `__len__` method on your own class that doesn't keep track of it's length, you might do this

```def __len__(self):
return sum(1
for i in self)```

Suggestion : 2

In programming language theory, lazy evaluation, or call-by-need, is an evaluation strategy which delays the evaluation of an expression until its value is needed (non-strict evaluation) and which also avoids repeated evaluations (sharing). ,The opposite of lazy evaluation is eager evaluation, sometimes known as strict evaluation. Eager evaluation is the evaluation strategy employed in most[quantify] programming languages. ,In Python 2.x the range() function computes a list of integers. The entire list is stored in memory when the first assignment statement is evaluated, so this is an example of eager or immediate evaluation: ,Lazy evaluation allows control structures to be defined normally, and not as primitives or compile-time techniques. For example one can define if-then-else and short-circuit evaluation operators:

```ifThenElse True b c = b
ifThenElse False b c = c

--or
True || b = True
False || b = b

--and
True && b = b
False && b = False```
```numberFromInfiniteList::Int - > Int
numberFromInfiniteList n = infinity!!n - 1
where infinity = [1..]

main = print \$ numberFromInfiniteList 4```
` fibs = 0: 1: zipWith(+) fibs(tail fibs)`
```interface Lazy<T> {
T eval();
}
```
```Lazy<Integer> a = ()-> 1;
for (int i = 1; i <= 10; i++) {
final Lazy<Integer> b = a;
a = ()-> b.eval() + b.eval();
}
System.out.println( "a = " + a.eval() );
```
```class Memo<T> implements Lazy<T> {
private Lazy<T> lazy;  // a lazy expression, eval sets it to null
private T memo = null; // the memorandum of the previous value

public Memo( Lazy<T> lazy ) { // constructor
this.lazy = lazy;
}

public T eval() {
if (lazy != null) {
memo = lazy.eval();
lazy = null;
}
return memo;
}
}
```

Suggestion : 3

In this tutorial, you'll learn how to create iterations easily using Python generators, how it is different from iterators and normal functions, and why you should use it.,It is fairly simple to create a generator in Python. It is as easy as defining a normal function, but with a yield statement instead of a return statement.,Python generators are a simple way of creating iterators. All the work we mentioned above are automatically handled by generators in Python.,This is because a for loop takes an iterator and iterates over it using next() function. It automatically ends when StopIteration is raised. Check here to know how a for loop is actually implemented in Python.

Here is an example to illustrate all of the points stated above. We have a generator function named `my_gen()` with several `yield` statements.

```# A simple generator
function
def my_gen():
n = 1
print('This is printed first')
# Generator
function contains yield statements
yield n

n += 1
print('This is printed second')
yield n

n += 1
print('This is printed at last')
yield n```

An interactive run in the interpreter is given below. Run these in the Python shell to see the output.

```>>> # It returns an object but does not start execution immediately. >>>
a = my_gen()

>>>
# We can iterate through the items using next(). >>>
next(a)
This is printed first
1
>>>
# Once the
function yields, the
function is paused and the control is transferred to the caller.

>>>
# Local variables and theirs states are remembered between successive calls. >>>
next(a)
This is printed second
2

>>>
next(a)
This is printed at last
3

>>>
# Finally, when the
function terminates, StopIteration is raised automatically on further calls. >>>
next(a)
Traceback(most recent call last):
...
StopIteration >>>
next(a)
Traceback(most recent call last):
...
StopIteration```

This is because a `for` loop takes an iterator and iterates over it using `next()` function. It automatically ends when `StopIteration` is raised. Check here to know how a for loop is actually implemented in Python.

```# A simple generator
function
def my_gen():
n = 1
print('This is printed first')
# Generator
function contains yield statements
yield n

n += 1
print('This is printed second')
yield n

n += 1
print('This is printed at last')
yield n

# Using
for loop
for item in my_gen():
print(item)```

Let's take an example of a generator that reverses a string.

```def rev_str(my_str):
length = len(my_str)
for i in range(length - 1, -1, -1):
yield my_str[i]

# For loop to reverse the string
for char in rev_str("hello"):
print(char)```

Output

```o
l
l
e
h```

Suggestion : 4

The length of the string object being compared must be at least 1, or the is* methods will return False. In other words, a string object of len(string) == 0, is considered "empty", or False. ,Another great feature of Python is its availability for all platforms. Python can run on Microsoft Windows, Macintosh and all Linux distributions with ease. This makes the programs very portable, as any program written for one platform can easily be used on another. , A Python script can find out about the type, class, attributes and methods of an object. This is referred to as reflection or introspection. See also Metaclasses. ,When working on systems such as Microsoft Windows™, the directory separators will conflict with the path string. To get around this, do the following:

``` >>> print("Hello World!")
Hello World!```
`python - V`
`pacman - S python`
`pacman - S python2`
```if 1:
print("True")
print("Done")```
```if 1:
print("True")

print("Done")```

Suggestion : 5

An ndarray is a generic multidimensional container for homogeneous data; that is, all of the elements must be the same type. Every array has a shape, a tuple indicating the size of each dimension, and a dtype, an object describing the data type of the array:,Higher dimensional objects give you more options as you can slice one or more axes and also mix integers. Consider the 2D array above, arr2d. Slicing this array is a bit different:,One of the key features of NumPy is its N-dimensional array object, or ndarray, which is a fast, flexible container for large data sets in Python. Arrays enable you to perform mathematical operations on whole blocks of data using similar syntax to the equivalent operations between scalar elements:,NumPy array indexing is a rich topic, as there are many ways you may want to select a subset of your data or individual elements. One-dimensional arrays are simple; on the surface they act similarly to Python lists:

```In: data1 = [6, 7.5, 8, 0, 1]

In: arr1 = np.array(data1)

In: arr1
Out: array([6., 7.5, 8., 0., 1.])```
```In: arr1 = np.array([1, 2, 3], dtype = np.float64)

In: arr2 = np.array([1, 2, 3], dtype = np.int32)

In: arr1.dtype In: arr2.dtype
Out: dtype('float64') Out: dtype('int32')```
```In: arr = np.array([
[1., 2., 3.],
[4., 5., 6.]
])

In: arr
Out:
array([
[1., 2., 3.],
[4., 5., 6.]
])

In: arr * arr In: arr - arr
Out: Out:
array([
[1., 4., 9.], array([
[0., 0., 0.],
[16., 25., 36.]
])[0., 0., 0.]
])```
```In: arr = np.arange(10)

In: arr
Out: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In: arr
Out: 5

In: arr[5: 8]
Out: array([5, 6, 7])

In: arr[5: 8] = 12

In: arr
Out: array([0, 1, 2, 3, 4, 12, 12, 12, 8, 9])```
```In: arr[1: 6]
Out: array([1, 2, 3, 4, 64])```
```In: names = np.array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'])

In: data = np.random.randn(7, 4)

In: names
Out:
array(['Bob', 'Joe', 'Will', 'Bob', 'Will', 'Joe', 'Joe'],
dtype = '|S4')

In: data
Out:
array([
[-0.048, 0.5433, -0.2349, 1.2792],
[-0.268, 0.5465, 0.0939, -2.0445],
[-0.047, -2.026, 0.7719, 0.3103],
[2.1452, 0.8799, -0.0523, 0.0672],
[-1.0023, -0.1698, 1.1503, 1.7289],
[0.1913, 0.4544, 0.4519, 0.5535],
[0.5994, 0.8174, -0.9297, -1.2564]
])```