30-Days-Of-Python/Chinese/21_classes_and_objects_cn.md

419 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 30天Python编程挑战第21天 - 类和对象
- [第21天](#-第21天)
- [类和对象](#类和对象)
- [创建类](#创建类)
- [创建对象](#创建对象)
- [类构造函数](#类构造函数)
- [对象方法](#对象方法)
- [对象默认方法](#对象默认方法)
- [修改类默认值的方法](#修改类默认值的方法)
- [继承](#继承)
- [覆盖父类方法](#覆盖父类方法)
- [💻 练习第21天](#-练习第21天)
- [练习级别1](#练习级别1)
- [练习级别2](#练习级别2)
- [练习级别3](#练习级别3)
# 📘 第21天
## 类和对象
Python是一种面向对象的编程语言。在Python中一切都是对象都有其属性和方法。在程序中使用的数字、字符串、列表、字典、元组、集合等都是相应内置类的对象。我们创建类来创建对象。类就像一个对象构造器或者说是创建对象的"蓝图"。我们实例化一个类来创建一个对象。类定义了对象的属性和行为,而对象则代表了类。
从这个挑战的开始我们就一直在不知不觉地使用类和对象。Python程序中的每个元素都是某个类的对象。
让我们检查一下Python中的一切是否都是类
```py
asabeneh@Asabeneh:~$ python
Python 3.9.6 (default, Jun 28 2021, 15:26:21)
[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> num = 10
>>> type(num)
<class 'int'>
>>> string = 'string'
>>> type(string)
<class 'str'>
>>> boolean = True
>>> type(boolean)
<class 'bool'>
>>> lst = []
>>> type(lst)
<class 'list'>
>>> tpl = ()
>>> type(tpl)
<class 'tuple'>
>>> set1 = set()
>>> type(set1)
<class 'set'>
>>> dct = {}
>>> type(dct)
<class 'dict'>
```
### 创建类
要创建一个类,我们需要关键字**class**,后跟类名和冒号。类名应该使用**驼峰命名法CamelCase**。
```sh
# 语法
class 类名:
代码放在这里
```
**示例:**
```py
class Person:
pass
print(Person)
```
```sh
<__main__.Person object at 0x10804e510>
```
### 创建对象
我们可以通过调用类来创建对象。
```py
p = Person()
print(p)
```
### 类构造函数
在上面的例子中我们已经从Person类创建了一个对象。然而没有构造函数的类在实际应用中并不真正有用。让我们使用构造函数使我们的类更有用。与Java或JavaScript中的构造函数一样Python也有一个内置的**__init__**()构造函数。**__init__**构造函数有一个self参数它是当前类实例的引用。
**示例:**
```py
class Person:
def __init__ (self, name):
# self允许将参数附加到类
self.name = name
p = Person('Asabeneh')
print(p.name)
print(p)
```
```sh
# 输出
Asabeneh
<__main__.Person object at 0x2abf46907e80>
```
让我们向构造函数添加更多参数。
```py
class Person:
def __init__(self, firstname, lastname, age, country, city):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.country = country
self.city = city
p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
print(p.firstname)
print(p.lastname)
print(p.age)
print(p.country)
print(p.city)
```
```sh
# 输出
Asabeneh
Yetayeh
250
Finland
Helsinki
```
### 对象方法
对象可以有方法。方法是属于对象的函数。
**示例:**
```py
class Person:
def __init__(self, firstname, lastname, age, country, city):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.country = country
self.city = city
def person_info(self):
return f'{self.firstname} {self.lastname}今年{self.age}岁。他住在{self.country}{self.city}。'
p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
print(p.person_info())
```
```sh
# 输出
Asabeneh Yetayeh今年250岁。他住在Finland的Helsinki。
```
### 对象默认方法
有时,你可能希望为对象方法提供默认值。如果我们为构造函数中的参数提供默认值,可以避免在不带参数调用或实例化类时出现错误。让我们看看这是什么样子:
**示例:**
```py
class Person:
def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.country = country
self.city = city
def person_info(self):
return f'{self.firstname} {self.lastname}今年{self.age}岁。他住在{self.country}{self.city}。'
p1 = Person()
print(p1.person_info())
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
print(p2.person_info())
```
```sh
# 输出
Asabeneh Yetayeh今年250岁。他住在Finland的Helsinki。
John Doe今年30岁。他住在Nomanland的Noman city。
```
### 修改类默认值的方法
在下面的例子中person类的所有构造函数参数都有默认值。此外我们还有一个skills参数可以通过方法访问。让我们创建一个add_skill方法向skills列表添加技能。
```py
class Person:
def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
self.firstname = firstname
self.lastname = lastname
self.age = age
self.country = country
self.city = city
self.skills = []
def person_info(self):
return f'{self.firstname} {self.lastname}今年{self.age}岁。他住在{self.country}{self.city}。'
def add_skill(self, skill):
self.skills.append(skill)
p1 = Person()
print(p1.person_info())
p1.add_skill('HTML')
p1.add_skill('CSS')
p1.add_skill('JavaScript')
p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
print(p2.person_info())
print(p1.skills)
print(p2.skills)
```
```sh
# 输出
Asabeneh Yetayeh今年250岁。他住在Finland的Helsinki。
John Doe今年30岁。他住在Nomanland的Noman city。
['HTML', 'CSS', 'JavaScript']
[]
```
### 继承
继承允许我们定义一个继承父类所有功能的类。它使代码可重用。
```py
# 语法
class 子类名(父类名):
代码放在这里
```
让我们通过实际例子来看看继承的含义:
```py
class Student(Person):
pass
s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki')
s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo')
print(s1.person_info())
s1.add_skill('JavaScript')
s1.add_skill('React')
s1.add_skill('Python')
print(s1.skills)
print(s2.person_info())
s2.add_skill('Organizing')
s2.add_skill('Marketing')
s2.add_skill('Digital Marketing')
print(s2.skills)
```
```sh
# 输出
Eyob Yetayeh今年30岁。他住在Finland的Helsinki。
['JavaScript', 'React', 'Python']
Lidiya Teklemariam今年28岁。他住在Finland的Espoo。
['Organizing', 'Marketing', 'Digital Marketing']
```
我们没有在Student类中调用任何方法但我们能够访问来自Parent类的所有方法。Student类继承了Person类的__init__构造函数和person_info方法。如果我们想要向子类添加一个特定于子类的新方法我们必须编写子类并在子类中创建新的方法。
```py
class Student(Person):
def __init__ (self, firstname='Asabeneh', lastname='Yetayeh',age=250, country='Finland', city='Helsinki', gender='male'):
self.gender = gender
super().__init__(firstname, lastname,age, country, city)
def person_info(self):
gender = '他' if self.gender =='male' else '她'
return f'{self.firstname} {self.lastname}今年{self.age}岁。{gender}住在{self.country}{self.city}。'
s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki','male')
s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo', 'female')
print(s1.person_info())
s1.add_skill('JavaScript')
s1.add_skill('React')
s1.add_skill('Python')
print(s1.skills)
print(s2.person_info())
s2.add_skill('Organizing')
s2.add_skill('Marketing')
s2.add_skill('Digital Marketing')
print(s2.skills)
```
```sh
# 输出
Eyob Yetayeh今年30岁。他住在Finland的Helsinki。
['JavaScript', 'React', 'Python']
Lidiya Teklemariam今年28岁。她住在Finland的Espoo。
['Organizing', 'Marketing', 'Digital Marketing']
```
我们可以使用super()函数或父类名Person来自动继承父类的方法和属性。在上面的例子中我们覆盖了父类方法。子类的person_info方法有不同的实现即使方法名称与父类相同。
### 覆盖父类方法
如上所示,我们可以通过创建与父类方法名称相同的子类方法来覆盖父类方法。
## 💻 练习第21天
### 练习级别1
1. Python有一个名为_statistics_的模块我们可以使用这个模块来计算统计数据。但是让我们尝试开发一个可以计算均值、中位数、众数、标准差等统计数据的类。
```py
class Statistics:
def __init__(self, data=[]):
self.data = data
def count(self):
# 你自己的实现
pass
def sum(self):
# 你自己的实现
pass
def min(self):
# 你自己的实现
pass
def max(self):
# 你自己的实现
pass
def range(self):
# 你自己的实现
pass
def mean(self):
# 你自己的实现
pass
def median(self):
# 你自己的实现
pass
def mode(self):
# 你自己的实现
pass
def standard_deviation(self):
# 你自己的实现
pass
def variance(self):
# 你自己的实现
pass
def frequency_distribution(self):
# 你自己的实现
pass
def describe(self):
# 你自己的实现
pass
```
```py
# 测试代码
data = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26]
statistics = Statistics(data)
print('Count:', statistics.count()) # 25
print('Sum: ', statistics.sum()) # 730
print('Min: ', statistics.min()) # 24
print('Max: ', statistics.max()) # 38
print('Range: ', statistics.range()) # 14
print('Mean: ', statistics.mean()) # 29.2
print('Median: ', statistics.median()) # 27
print('Mode: ', statistics.mode()) # {'mode': 26, 'count': 5}
print('Standard Deviation: ', statistics.standard_deviation()) # 4.2
print('Variance: ', statistics.variance()) # 17.5
print('Frequency Distribution: ', statistics.frequency_distribution()) # [(24, 2), (25, 1), (26, 5), (27, 4), (29, 1), (31, 2), (32, 3), (33, 2), (34, 2), (37, 2), (38, 1)]
```
### 练习级别2
1. 创建一个名为PersonAccount的类。它有firstname、lastname、incomes、expenses属性和添加收入、添加支出以及账户余额方法。
### 练习级别3
1. 以下是使用函数的方法。让我们将其转换为类
```python
def print_products(*args, **kwargs):
for product in args:
print(product)
print(kwargs)
for key in kwargs:
print(f"{key}: {kwargs[key]}")
print_products("apple", "banana", "orange", vegetable="tomato", juice="orange")
```
```sh
apple
banana
orange
{'vegetable': 'tomato', 'juice': 'orange'}
vegetable: tomato
juice: orange
```
1. 在一个名为PersonAccount的类中我们有属性firstname、lastname、incomes、expenses。设计一个类用于计算一个人的净收入。
🎉 恭喜!🎉
[<< 第 20 天](./20_python_package_manager_cn.md) | [第 22 天 >>](./22_web_scraping_cn.md)