Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
12 views

Python Note 9

Python Learning Notes

Uploaded by

brian07151992
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

Python Note 9

Python Learning Notes

Uploaded by

brian07151992
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 25

Python code 9

28/01/2024

Computer logic

Have you noticed that the conditions we've used so far have been very simple, not to say, quite primitive? The conditions we use in
real life are much more complex. Let's look at this sentence:

If we have some free time, and the weather is good, we will go for a walk.

We've used the conjunction and , which means that going for a walk depends on the simultaneous fulfilment of these two
conditions. In the language of logic, such a connection of conditions is called a conjunction. And now another example:

If you are in the mall or I am in the mall, one of us will buy a gift for Mom.

The appearance of the word or means that the purchase depends on at least one of these conditions. In logic, such a compound is
called a disjunction.

It's clear that Python must have operators to build conjunctions and disjunctions. Without them, the expressive power of the
language would be substantially weakened. They're called logical operators.

and
One logical conjunction operator in Python is the word and. It's a binary operator with a priority that is lower than the one
expressed by the comparison operators. It allows us to code complex conditions without the use of parentheses like this one:

counter > 0 and value == 100

The result provided by the and operator can be determined on the basis of the truth table.

If we consider the conjunction of A and B , the set of possible values of arguments and corresponding values of the conjunction
looks as follows:

Argument A Argument B A and B


False False False
False True False
True False False
True True True

or

A disjunction operator is the word or . It's a binary operator with a lower priority than and (just like + compared to * ). Its truth
table is as follows:
Argument A Argument B A or B
False False False
False True True
True False True
True True True

not

In addition, there's another operator that can be applied for constructing conditions. It's a unary operator performing a logical
negation. Its operation is simple: it turns truth into falsehood and falsehood into truth.

This operator is written as the word not , and its priority is very high: the same as the unary + and - . Its truth table is simple:

Argument not Argument


False True
True False

Logical expressions

Let's create a variable named var and assign 1 to it. The following conditions are pairwise equivalent:
# Example 1:
print(var > 0)
print(not (var <= 0))

# Example 2:
print(var != 0)
print(not (var == 0))

You may be familiar with De Morgan's laws. They say that:

The negation of a conjunction is the disjunction of the negations.

The negation of a disjunction is the conjunction of the negations.

Let's write the same thing using Python:

not (p and q) == (not p) or (not q)


not (p or q) == (not p) and (not q)

Logical values vs. single bits


Logical operators take their arguments as a whole regardless of how many bits they contain. The operators are aware only of the
value: zero (when all the bits are reset) means False ; not zero (when at least one bit is set) means True .

The result of their operations is one of these values: False or True . This means that this snippet will assign the value True to
the j variable if i is not zero; otherwise, it will be False .

i = 1
j = not not i

Bitwise operators

However, there are four operators that allow you to manipulate single bits of data. They are called bitwise operators.

They cover all the operations we mentioned before in the logical context, and one additional operator. This is the xor (as
in exclusive or) operator, and is denoted as ^ (caret).

Here are all of them:

 & (ampersand) - bitwise conjunction;


 | (bar) - bitwise disjunction;
 ~ (tilde) - bitwise negation;
 ^ (caret) - bitwise exclusive or (xor).
 &(和号)- 按位与(Bitwise AND):
o 这个运算符接受两个数字作为操作数,并对两个数字的每一位进行与(AND)操作。只有两个位都为 1 时,结果位才为 1,否则为 0。
 |(竖线)- 按位或(Bitwise OR):
o 这个运算符也是接受两个数字作为操作数,并对两个数字的每一位进行或(OR)操作。只要两个位中有一个为 1,结果位就为 1。如果两个位都是 0,结果位也为 0。
 ~(波浪号)- 按位取反(Bitwise NOT):
o 这个运算符接受一个数字作为操作数,并对该数字的每一位进行取反操作。即 1 变为 0,0 变为 1。在 Python 中,由于整数是用补码来表示的,所以按位取反操作会得到操作数的补码表示的负值(具体表
现为取反后的值加 1 再取负)。
 ^(脱字符号)- 按位异或(Bitwise XOR):
o 这个运算符接受两个数字作为操作数,并对两个数字的每一位进行异或(XOR)操作。当两个位相异(一个为 1,另一个为 0)时,结果位为 1。如果两个位相同,结果位为 0。

Bitwise operations ( & , | , and ^ )


Argument A Argument B A & B A | B A ^ B
0 0 0 0 0
0 1 0 1 1
1 0 0 1 1
1 1 1 1 0

Bitwise operations (~)


Argument ~ Argument
0 1
1 0
Let's make it easier:

 & requires exactly two 1 s to provide 1 as the result;


 | requires at least one 1 to provide 1 as the result;
 ^ requires exactly one 1 to provide 1 as the result.

Let us add an important remark: the arguments of these operators must be integers; we must not use floats here.

The difference in the operation of the logical and bit operators is important: the logical operators do not penetrate into the
bit level of its argument. They're only interested in the final integer value.

Bitwise operators are stricter: they deal with every bit separately. If we assume that the integer variable occupies 64 bits (which
is common in modern computer systems), you can imagine the bitwise operation as a 64-fold evaluation of the logical operator for
each pair of bits of the arguments. This analogy is obviously imperfect, as in the real world all these 64 operations are performed at
the same time (simultaneously).

Logical vs. bit operations: continued

We'll now show you an example of the difference in operation between the logical and bit operations. Let's assume that the
following assignments have been performed:
i = 15
j = 22

If we assume that the integers are stored with 32 bits, the bitwise image of the two variables will be as follows:

i: 00000000000000000000000000001111
j: 00000000000000000000000000010110
The assignment is given:
log = i and j

We are dealing with a logical conjunction here. Let's trace the course of the calculations. Both variables i and j are not zeros, so
will be deemed to represent True . Consulting the truth table for the and operator, we can see that the result will be True . No other
operations are performed.

log: True
Now the bitwise operation - here it is:
bit = i & j

The & operator will operate with each pair of corresponding bits separately, producing the values of the relevant bits of the result.
Therefore, the result will be as follows:

i 00000000000000000000000000001111
j 00000000000000000000000000010110
bit = i & j 00000000000000000000000000000110
These bits correspond to the integer value of six.

Let's look at the negation operators now. First the logical one:

logneg = not i

The logneg variable will be set to False - nothing more needs to be done.

The bitwise negation goes like this:

bitneg = ~i

It may be a bit surprising: the bitneg variable value is -16 . This may seem strange, but isn't at all. If you wish to learn more, you
should check out the binary numeral system and the rules governing two's complement numbers.

i 00000000000000000000000000001111
bitneg = ~i 11111111111111111111111111110000

Each of these two-argument operators can be used in abbreviated form. These are the examples of their equivalent notations:
x = x & y x &= y
x = x | y x |= y
x = x ^ y x ^= y

You can also make a sequence of instructions depending on the state of your bit i here it is:

if flag_register & the_mask:


# My bit is set.
else:
# My bit is reset.

2. Reset your bit - you assign a zero to the bit while all the other bits must remain unchanged; let's use the same property of the
conjunction as before, but let's use a slightly different mask - exactly as below:

11111111111111111111111111110111

Note that the mask was created as a result of the negation of all the bits of the_mask variable. Resetting the bit is simple, and looks
like this (choose the one you like more):

flag_register = flag_register & ~the_mask


flag_register &= ~the_mask
3. Set your bit - you assign a 1 to your bit, while all the remaining bits must remain unchanged; use the following disjunction
property:

x | 1 = 1
x | 0 = x

You're now ready to set your bit with one of the following instructions:

flag_register = flag_register | the_mask


flag_register |= the_mask

4. Negate your bit - you replace a 1 with a 0 and a 0 with a 1 . You can use an interesting property of the xor operator:

x ^ 1 = ~x
x ^ 0 = x

and negate your bit with the following instructions:

flag_register = flag_register ^ the_mask


flag_register ^= the_mask

Binary left shift and binary right shift


Python offers yet another operation relating to single bits: shifting. This is applied only to integer values, and you mustn't use
floats as arguments for it.

You already apply this operation very often and quite unconsciously. How do you multiply any number by ten? Take a look:

12345 × 10 = 123450

As you can see, multiplying by ten is in fact a shift of all the digits to the left and filling the resulting gap with zero.

Division by ten? Take a look:

12340 ÷ 10 = 1234

Dividing by ten is nothing but shifting the digits to the right.

The same kind of operation is performed by the computer, but with one difference: as two is the base for binary numbers (not
10), shifting a value one bit to the left thus corresponds to multiplying it by two; respectively, shifting one bit to the
right is like dividing by two (notice that the rightmost bit is lost).

The shift operators in Python are a pair of digraphs: << and >> , clearly suggesting in which direction the shift will act.

value << bits


value >> bits
The left argument of these operators is an integer value whose bits are shifted. The right argument determines the
size of the shift.

It shows that this operation is certainly not commutative.

The priority of these operators is very high. You'll see them in the updated table of priorities, which we'll show you at the end of this
section.

Take a look at the shifts in the editor window.

The final print() invocation produces the following output:

17 68 8

Note:

 17 >> 1 → 17 // 2 (17 floor-divided by 2 to the power of 1) → 8 (shifting to the right by one bit is the same as integer
division by two)
 17 << 2 → 17 * 4 (17 multiplied by 2 to the power of 2) → 68 (shifting to the left by two bits is the same as integer
multiplication by four)

假设 var = 17,其二进制表示为 10001。


当我们执行 var >> 1 时,二进制位向右移动一位,变成了 1000,这等于十进制中的 8。
当我们执行 var << 2 时,二进制位向左移动两位,变成了 1000100,这等于十进制中的 68。
And here is the updated priority table, containing all the operators introduced so far:

Priority Operator
1 ~, +, - unary
2 **

3 * , / , // , %

4 +, - binary
5 << , >>

6 < , <= , > , >=

7 == , !=

8 &

9 |

10 = , += , -= , *= , /= , %= , &= , ^= , |= , >>= , <<=

Key takeaways

1. Python supports the following logical operators:

 and → if both operands are true, the condition is true, e.g., (True and True) is True ,
 or → if any of the operands are true, the condition is true, e.g., (True or False) is True ,
 not → returns false if the result is true, and returns true if the result is false, e.g., not True is False .

2. You can use bitwise operators to manipulate single bits of data. The following sample data:

 x = 15 , which is 0000 1111 in binary,


 y = 16 , which is 0001 0000 in binary.

will be used to illustrate the meaning of bitwise operators in Python. Analyze the examples below:

 & does a bitwise and, e.g., x & y = 0 , which is 0000 0000 in binary,
 | does a bitwise or, e.g., x | y = 31 , which is 0001 1111 in binary,
 ˜ does a bitwise not, e.g., ˜ x = 240 *, which is 1111 0000 in binary,
 ^ does a bitwise xor, e.g., x ^ y = 31 , which is 0001 1111 in binary,
 >> does a bitwise right shift, e.g., y >> 1 = 8 , which is 0000 1000 in binary,
 << does a bitwise left shift, e.g., y << 3 = , which is 1000 0000 in binary,

* -16 (decimal from signed 2's complement) -- read more about the Two's complement operation.

Why do we need lists?


It may happen that you have to read, store, process, and finally, print dozens, maybe hundreds, perhaps even thousands of
numbers. What then? Do you need to create a separate variable for each value? Will you have to spend long hours writing
statements like the one below?

var1 = int(input())
var2 = int(input())
var3 = int(input())
var4 = int(input())
var5 = int(input())
var6 = int(input())
:
:

If you don't think that this is a complicated task, then take a piece of paper and write a program that:

 reads five numbers,


 prints them in order from the smallest to the largest (NB, this kind of processing is called sorting).

You should find that you don't even have enough paper to complete the task.

So far, you've learned how to declare variables that are able to store exactly one given value at a time. Such variables are
sometimes called scalars by analogy with mathematics. All the variables you've used so far are actually scalars.
Think of how convenient it would be to declare a variable that could store more than one value. For example, a hundred, or a
thousand or even ten thousand. It would still be one and the same variable, but very wide and capacious. Sounds appealing?
Perhaps, but how would it handle such a container full of different values? How would it choose just the one you need?

在编程中,标量(scalar)变量是指可以存储单个值的变量。这个概念与数学中的标量类似,数学中的标量是指只有大小没有方向的量,比如一个单独的数字。在编程语言中,标量可以是整数、浮点数、字符或布尔值等。

例如,在 Python 中,你可以声明以下标量变量:

python
複製
integer_scalar = 10 # 整数标量
float_scalar = 3.14 # 浮点数标量
char_scalar = 'A' # 字符标量 (在 Python 中实际上是一个长度为 1 的字符串)
boolean_scalar = True # 布尔标量
每个变量都可以存储一个数据值。如果你需要存储多个值,你就会使用复合数据类型,如列表、元组、集合或字典。标量与复合数据类型的区别在于,复合数据类型可以存储多个值(它们可以包含标量或其他复合类型),而标量变量只能存储一个单一
的值。

What if you could just number them? And then say: give me the value number 2; assign the value number 15; increase the value
number 10000.
We'll show you how to declare such multi-value variables. We'll do this with the example we just suggested. We'll write
a program that sorts a sequence of numbers. We won't be particularly ambitious - we'll assume that there are exactly five
numbers.

Let's create a variable called numbers ; it's assigned with not just one number, but is filled with a list consisting of five values (note:
the list starts with an open square bracket and ends with a closed square bracket; the space between the brackets is
filled with five numbers separated by commas).

numbers = [10, 5, 7, 2, 1]

Let's say the same thing using adequate terminology: numbers is a list consisting of five values, all of them numbers. We can
also say that this statement creates a list of length equal to five (as in there are five elements inside it).

The elements inside a list may have different types. Some of them may be integers, others floats, and yet others may be lists.

Python has adopted a convention stating that the elements in a list are always numbered starting from zero. This means that
the item stored at the beginning of the list will have the number zero. Since there are five elements in our list, the last of them is
assigned the number four. Don't forget this.

You'll soon get used to it, and it'll become second nature.

Before we go any further in our discussion, we have to state the following: our list is a collection of elements, but each
element is a scalar.
Indexing lists

How do you change the value of a chosen element in the list?

Let's assign a new value of 111 to the first element in the list. We do it this way:

numbers = [10, 5, 7, 2, 1]
print("Original list content:", numbers) # Printing original list content.

numbers[0] = 111
print("New list content: ", numbers) # Current list content.

And now we want the value of the fifth element to be copied to the second element - can you guess how to do it?

numbers = [10, 5, 7, 2, 1]
print("Original list content:", numbers) # Printing original list content.

numbers[0] = 111
print("\nPrevious list content:", numbers) # Printing previous list content.

numbers[1] = numbers[4] # Copying value of the fifth element to the second.


print("New list content:", numbers) # Printing current list content.

The value inside the brackets which selects one element of the list is called an index, while the operation of selecting an element
from the list is known as indexing.

We're going to use the print() function to print the list content each time we make the changes. This will help us follow each step
more carefully and see what's going on after a particular list modification.

Note: all the indices used so far are literals. Their values are fixed at runtime, but any expression can be the index, too. This
opens up lots of possibilities.

Accessing list content

Each of the list's elements may be accessed separately. For example, it can be printed:

print(numbers[0]) # Accessing the list's first element.

Assuming that all of the previous operations have been completed successfully, the snippet will send 111 to the console.

As you can see in the editor, the list may also be printed as a whole - just like here:
print(numbers) # Printing the whole list.

As you've probably noticed before, Python decorates the output in a way that suggests that all the presented values form a list. The
output from the example snippet above looks like this:

[111, 1, 7, 2, 1]

The len() function

The length of a list may vary during execution. New elements may be added to the list, while others may be removed from it.
This means that the list is a very dynamic entity.

If you want to check the list's current length, you can use a function named len() (its name comes from length).

The function takes the list's name as an argument, and returns the number of elements currently stored inside the list (in
other words - the list's length).

Look at the last line of code in the editor, run the program and check what value it will print to the console. Can you guess?

Removing elements from a list


Any of the list's elements may be removed at any time - this is done with an instruction named del (delete). Note: it's
an instruction, not a function.

You have to point to the element to be removed - it'll vanish from the list, and the list's length will be reduced by one.

Look at the snippet below. Can you guess what output it will produce? Run the program in the editor and check.

del numbers[1]
print(len(numbers))
print(numbers)

You can't access an element which doesn't exist - you can neither get its value nor assign it a value. Both of these
instructions will cause runtime errors now:

print(numbers[4])
numbers[4] = 1

Add the snippet above after the last line of code in the editor, run the program and check what happens.

Note: we've removed one of the list's elements - there are only four elements in the list now. This means that element number four
doesn't exist.

Negative indices are legal


It may look strange, but negative indices are legal, and can be very useful.

An element with an index equal to -1 is the last one in the list.

print(numbers[-1])

The example snippet will output 1 . Run the program and check.

Similarly, the element with an index equal to -2 is the one before last in the list.

print(numbers[-2])

The example snippet will output 2 .

The last accessible element in our list is numbers[-4] (the first one) - don't try to go any further!

Functions vs. methods

A method is a specific kind of function - it behaves like a function and looks like a function, but differs in the way in which it
acts, and in its invocation style.

A function doesn't belong to any data - it gets data, it may create new data and it (generally) produces a result.

A method does all these things, but is also able to change the state of a selected entity.
A method is owned by the data it works for, while a function is owned by the whole code.

This also means that invoking a method requires some specification of the data from which the method is invoked.

It may sound puzzling here, but we'll deal with it in depth when we delve into object-oriented programming.

In general, a typical function invocation may look like this:

result = function(arg)

The function takes an argument, does something, and returns a result.

You might also like