python面向对象编程-Class and Methods-<ThinkPython>

本书章节深入探讨Python作为面向对象编程语言的特点,包括类、方法的定义与使用,实例化对象及其操作,以及如何利用类和方法实现复杂功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Chapter 17  Classes and methods


The link of this chapter of the book ThinkPython
http://www.greenteapress.com/thinkpython/html/book018.html

17.1  Object-oriented features

Python is an object-oriented programming language, which meansthat it provides features that support object-orientedprogramming.

It is not easy to define object-oriented programming, but we havealready seen some of its characteristics:

  • Programs are made up of object definitions and functiondefinitions, and most of the computation is expressed in termsof operations on objects.
  • Each object definition corresponds to some object or conceptin the real world, and the functions that operate on that objectcorrespond to the ways real-world objects interact.

For example, the Time class defined in Chapter 16corresponds to the way people record the time of day, and thefunctions we defined correspond to the kinds of things people do withtimes. Similarly, the Point and Rectangle classescorrespond to the mathematical concepts of a point and a rectangle.

So far, we have not taken advantage of the features Python provides tosupport object-oriented programming. Thesefeatures are not strictly necessary; most of them providealternative syntax for things we have already done. But in many cases,the alternative is more concise and more accurately conveys thestructure of the program.

For example, in the Time program, there is no obviousconnection between the class definition and the function definitionsthat follow. With some examination, it is apparent that every functiontakes at least one Time object as an argument.

This observation is the motivation for methods; a method isa function that is associated with a particular class.We have seen methods for strings, lists, dictionaries and tuples.In this chapter, we will define methods for user-defined types.

Methods are semantically the same as functions, but there aretwo syntactic differences:

  • Methods are defined inside a class definition in orderto make the relationship between the class and the method explicit.
  • The syntax for invoking a method is different from thesyntax for calling a function.

In the next few sections, we will take the functions from the previoustwo chapters and transform them into methods. This transformation ispurely mechanical; you can do it simply by following a sequence ofsteps. If you are comfortable converting from one form to another,you will be able to choose the best form for whatever you are doing.

17.2  Printing objects

In Chapter 16, we defined a class namedTime and in Exercise 16.1, you wrote a function named print_time:

class Time(object):
    """represents the time of day.
       attributes: hour, minute, second"""

def print_time(time):
    print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second)

To call this function, you have to pass a Time object as anargument:

>>> start = Time()
>>> start.hour = 9
>>> start.minute = 45
>>> start.second = 00
>>> print_time(start)
09:45:00

To make print_time a method, all we have to do ismove the function definition inside the class definition. Noticethe change in indentation.

class Time(object):
    def print_time(time):
        print '%.2d:%.2d:%.2d' % (time.hour, time.minute, time.second)

Now there are two ways to call print_time. The first(and less common) way is to use function syntax:

>>> Time.print_time(start)
09:45:00

In this use of dot notation, Time is the name of the class,and print_time is the name of the method. start ispassed as a parameter.

The second (and more concise) way is to use method syntax:

>>> start.print_time()
09:45:00

In this use of dot notation, print_time is the name of themethod (again), and start is the object the method isinvoked on, which is called the subject. Just as thesubject of a sentence is what the sentence is about, the subjectof a method invocation is what the method is about.

Inside the method, the subject is assigned to the firstparameter, so in this case start is assignedto time.

By convention, the first parameter of a method iscalled self, so it would be more common to writeprint_time like this:

class Time(object):
    def print_time(self):
        print '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)

The reason for this convention is an implicit metaphor:

  • The syntax for a function call, print_time(start),suggests that the function is the active agent. It says somethinglike, “Hey print_time! Here’s an object for you to print.”
  • In object-oriented programming, the objects are the activeagents. A method invocation like start.print_time() says“Hey start! Please print yourself.”

This change in perspective might be more polite, but it is not obviousthat it is useful. In the examples we have seen so far, it may notbe. But sometimes shifting responsibility from the functions onto theobjects makes it possible to write more versatile functions, and makesit easier to maintain and reuse code.

Exercise 1  Rewrite time_to_int(from Section  16.4 ) as a method. It is probably notappropriate to rewrite int_to_time as a method; it’s notclear what object you would invoke it on!

17.3  Another example

Here’s a version of increment (from Section 16.3)rewritten as a method:

# inside class Time:

    def increment(self, seconds):
        seconds += self.time_to_int()
        return int_to_time(seconds)

This version assumes that time_to_int is writtenas a method, as in Exercise 17.1. Also, note thatit is a pure function, not a modifier.

Here’s how you would invoke increment:

>>> start.print_time()
09:45:00
>>> end = start.increment(1337)
>>> end.print_time()
10:07:17

The subject, start, gets assigned to the first parameter,self. The argument, 1337, gets assigned to thesecond parameter, seconds.

This mechanism can be confusing, especially if you make an error.For example, if you invoke increment with two arguments, youget:

>>> end = start.increment(1337, 460)
TypeError: increment() takes exactly 2 arguments (3 given)

The error message is initially confusing, because there areonly two arguments in parentheses. But the subject is alsoconsidered an argument, so all together that’s three.

17.4  A more complicated example

is_after (from Exercise 16.2) is slightly more complicatedbecause it takes two Time objects as parameters. In this case it isconventional to name the first parameter self and the secondparameter other:

# inside class Time:

    def is_after(self, other):
        return self.time_to_int() > other.time_to_int()

To use this method, you have to invoke it on one object and passthe other as an argument:

>>> end.is_after(start)
True

One nice thing about this syntax is that it almost readslike English: “end is after start?”

17.5  The init method

The init method (short for “initialization”) isa special method that gets invoked when an object is instantiated. Its full name is __init__ (two underscore characters,followed by init, and then two more underscores). Aninit method for the Time class might look like this:

# inside class Time:

    def __init__(self, hour=0, minute=0, second=0):
        self.hour = hour
        self.minute = minute
        self.second = second

It is common for the parameters of __init__to have the same names as the attributes. The statement

        self.hour = hour

stores the value of the parameter hour as an attributeof self.

The parameters are optional, so if you call Time withno arguments, you get the default values.

>>> time = Time()
>>> time.print_time()
00:00:00

If you provide one argument, it overrides hour:

>>> time = Time (9)
>>> time.print_time()
09:00:00

If you provide two arguments, they override hour andminute.

>>> time = Time(9, 45)
>>> time.print_time()
09:45:00

And if you provide three arguments, they override all threedefault values.

Exercise 2  

Write an init method for the Point class that takesx and y as optional parameters and assignsthem to the corresponding attributes.

17.6  The __str__ method

__str__ is a special method, like __init__,that is supposed to return a string representation of an object.

For example, here is a str method for Time objects:

# inside class Time:

    def __str__(self):
        return '%.2d:%.2d:%.2d' % (self.hour, self.minute, self.second)

When you print an object, Python invokes the str method:

>>> time = Time(9, 45)
>>> print time
09:45:00

When I write a new class, I almost always start by writing __init__, which makes it easier to instantiate objects, and __str__, which is useful for debugging.

Exercise 3  Write a str method for the Point class. Createa Point object and print it.

17.7  Operator overloading

By defining other special methods, you can specify the behaviorof operators on user-defined types. For example, if you definea method named __add__ for the Time class, you can use the+ operator on Time objects.

Here is what the definition might look like:

# inside class Time:

    def __add__(self, other):
        seconds = self.time_to_int() + other.time_to_int()
        return int_to_time(seconds)

And here is how you could use it:

>>> start = Time(9, 45)
>>> duration = Time(1, 35)
>>> print start + duration
11:20:00

When you apply the + operator to Time objects, Python invokes__add__. When you print the result, Python invokes __str__. So there is quite a lot happening behind the scenes!

Changing the behavior of an operator so that it works withuser-defined types is called operator overloading. For everyoperator in Python there is a corresponding special method, like __add__. For more details, seedocs.python.org/ref/specialnames.html.

Exercise 4  Write an add method for the Point class.

17.8  Type-based dispatch

In the previous section we added two Time objects, but youalso might want to add an integer to a Time object. Thefollowing is a version of __add__that checks the type of other and invokes eitheradd_time or increment:

# inside class Time:

    def __add__(self, other):
        if isinstance(other, Time):
            return self.add_time(other)
        else:
            return self.increment(other)

    def add_time(self, other):
        seconds = self.time_to_int() + other.time_to_int()
        return int_to_time(seconds)

    def increment(self, seconds):
        seconds += self.time_to_int()
        return int_to_time(seconds)

The built-in function isinstance takes a value and aclass object, and returns True if the value is an instanceof the class.

If other is a Time object, __add__ invokesadd_time. Otherwise it assumes that the parameteris a number and invokes increment. This operation iscalled a type-based dispatch because it dispatches thecomputation to different methods based on the type of thearguments.

Here are examples that use the + operator with differenttypes:

>>> start = Time(9, 45)
>>> duration = Time(1, 35)
>>> print start + duration
11:20:00
>>> print start + 1337
10:07:17

Unfortunately, this implementation of addition is not commutative.If the integer is the first operand, you get

>>> print 1337 + start
TypeError: unsupported operand type(s) for +: 'int' and 'instance'

The problem is, instead of asking the Time object to add an integer,Python is asking an integer to add a Time object, and it doesn’t knowhow to do that. But there is a clever solution for this problem: thespecial method __radd__, which stands for “right-side add.”This method is invoked when a Time object appears on the right side ofthe + operator. Here’s the definition:

# inside class Time:

    def __radd__(self, other):
        return self.__add__(other)

And here’s how it’s used:

>>> print 1337 + start
10:07:17
Exercise 5  Write an add method for Points that works with either aPoint object or a tuple:
  • If the second operand is a Point, the method should return a newPoint whose x coordinate is the sum of the x coordinates of theoperands, and likewise for the y coordinates.
  • If the second operand is a tuple, the method should add thefirst element of the tuple to the x coordinate and the secondelement to the y coordinate, and return a new Point with the result.

17.9  Polymorphism

Type-based dispatch is useful when it is necessary, but (fortunately)it is not always necessary. Often you can avoid it by writing functionsthat work correctly for arguments with different types.

Many of the functions we wrote for strings will actuallywork for any kind of sequence.For example, in Section 11.1we used histogram to count the number of times each letterappears in a word.

def histogram(s):
    d = dict()
    for c in s:
        if c not in d:
            d[c] = 1
        else:
            d[c] = d[c]+1
    return d

This function also works for lists, tuples, and even dictionaries,as long as the elements of s are hashable, so they can be usedas keys in d.

>>> t = ['spam', 'egg', 'spam', 'spam', 'bacon', 'spam']
>>> histogram(t)
{'bacon': 1, 'egg': 1, 'spam': 4}

Functions that can work with several types are called polymorphic.Polymorphism can facilitate code reuse. For example, the built-infunction sum, which adds the elements of a sequence, worksas long as the elements of the sequence support addition.

Since Time objects provide an add method, they workwith sum:

>>> t1 = Time(7, 43)
>>> t2 = Time(7, 41)
>>> t3 = Time(7, 37)
>>> total = sum([t1, t2, t3])
>>> print total
23:01:00

In general, if all of the operations inside a function work with a given type, then the function works with that type.

The best kind of polymorphism is the unintentional kind, whereyou discover that a function you already wrote can beapplied to a type you never planned for.

17.10  Debugging

It is legal to add attributes to objects at any point in the executionof a program, but if you are a stickler for type theory, it is adubious practice to have objects of the same type with differentattribute sets. It is usually a good idea toinitialize all of an objects attributes in the init method.

If you are not sure whether an object has a particular attribute, youcan use the built-in function hasattr (see Section 15.7).

Another way to access the attributes of an object is through thespecial attribute __dict__, which is a dictionary that mapsattribute names (as strings) and values:

>>> p = Point(3, 4)
>>> print p.__dict__
{'y': 4, 'x': 3}

For purposes of debugging, you might find it useful to keep thisfunction handy:

def print_attributes(obj):
    for attr in obj.__dict__:
        print attr, getattr(obj, attr)

print_attributes traverses the items in the object’s dictionaryand prints each attribute name and its corresponding value.

The built-in function getattr takes an object and an attributename (as a string) and returns the attribute’s value.

17.11  Glossary

object-oriented language:
A language that provides features,such as user-defined classes and method syntax, that facilitateobject-oriented programming.
object-oriented programming:
A style of programming in whichdata and the operations that manipulate it are organized into classesand methods.
method:
A function that is defined inside a class definition andis invoked on instances of that class.
subject:
The object a method is invoked on.
operator overloading:
Changing the behavior of an operator like+ so it works with a user-defined type.
type-based dispatch:
A programming pattern that checks the typeof an operand and invokes different functions for different types.
polymorphic:
Pertaining to a function that can work with morethan one type.

17.12  Exercises

Exercise 6  

This exercise is a cautionary tale about one of the mostcommon, and difficult to find, errors in Python.

  1. Write a definition for a class named Kangaroo with the followingmethods:
    1. An __init__ method that initializes an attribute named pouch_contents to an empty list.
    2. A method named put_in_pouch that takes an objectof any type and adds it to pouch_contents.
    3. A __str__ method that returns a string representationof the Kangaroo object and the contents of the pouch.

    Test your code by creating two Kangaroo objects, assigning them to variablesnamed kanga and roo, and then adding roo to thecontents of kanga’s pouch.

  2. Download thinkpython.com/code/BadKangaroo.py. It containsa solution to the previous problem with one big, nasty bug.Find and fix the bug.

    If you get stuck, you can downloadthinkpython.com/code/GoodKangaroo.py, which explains theproblem and demonstrates a solution.

Exercise 7  

Visual is a Python module that provides 3-D graphics. It isnot always included in a Python installation, so you might haveto install it from your software repository or, if it’s not there,from vpython.org.

The following example creates a 3-D space that is 256 unitswide, long and high, and sets the “center” to be thepoint (128, 128, 128). Then it draws a blue sphere.

from visual import *

scene.range = (256, 256, 256)
scene.center = (128, 128, 128)

color = (0.1, 0.1, 0.9)          # mostly blue
sphere(pos=scene.center, radius=128, color=color)

color is an RGB tuple; that is, the elements are Red-Green-Bluelevels between 0.0 and 1.0 (seewikipedia.org/wiki/RGB_color_model).

If you run this code, you should see a window with a blackbackground and a blue sphere. If you drag the middle buttonup and down, you can zoom in and out. You can also rotatethe scene by dragging the right button, but with only onesphere in the world, it is hard to tell the difference.

The following loop creates a cube of spheres:

t = range(0, 256, 51)
for x in t:
    for y in t:
        for z in t:
            pos = x, y, z
            sphere(pos=pos, radius=10, color=color)
  1. Put this code in a script and make sure it works foryou.
  2. Modify the program so that each sphere in the cubehas the color that corresponds to its position in RGB space.Notice that the coordinates are in the range 0–255, butthe RGB tuples are in the range 0.0–1.0.

  3. Download thinkpython.com/code/color_list.pyand use the function read_colors to generate a listof the available colors on your system, their names andRGB values. For each named color draw a sphere in theposition that corresponds to its RGB values.

You can see my solution at thinkpython.com/code/color_space.py.

把下述python代码换成matlab语言graph TD A[MPC控制器] -->|调度指令| B[光伏MPPT] A -->|调度指令| C[风机MPPT] A -->|启停信号| D[柴油发电机] A -->|充放电计划| E[储能系统] A -->|负荷预测| F[负荷管理]class PVSystem: def __init__(self, V_oc=45, I_sc=8): self.V = V_oc self.I = I_sc self.step = 0.5 # 电压扰动步长 def mppt_perturb_observe(self, V_pv, I_pv): P_old = self.V * self.I P_new = V_pv * I_pv if P_new > P_old: self.V += self.step if (V_pv > self.V) else -self.step else: self.step *= -0.8 # 反向搜索 return self.Vclass WindTurbine: def __init__(self, R=3.2, lambda_opt=7): self.R = R # 叶片半径(m) self.lambda_opt = lambda_opt # 最佳叶尖速比 def mppt_tsr(self, wind_speed, gen_speed): tip_speed_ratio = (gen_speed * self.R) / wind_speed delta = 0.05 * (self.lambda_opt - tip_speed_ratio) return gen_speed + delta # 调整发电机转速class WindTurbine: def __init__(self, R=3.2, lambda_opt=7): self.R = R # 叶片半径(m) self.lambda_opt = lambda_opt # 最佳叶尖速比 def mppt_tsr(self, wind_speed, gen_speed): tip_speed_ratio = (gen_speed * self.R) / wind_speed delta = 0.05 * (self.lambda_opt - tip_speed_ratio) return gen_speed + delta # 调整发电机转速class DieselGenerator: def __init__(self, P_max=50): # 50kW柴油机 self.status = False self.P_out = 0 def start_stop(self, demand, soc): if demand > 0.8*soc and not self.status: self.status = True self.P_out = min(demand - soc, self.P_max) elif demand < 0.2*soc and self.status: self.shutdown() def shutdown(self): self.status = False self.P_out = 0class EnergyStorage: def __init__(self, capacity=100, soc=0.5): # 100kWh self.soc = soc self.charge_mode = 'CC' # 恒流/恒压 def charge_control(self, P_demand, V_bus): if self.soc < 0.2: return
03-28
<think>嗯,用户想把之前用Python写的代码转换成MATLAB,特别是涉及到MPC控制器、光伏MPPT、风机MPPT、柴油发电机和储能系统的类和方法。首先,我需要回忆一下Python和MATLAB在语法和结构上的主要区别。Python使用类,而MATLAB也有面向对象的编程,但语法不同。比如,MATLAB的类定义在单独的文件中,方法需要放在methods块里。另外,Python的列表推导式在MATLAB中可能需要用循环或者向量化操作来代替。 接下来,用户提到的各个模块,比如MPC控制器,可能需要处理优化问题。Python里可能用了scipy或者cvxpy,而MATLAB则可以用Optimization Toolbox或者MPC工具箱。MPPT部分可能涉及到算法如P&O(扰动观察法),需要确保在MATLAB中正确实现逻辑。 然后,考虑类的方法转换。例如,Python中的类方法可能需要转换成MATLAB的静态方法或者普通方法。属性的初始化在MATLAB的构造函数中处理。还要注意MATLAB的函数参数传递方式,是否使用handle类来传递对象引用。 用户可能没有提到的细节包括MATLAB处理矩阵运算的方式,比如元素乘法和矩阵乘法的区别,以及如何处理动态类型和变量作用域。此外,MATLAB没有Python的列表切片,可能需要用数组操作来实现。 需要确保生成的MATLAB代码结构清晰,每个类对应一个文件,方法正确封装。同时,像MPC这样的控制器可能需要调用特定的求解器,需要检查MATLAB中对应的函数。另外,柴油发电机和储能系统的逻辑可能需要状态更新,这部分在MATLAB中可能需要使用持久变量或者类的属性来保存状态。 最后,测试和验证转换后的代码是否功能一致,可能需要逐步转换每个模块并进行单元测试。用户可能还需要性能优化方面的建议,比如预分配数组,使用向量化操作等。</think>### Python到MATLAB代码转换关键点分析 1. **类结构转换** MATLAB使用`classdef`定义类,方法与属性需明确声明。例如光伏MPPT类转换: ```matlab classdef PV_MPPT properties V_oc I_sc V_mppt end methods function obj = PV_MPPT(V_oc, I_sc) obj.V_oc = V_oc; obj.I_sc = I_sc; end function [V, I] = track(obj, irradiance) % 实现类似Python的MPPT算法 obj.V_mppt = obj.V_oc * 0.8; I = irradiance/1000 * obj.I_sc; V = obj.V_mppt; end end end ``` 2. **矩阵运算转换** Python的`numpy`操作需改为MATLAB语法: ```matlab % Python: np.dot(A, B) A * B % Python: arr[1:] arr(2:end) ``` 3. **控制结构差异** - 循环语句去掉冒号 - 逻辑运算改用`&&`、`||` ```matlab % Python列表推导式转换 matlab_arr = arrayfun(@(x) x^2, 1:10); ``` 4. **MPC控制器实现** MATLAB推荐使用`mpc`对象或`fmincon`: ```matlab function u = mpc_control(x0, ref) opt = optimoptions('fmincon','Algorithm','sqp'); cost_func = @(u) sum((predict_states(u)-ref).^2); u = fmincon(cost_func, u0, [], [], [], [], lb, ub, [], opt); end ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值