每天30分钟学python
每天10分钟的Python速成课程 (10 minutes a day Python crash course)
This is a series of short 10 minute Python articles helping you to boost your knowledge of Python. I try to post an article each day (no promises), starting from the very basics, going up to more complex idioms. Feel free to contact me on LinkedIn for questions or requests on particular subjects of Python you want to know about.
这是一系列简短的10分钟Python文章,可帮助您增强Python知识。 我尝试每天发布一篇文章(不做任何保证),从最基础的内容开始,再到更复杂的习惯用法。 如果您想了解有关Python特定主题的问题或要求,请随时通过LinkedIn与我联系。
When getting a bit more into programming, one will come across two big paradigms: functional programming and object-oriented programming (OOP). Until now, what we mostly did is called functional programming. I have not yet found a satisfying all-round definition for both terms. However, the key difference is that functional programming, as the name suggests, centers around functions and the program structure is like a step-by-step recipe, while OOP centers around the data, which is structured in objects. It is mostly a different way of approaching a problem. There is no real good or bad between the two paradigms as there is in a preference for tennis over soccer. Sometimes, one approach seems easier for a problem, but I am convinced that you could achieve the same results with both methods. Both, OOP and the functional approach are compatible with Python.
当对编程有更多了解时,将遇到两个主要范例:函数式编程和面向对象的编程(OOP)。 到现在为止,我们最常做的事情就是函数编程。 对于这两个术语,我尚未找到令人满意的全面定义。 但是,关键区别在于,顾名思义,函数式编程以函数为中心,程序结构就像循序渐进的配方,而OOP则以对象中结构化的数据为中心。 这主要是解决问题的另一种方式。 两种范例之间并没有真正的利弊之分,因为网球比足球更偏向网球。 有时候,一种方法似乎更容易解决问题,但是我坚信,使用这两种方法都可以达到相同的结果。 OOP和功能方法都与Python兼容。
The core idea of OOP is the abstraction of the program into objects. An object is a structure that combines the data and the code relevant to that particular piece of data. Evangelist of OOP claim that this reduces the amount of repetition and makes the code more readable. I must admit, that the idea is pretty neat and does definitely have some benefits. As a nice starter example, lets create an object for an animal and see how OOP works in Python.
OOP的核心思想是将程序抽象为对象。 对象是将数据和与该特定数据段相关的代码组合在一起的结构。 OOP的传播者声称,这减少了重复次数,并使代码更具可读性。 我必须承认,这个想法很巧妙,而且确实有一些好处。 作为一个很好的入门示例,让我们为动物创建一个对象,看看OOP如何在Python中工作。
class Animal:
"""
Our animal class
"""
def __init__(self, name, height):
self.name = name
self.height = height
def description(self):
print(f'Hi, I am a {self.name}.')
if self.height < 1:
print('I am quite tiny!')
elif self.height < 2:
print('I am a similar size than you!')
else:
print('I am pretty huge!')
animal1 = Animal('Frog', 0.1)
animal2 = Animal('Rhinoceros', 4)
animal1.description()
animal2.description()
This structure does not look that difficult, but there are some new concepts. To start a class definition, you start with the class keyword, followed by a name. As a convention, class names start capitalized, but from a Python perspective, any name would be fine (but capitalize it anyway please). Similar to a function definition, we have a semicolon and all code that is indented belongs to the definition. It is good practice to provide a DocString to describe the class. In the definition itself, we can now create variables and methods. Methods are the names for functions that are in a class definition.
这种结构看起来并不难,但是有一些新概念。 要开始类定义,请从class关键字开始,后跟一个名称。 按照惯例,类名开始使用大写字母,但从Python的角度来看,任何名称都可以(但请始终使用大写字母)。 类似于函数定义,我们有一个分号,并且所有缩进的代码都属于该定义。 最好提供一个DocString来描述该类。 在定义本身中,我们现在可以创建变量和方法。 方法是类定义中的函数的名称。
It is important to know the difference between the class definition and a class instance. The code we have created in the previous example starts with the class definition and creates a blueprint for our object. When we want to use that particular type of object, we need to create an instance. After the definition of our Animal class, we create two instances of that class: animal1 and animal2. While the blueprint defines which data and methods are available, it does not contain the data itself. When creating an instance of the class, we create the object that contains the actual data. In our example animal1 and animal2 are both of the type Animal but they contain different data: Frog for animal1 and Rhinoceros for animal2. You can create as many instances as you like of a previously defined class.
了解类定义和类实例之间的区别很重要。 我们在上一个示例中创建的代码从类定义开始,并为我们的对象创建一个蓝图。 当我们要使用特定类型的对象时,我们需要创建一个实例。 在定义Animal类之后,我们创建该类的两个实例: animal1和animal2 。 尽管该蓝图定义了可用的数据和方法,但它并不包含数据本身。 在创建类的实例时,我们将创建包含实际数据的对象。 在我们的示例中, animal1和animal2都是Animal类型,但是它们包含不同的数据:Frog表示animal1 ,Rhinoceros表示animal2 。 您可以根据需要创建任意数量的先前定义的类的实例。
When creating an instance of a class, we call one of Python’s special methods: a constructor. We can see that it is special, because its name is surrounded by double-underscores. These, so called dunder-methods are given special treatment in Python. The init dunder-method indicates the constructor, a method that is called when a class instance is created. Methods can take parameters just like regular functions however, classes have one mandatory first parameter: self. Any class method in Python requires this parameter and the reason is that this particular object caries the data of the instance. When we define a class in Python, we have a reference to that class. This definition is the same for every object. To have each instance hold their own set of data such that we have a Frog and a Rhinoceros, each class has the self object, which holds the actual data. In the constructor, we define the created variables and add the data to this self object. This object is shared between the instance, but not between different instances. Now, we can use that instance data in the other methods we define in the class, such as in the description() method. This is the solution the Python developers came up with for having data at the instance level. While you can define variables at class level (something other programming languages do), this can result in unwanted results:
创建类的实例时,我们调用Python的一种特殊方法:构造函数。 我们可以看到它很特殊,因为它的名称被双下划线包围。 这些所谓的dunder方法在Python中得到了特殊处理。 初始化dunder方法指示构造函数,该方法在创建类实例时调用。 方法可以像常规函数一样接受参数,但是类具有一个强制性的第一个参数: self 。 Python中的任何类方法都需要此参数,原因是该特定对象携带实例的数据。 当我们在Python中定义一个类时,我们会引用该类。 每个对象的定义都是相同的。 为了使每个实例拥有自己的数据集(例如,我们有青蛙和犀牛),每个类都具有self对象,该对象保存实际数据。 在构造函数中,我们定义创建的变量并将数据添加到此self对象。 该对象在实例之间共享,但在不同的实例之间不共享。 现在,我们可以在类中定义的其他方法(例如description()方法)中使用该实例数据。 这是Python开发人员想出的在实例级别获取数据的解决方案。 尽管您可以在类级别定义变量(其他编程语言也可以这样做),但这可能会导致不需要的结果:
class Library:
books = []
# Public library instance
library = Library()
library.books.append('Harry Potter')
# Another instance
home_book_shelve = Library()
home_book_shelve.books.append('Thrawn trilogy')
# Classes might share at definition level
home_book_shelve.books
This is not a bug but how Python works. The list is defined when the class is defined. Each instance gets a reference to that list and therefore, all instances share that list. This is only the case for mutable objects. immutable objects generally get a new reference when changed again, therefore, overwriting the previous reference. Just be mindful when not using the default method of defining all parameters in the constructor (which you generally should use).
这不是错误,而是Python的工作方式。 该列表是在定义类时定义的。 每个实例都有对该列表的引用,因此,所有实例都共享该列表。 这仅适用于可变对象。 不变的对象通常在再次更改时会获得新的引用,因此将覆盖先前的引用。 请注意不要在构造函数中使用默认方法定义所有参数的默认方法(通常应使用该方法)。
animal1 = Animal('Frog', 0.1)
animal2 = Animal('Rhinoceros', 4)
animal1.name, animal2.name
All variables that we add to the self object are accessible using the dot notation. Generally, all variables that are in an object are called attributes, while all functions are called methods. Both should have unique names and can be accessed using <object name>.<attribute name>
or <object name>.<method name>()
. This is the same notation as if any object in Python. Strings and integers are all objects with the same methodology. However, these classes have many more dunder-methods defined. There are special methods that take care of printing the object, if objects are add together, and if objects are multiplied. We can also define these and with those definitions make our own rules:
我们添加到self对象的所有变量都可以使用点表示法来访问。 通常,对象中的所有变量都称为属性,而所有函数均称为方法。 两者都应具有唯一的名称,并且可以使用<object name>.<attribute name>
或<object name>.<method name>()
。 这与Python中的任何对象都是相同的表示法。 字符串和整数都是使用相同方法的所有对象。 但是,这些类还定义了许多隐蔽方法 。 如果将对象加在一起以及将对象相乘,则有一些特殊的方法负责打印对象。 我们还可以定义这些,并使用这些定义制定自己的规则:
class strange_number:
def __init__(self, number):
self.number = number
def __repr__(self):
return str(self.number)
def __add__(self, other):
return self.number - other.number
number1 = strange_number(5)
number2 = strange_number(2)
print(f'{number1} + {number2} = {number1 + number2}')
The class has two more dunder-methods. The first takes care of the representation of a the class. If we would simply type the variable name representing the class instance, i.e. number1, it will call the repr dunder-method and returns it representation. This method has to return a string, but what the string is, we are free to define. The second dunder-method defines how to add two objects. It expects as a parameter, next to the mandatory self object, which is the other object. Technically, this could be any object and we have to test which type it is, before doing an addition. For now, we assume it will be of the same type. This can be any definition, even something else as we did in this example. This is very powerful as you can define objects like for example contact cards and using the add function, merge two contacts. We have seen an interesting example when we used Path from the Pathlib module. Path has the divide dunder-method defined such that it combines the path:
该类还有另外两种方法。 第一个负责类的表示。 如果我们只是简单地键入代表类实例的变量名,即number1,它将调用repr dunder方法并返回其表示形式。 该方法必须返回一个字符串,但是字符串是什么,我们可以自由定义。 第二个dunder方法定义了如何添加两个对象。 它期望在强制性自我对象(另一个对象)旁边作为参数。 从技术上讲,这可以是任何对象,在添加之前,我们必须测试它是哪种类型。 现在,我们假设它的类型相同。 这可以是任何定义,甚至可以像我们在本示例中所做的那样定义。 这非常强大,因为您可以定义诸如联系人卡片之类的对象,并使用添加功能合并两个联系人。 当我们从Pathlib模块使用Path时,我们已经看到了一个有趣的示例。 路径定义了除法方法,以便结合路径:
from pathlib import Path
cwd = Path.cwd()
print(cwd / 'README.md')
For each mathematical operation, there is a dunder-method that can be defined or overloaded. Overloading means that you overwrite an existing method, which can be a regular method or one of the dunder-methods, with a new definition. There are a couple of other dunder-methods, for example for iteration related topics. It is not required to know them by hard, but definitely nice to know about their existence.
对于每个数学运算,都有一个可以定义或重载的dunder方法 。 重载意味着您使用新定义覆盖现有方法,该方法可以是常规方法或dunder方法之一。 还有其他一些dunder方法 ,例如与迭代相关的主题。 并不需要很了解它们,但是知道它们的存在绝对是一件很高兴的事情。
今天的练习: (Practice for today:)
Classes are great as a form of abstraction and especially suited to represent objects we know in real life. Many games need dice to play and there is a huge assortment of dice available. Some only have four faces, while others might have 100 faces.
类是一种很好的抽象形式,特别适合表示我们在现实生活中认识的对象。 许多游戏都需要骰子才能玩,并且有各种各样的骰子可供选择。 一些人只有四张脸,而另一些人可能有100张脸。
Assignment:Create a Die class that inputs the number of faces as a parameter. It should have a throw() function to have a roll, of course using the correct die, i.e. a four-sided die can only throw 1, 2, 3, or 4. It should also contain a history() method to show the past die rolls() and a nice repr dunder function to tell us which die it is.
分配:创建一个Die类,以输入面数作为参数。 它应该具有throw()函数才能掷骰,当然要使用正确的骰子,即四面骰子只能投掷1、2、3或4。它还应包含history()方法以显示过去的die rolls()和一个不错的repr dunder函数来告诉我们它是哪个模具。
Hints:1. The random module as a randint(a, b) function that generates random numbers between (a, b) including both boundaries. Might be useful for dice ;-).2. You could use a list to keep track of all previous rolls.
提示:1。 作为randint(a,b)函数的随机模块,可在(a,b)之间生成包括两个边界的随机数。 可能对骰子有用;-)。2。 您可以使用列表来跟踪所有先前的卷。
A solution is posted on my Github.
一个解决方案发布在我的Github上。
If you have any questions, feel free to contact me through LinkedIn.
如有任何疑问,请随时通过LinkedIn与我联系。
翻译自: https://towardsdatascience.com/learning-python-10-minutes-a-day-23-8fd7e119da8d
每天30分钟学python