《Python Quick start ( The first 3 edition )》 Naomi · Sead
15.4 Class variables
Class variables (class variable) Is a variable associated with a class , And can be accessed by all instances of the class .
Class variables are created by assignment statements in the class definition code , Not in __init__ Function .
【 example 】 You can use class variables to create pi value , for Circle Access to all instances of class
circle.py
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
def area(self):
return self.radius * self.radius * Circle.pi
Interactive environment test :
>>> from circle import Circle
>>> Circle.pi
3.14159
>>>
In order to avoid writing the class name dead , have access to __class__ attribute , This property will return the class to which the instance belongs , Available Python Access to all instances of class . for example :
>>> c = Circle(3)
>>> c.__class__
<class 'circle.Circle'>
>>> Circle
<class 'circle.Circle'>
>>>
>>> c.__class__.pi
3.14159
>>>
The uniqueness of class variables
Python When looking for instance variables , If an instance variable with that name cannot be found , It will find and return the class variable value in the class variable with the same name . Only when a suitable class variable cannot be found ,Python That's what makes a mistake .
>>> c1 = Circle(1)
>>> c2 = Circle(2)
>>> c1.pi
3.14159
>>> c1.pi = 3.14
>>> c1.pi
3.14
>>> c2.pi
3.14159
>>> Circle.pi
3.14159
>>>
explain : The above example c1 Have your own pi copy , And c2 Access to the Circle.pi Is not the same . Because of c1.pi The value of is in c1 An instance variable is created in (Python The data fields of class instances do not need to be declared in advance , You can create it at run time ), It does not apply to class variables Circle.pi Any impact . Follow up on c1.pi The value of this instance variable will be returned when searching . And yes c2.pi The search of will be in c2 Find instance variables in pi, But I didn't find it , Then it will return the class variable Circle.pi Value . If you need to change the value of a class variable , Please access by class name , Not through instance variables self.
15.5 Static methods and class methods
15.5.1 Static methods
Please use @staticmethod Decorator to create static methods
to update circle.py The content of
"""circle module: contains the Circle class."""
class Circle:
"""Circle class"""
all_circles = [] # This type of variable contains a list of all instances created
pi = 3.14159
def __init__(self, r=1):
"""Create a Circle with the given radius"""
self.radius = r
self.__class__.all_circles.append(self) # If the instance has been initialized , Just add yourself to all_circles list
def area(self):
"""determine the area of the Circle"""
return self.__class__.pi * self.radius * self.radius
@staticmethod
def total_area():
"""Static method to total the areas of all Circles"""
total = 0
for c in Circle.all_circles:
total = total + c.area()
return total
Then test in interactive mode :
>>> import circle
>>> c1 = circle.Circle(1)
>>> c2 = circle.Circle(2)
>>> circle.Circle.total_area()
15.70795
>>> c2.radius = 3
>>> circle.Circle.total_area()
31.415899999999997
>>> c2.radius = 3
>>> circle.Circle.total_area()
31.415899999999997
>>> c2.radius = 4
>>> circle.Circle.total_area()
53.40703
>>>
>>> Circle.all_circles
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'Circle' is not defined
>>> circle.Circle.all_circles
[<circle.Circle object at 0x7ff68ce4dcd0>, <circle.Circle object at 0x7ff68cefd7f0>]
>>>
>>> c2.radius = 2
>>> circle.Circle.total_area()
15.70795
>>>
The above example also uses the document string , Give the available methods in the document string of the class , Include usage information in the document string of the method .
>>> circle.__doc__
'circle module: contains the Circle class.'
>>> circle.Circle.__doc__
'Circle class'
>>> circle.Circle.area.__doc__
'determine the area of the Circle'
>>> circle.Circle.total_area.__doc__
'Static method to total the areas of all Circles'
>>>
stay Python Interactive console ,help(circle) Command to view help information .
15.5.2 Class method
Class methods are very similar to static methods , Can be called before the object of the class is instantiated , Can also be called through an instance of a class . But class methods implicitly pass the class as the first parameter .
here def A decorator is added in front of the method @classmethod. Class as parameter , It is conventionally named cls. And then It can be used cls Instead of self.__class__.
circle_cm.py
"""circle_cm module: contains the Circle class."""
class Circle:
"""Circle class"""
all_circles = [] # This type of variable contains a list of all instances created
pi = 3.14159
def __init__(self, r=1):
"""Create a Circle with the given radius"""
self.radius = r
self.__class__.all_circles.append(self) # If the instance has been initialized , Just add yourself to all_circles list
def area(self):
"""determine the area of the Circle"""
return self.__class__.pi * self.radius * self.radius
@classmethod
def total_area(cls):
"""Static method to total the areas of all Circles"""
total = 0
for c in cls.all_circles:
total = total + c.area()
return total
Then test in interactive mode :
>>> c1 = circle_cm.Circle(1)
>>> c2 = circle_cm.Circle(2)
>>> circle_cm.Circle.total_area()
15.70795
>>> c2.radius = 3
>>> circle_cm.Circle.total_area()
31.415899999999997
>>>
Use class methods instead of static methods , You don't have to hard code the class name total_area. such ,Circle All subclasses of can still call total_area, But it refers to its own members, not Circle Members of .
15.10 use @property Get more flexible instance variables
Python Allow programmers to access instance variables directly , There is no need to adopt the method getter and setter This extra mechanism
Attributes can be passed through similar getter and setter Indirect access to instance variables , It can also use the period representation of direct access to instance variables .
Add... To the method property Ornament , You can create attributes , The name of the method is the property name :
temperature.py
class Temperature:
def __init__(self):
self._temp_fahr = 0
@property
def temp(self):
return (self._temp_fahr -32) * 5 / 9
@temp.setter # No setter When the method is used , Properties are read-only
def temp(self, new_temp):
self._temp_fahr = new_temp * 9 / 5 + 32
@temp.deleter
def temp(self):
del self._temp_fahr
(1) test get
>>> import temperature
>>>
>>> t = temperature.Temperature()
>>> t.temp
-17.77777777777778
>>>
>>> t.temp()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'float' object is not callable
>>>
(2) test set
>>> t.temp = 34
>>> t2._temp_fahr
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 't2' is not defined
>>> t._temp_fahr
93.2
>>> t.temp
34.0
>>>
>>> t.temp(36)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'float' object is not callable
>>>
_temp_fahr Deposited 0 Before being returned , Will be converted to Celsius .34 It will be setter Switch back to Fahrenheit .
Python Added support for attributes , Bring a great benefit , That is, traditional instance variables can be used during initial development , In the future, you can seamlessly switch to attributes anytime, anywhere as needed , The client code does not need to be changed at all . The way of access remains the same , It's still a period expression .
(3) Test to delete _temp_fahr
>>> dir(t)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_temp_fahr', 'temp']
>>>
>>>
>>> del t.temp
>>>
>>> dir(t)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'temp']
>>>
>>> t.temp
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/root/Pictures/temperature.py", line 6, in temp
return (self._temp_fahr -32) * 5 / 9
AttributeError: 'Temperature' object has no attribute '_temp_fahr'
>>>
perform del t.temp after ,dir(t) You can see _temp_fahr period
summary :
When an instantiated object uses properties , Not calling properties , Instead, call the method name
When defining methods @property Must be in @xxx.setter Before , And the names of the two modified methods are the same -> temp()
@property Realization getter function
@xxx.setter Realization setter function
@xxx.deleter Realize the deletion function
Only achieve @property Indicates read-only
At the same time to realize @property and @x.setter Represent readable and writable
At the same time to realize @property,@x.setter and @x.deleter Indicates readable, writable and erasable
The first 16 Chapter Regular expressions
16.1 What is a regular expression
【 example 】 Next, we will use regular expressions to calculate the words contained in the text file hello The number of rows . Even if there are multiple hello, It will only be calculated once :
import re
regexp = re.compile("hello")
count = 0
file = open("textfile", 'r')
for line in file.readlines():
if regexp.search(line):
count = count + 1
file.close()
print(count)
The above program first imports Python Regular expression module re.
Then string the text "hello" As a literal regular expression , And use re.compile Function to compile it .
Identification will be done by search Method to accomplish , If the regular expression is not found in the parameter string , Then return to None.Python In Boolean context None Interpreted as false. If the regular expression is found in the string ,Python Will return a special object , It can be used to determine a variety of information related to this match , for example , Where in the string .
textfile The contents are as follows , The execution result is 1
Hello
123helloh
Wednesday
July Aug
nihao
16.3 Regular expressions and raw strings
【 example 】 Suppose you want to find a string in text "\ten" Where is it . Because I know that I have to express the backslash as double backslash , So it may be written in the following format :
regexp = re.compile("\\ten")
The above code can be compiled smoothly , But there are mistakes .
\\ stay Python The string represents a backslash . Calling re.compile Before ,Python This string will be interpreted as \ten, This is also passed to re.compile The content of . In the context of regular expressions ,\t Represents a tab , Therefore, the compiled regular expression will search for tabs plus two characters "en".
Write it correctly
(1)regexp = re.compile("\\\\ten")
(2) Or use the original string ( Precede the first quotation mark of the string r character )
regexp = re.compile(r"\\ten")
Be careful : In regular expressions , comma 、 Colons and spaces have no special meaning , Only represents the character itself .
16.4 Extract the matching text from the string
【 example 】 Suppose a text file contains a list of people and phone numbers , The format of each line is as follows ( Middle name 、 The telephone area code may not exist )
firstname middlename, surname: phonenumber
Extract data from the schema
The first step is to use special characters (), Group the sub patterns corresponding to the data to be extracted . Then use a special character sequence ?P <name> Give each sub schema a unique name , As shown below :
(?P<first>[-a-zA-Z]+)( (?P<middle>([-a-zA-Z]+)))?, (?P<last>[-a-zA-Z]+): (?P<phone>(\d{3}-)?\d{3}-\d{4}
Be careful , The above code should be entered in one line , No line breaks .
peopleinfo.py
import re
regexp = re.compile(r"(?P<first>[-a-zA-Z]+)"
r"( (?P<middle>([-a-zA-Z]+)))?"
r", (?P<last>[-a-zA-Z]+)"
r": (?P<phone>(\d{3}-)?\d{3}-\d{4})"
)
file = open("infofile",'r')
for line in file.readlines():
result = regexp.search(line)
if result == None:
print("Oops, I don't think this is a record")
else:
lastname = result.group('last')
firstname = result.group('first')
middlename = result.group('middle')
if middlename == None:
middlename = ""
phonenumber = result.group('phone')
print('Name:', firstname, middlename, lastname, '| Number:', phonenumber)
file.close()
infofile( Of course, the phone number is made casually Please ignore doge)
Harry, Potter: 222-333-4444
Ron, Weasley: 222-333-4449
Hermione, Granger: 666-4449
Albus, Dumbledore: 776-1234
Severus, Snape: 007-776-1234
Dobby,hahaha
Albus Severus, Potter: 233-776-6688
perform peopleinfo.py Output after
Name: Harry Potter | Number: 222-333-4444
Name: Ron Weasley | Number: 222-333-4449
Name: Hermione Granger | Number: 666-4449
Name: Albus Dumbledore | Number: 776-1234
Name: Severus Snape | Number: 007-776-1234
Oops, I don't think this is a record
Name: Severus Snape | Number: 007-776-1234
Name: Albus Severus Potter | Number: 233-776-6688
16.5 Replace text with regular expressions
Method sub You can find strings in text and replace them in place with other strings .
【 example 】 Use one "the" Replace "the the"
>>> import re
>>> string = "If the the problem is textual, use the the re module"
>>> pattern = r"the the"
>>> regexp = re.compile(pattern)
>>> regexp.sub("the", string)
'If the problem is textual, use the re module'
>>> string
'If the the problem is textual, use the the re module'
>>>
explain :sub Method will call the regular expression ( In this case regexp) To scan its second parameter ( In this case string), Replace all matching substrings with the first parameter value ( In this case "the") And generate a new string .
【 example 】 Replace the matching substring with a new substring that has a certain relationship with the matching value
>>> import re
>>> int_string = "1 2 3 4 5"
>>> def int_match_to_float(match_obj):
... return(match_obj.group('num') + ".0")
...
>>> pattern = r"(?P<num>[0-9]+)"
>>> regexp = re.compile(pattern)
>>> regexp.sub(int_match_to_float, int_string)
'1.0 2.0 3.0 4.0 5.0'
>>> int_string
'1 2 3 4 5'
>>>
explain :sub The first parameter of the method , That is, the substring used for replacement , It doesn't have to be a string , It can also be a function . If sub The first parameter of the method is a function ,Python This function will be called on the current matching object , Then perform the function calculation and return a string for replacement .