CS入门学习笔记13-MIT 6.00.1x- Lecture 11 Classes

Lectrue 11

1. Class 由来

1.1 Objects

  • 先前学过的int,float,string,list,dictionary都是一种type,他们中包含的各种具体内容都是一个object。
  • object包括:
    · A type (a particular object is said to be an instance of the type),不同的type控制对象不同的behavior
    · An internal data representation (primitive or composite)
    · A set of procedures for interaction with the object

**Example: [1, 2, 3, 4]

  • Type: list
  • Internal data representation,可以选择不同的表示方法:
    1、 int length L, an object array of size S >= L ——》 an efficient way to search, 但是 hard to change.
    2、 A linked list of individual cells. 每一个cell都包含有两部分: <data, pointer to next cell>,数据本身,以及一个指向下一个cell的pointer。——》not so efficient to search, 但是easy to change (like insert)
  • !! Internal representation is private – users of the objects should not rely on particular details of the implementation.
  • Procedures for manipulating lists
    在这里插入图片描述
    我们有如上图中这么多的可对list进行的操作,但作为用户,我们只需要知道如何use the procedure,不需要知道它们其中的internal data representation.

1.2 Object-oriented programming (OOP)

  • Everything is an object and has a type

  • Objects are a data abstraction that encapsulate
    – Internal representation
    – Interface for interacting with object

    • Defines behaviors(用户只能看到这个), hide implementation
    • Attributes: data, methods (procedures)
  • One can
    – Create new instances of objects(explicitly or using literals)
    – Destroy objects

    • Explicitly using delor just “forget” about them
    • Python system will reclaim destroyed or inaccessible objects – python has a garbage collection allows the system to go around and reclaim the objects which are not accessible.

1.3 Advantages of OOP

  • Bundle data into packages together with procedures that work on them through well-defined interfaces

  • Divide-and-conquer development
    – Implement and test behaior of each class separately
    – Increased modularity reduces complexity

  • Classes make it easy to reuse code
    – Many Python modules define new classes
    – Each clase has a separate environment (no collision on function names)
    – Inheritance allows subclasses to redefine or extend a selected subset of a superclass’ behavior

2. Defining new types
  • In Python, the class statement is used to define a new type
class Coordinate(object):
    ...define attributes here ...
  • Indentation used to indicate which statements are part of the class definition

  • Classes can inherit attributes from other classes, in this case Coordinate inherits from the object class. Coordinate is said to be a subclass of object, object is a superclass of Coordinate. One can override an inherited attribute with a new definition in the class statement.

  • 当我们定义一个class的时候,我们实际上就定义了一种数据类型。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样

  • What are attributes? – data and procedures that “belong” to the class
    data attributes
    think of data as other objects that make up the class
    procedural attributes (methods)
    think of methods as functions that only work with this class

2.1 Creating an instance

  • Usually when creating an instance of a type, we will want to provide some initial values for the internal data. To do this, define an init method:
class Coordinate(object):  
# 括号里的内容是class parent,说明此class 会inherit 父class里的所有attribute
    def __init__(self, x, y):
        self.x = x # x, y 是instance variables
        self.y = y 
'''
when calling a method of an object, Python always passes the object as the first argument. By convention, we use self as the name of the first argument of methods.
self 相当于是coordinate用于指向自己的一个指针,确保了是在local的environment里运行。
也可以用别的名字,但self是一种习惯,每一个class里的procedure都要在第一个attribute的位置写这个。

若在class中没有定义__init__函数,那么系统就会去superclass object里寻找。
When accessing an attribute of an instance, start by looking within the class definition, then move up to the definition of a superclass, then move to the global environment.
'''
# calling the upper class
c = Coordinate(3, 4)  
# don't provide argument for self, python does this automatically
origin = Coordinate(0, 0)
print c.x, origin.x
>>> 3 0
>type(c)
>>> __main__.Coordinate
>type(Coordinate.__init__)
>>> function
>type(object)
>>> type
>type(Coordinate)
>>> type
>print(c)
>>><__main__.Coordinate object at 0x000001811CAF8088>
# 直接print(c)会返回c所在的位置。

# 用于判断c是否是type为Coordinate的一个instance
>isinstance(c, Coordinate)
>>> True

'''
每call一次coordinate,就会生成一个新的frame,里面存放各自独立的变量。
'''

2.2 an environment view of classes

在这里插入图片描述在这里插入图片描述
frame --> Coordinate
method --> init
procedure --> 定义self, x, y

在这里插入图片描述当class被call之后,生成的新frame才算是一个instance

在这里插入图片描述
在这里插入图片描述
上图显示出,通过c.__init__这种方式也可以叫出class里的method,但是根据python不同的版本,可能会产生不同的结果:生成一个新的frame或者改变原frame,这种做法很危险,但此例只是为了展示其能被调用。

3. Adding methods to a class

one can define a str method for a class, which Python will call hen it needs a string to print. This method will be called with the object as the first argument and should return a str.

class Coordinate(object):
    def __init__(self, x, y):
        self.x = x
        self.y = y
    def __str__(self):
        return "<" + self.x + "," + self.y + ">"
    def distance(self, other):
        return math.sqrt(sq(self.x - other.x) + sq(self.y - other.y))

c = Coordinate(6, 8)
origin = Coordinate(0, 0)
print(origin.distance(c))
# origin.distance()里面不能直接指定一个tuple形式的坐标,因为程序找不到对应的x和y。
>>> 10.0
4. 作业题

4.1. time 与 self.time的区别

class Clock(object):
    def __init__(self, time):
	     self.time = time
    def print_time(self):
	     time = '6:30' # 若将此处改为self.time,则输出结果变为6:30
	     print(self.time) # 若将此处改为time,则输出结果变为6:30

clock = Clock('5:30')
clock.print_time()
# 此例中可以理解为有两个变量,self.time和time,分别储存不同的值。

4.2. class中method的运行

class Clock(object):
    def __init__(self, time):
	self.time = time
    def print_time(self, time):
	print time

clock = Clock('5:30')
clock.print_time('10:30')
# 在第一次call Clock('5:30')时,相当于只运行了 __init__ 这个函数,赋值了此frame里的self.time。

4.3. 不同instance之间的aliasing关系

class Clock(object):
    def __init__(self, time):
	     self.time = time
    def print_time(self):
	     print(self.time)

boston_clock = Clock('5:30')
paris_clock = boston_clock
paris_clock.time = '10:30'
boston_clock.print_time()

>>>10:30
# boston_clock and paris_clock are two names for the same object. 
# 他们指向的是同一个对象
# This is called aliasing.

4.4. x与self.x的再次区别

class Weird(object):
    def __init__(self, x, y): 
        self.y = y
        self.x = x
    def getX(self):
        return x 
    def getY(self):
        return y

class Wild(object):
    def __init__(self, x, y): 
        self.y = y
        self.x = x
    def getX(self):
        return self.x 
    def getY(self):
        return self.y

X = 7
Y = 8

> w1 = Weird(X, Y)
> print w1.getX()
>>> name 'x' is not defined

> w1 = Wild(X, Y)
> print(w1.getX())
>>> 7

> w4 = Wild(X, 18)
> print w4.getX()
>>> 7
# 因为class时是在定义,会先执行X,Y的赋值,才会有w4的赋值。

> X = w4.getX() + w1.getX()
# 改变X的值为14,然后再次调用w4.getX()
> print w4.getX()
>>> 7
# 所以,改变的是全局变量X的值,而没有改变w4的frame中x的值。

4.5. 在一个类中添加equal和repr 两个method

class Coordinate(object):
def init(self, x, y):
self.x = x
self.y = y

def getX(self):
    # Getter method for a Coordinate object's x coordinate.
    # Getter methods are better practice than just accessing an attribute directly
    return self.x

def getY(self):
    # Getter method for a Coordinate object's y coordinate
    return self.y

def __str__(self):
    return '<' + str(self.getX()) + ',' + str(self.getY()) + '>'

Your task is to define the following two methods for the Coordinate class:

Add an __eq__ method that returns True if coordinates refer to same point in the plane (i.e., have the same x and y coordinate).

Define __repr__, a special method that returns a string that looks like a valid Python expression that could be used to recreate an object with the same value. In other words, eval(repr(c)) == c given the definition of __eq__ from part 
class Coordinate(object):
    def __init__(self,x,y):
        self.x = x
        self.y = y

    def getX(self):
        # Getter method for a Coordinate object's x coordinate.
        # Getter methods are better practice than just accessing an attribute directly
        return self.x

    def getY(self):
        # Getter method for a Coordinate object's y coordinate
        return self.y

    def __str__(self):
        return '<' + str(self.getX()) + ',' + str(self.getY()) + '>'

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __repr__(self):
        return 'Coordinate(' + str(self.getX()) + ', ' + str(self.getY()) + ')'

**关于repr

  • repr是python类中的一个特殊方法,在内置的object类中就已经定义,由于所有的python类都是object类的子类,所以所有的python对象都具有repr这个方法。
  • repr时常被用于与str比较,区别在于,str只是将目标转换为字符形式,repr虽然返回的是string格式,但是更容易被解释器读取的完整形式,更可以与eval进一步配合,形成eval(repr©) == c的效果(c可以使各种数据类型)
    在这里插入图片描述
  • 援引别处的信息进一步参考:
    class test:
        def __init__(self,name,age):
            self.age = age
            self.name = name
     
    t = test("Zhou",30)
     
    print(t)

以上代码的输出结果为“<main.test object at 0x000001FA117FEA58>”

print方法之所以能打印对应,正是由于每个类都有继承自object类的_repr_方法,在这里,print函数实际输出的是test对象_repr_方法的返回值,以下两行代码的结果是完全一致的:

    print(t)
     
    print(t._repr_()

_repr_方法默认返回该对象实现类的“类名+object at +内存地址”值

当然,我们也可以尝试自己重写该方法,来满足我们希打印出的信息

    class test:
        def __init__(self,name,age):
            self.age = age
            self.name = name
        def __repr__(self):
            return "Class_Test[name="+self.name+",age="+str(self.age)+"]"
    t = test("Zhou",30)
     
    print(t)

输出结果为:Class_Test[name=Zhou,age=30]

通过重写_repr_方法,我们打印出了类名、以及其包含的属性名称、属性值
————————————————
版权声明:本文为CSDN博主「specialxj79」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/specialxj79/article/details/90389989

5. Example class: a set of integers

**new type的三要素: behavior, internal data representation, interface

  • Create a new type to represent a set (or collection) of integers
    – Initially the set is empty
    – A particular integer appears only once in a set----define the behavior

    • This constraint, called a representational invariant, is enforced by the code in the methods.

    Internal data representation

    • Use a list to remember the elements of a set

    Interface

    • insert(e) – insert integer e into set if not there
    • member(e) – return True if integer e is in set, False else
    • remove(e) – remove integer e from set, error if not present

class intSet(object):
    """An intSet is a set of integers
    The value is represented by a list of ints, self.vals
    Each int in the set occurs in self.vals exactly once."""
    
    def __init__(self):
        """Create an empty set of integers"""
        self.vals = []
    
    def insert(self, e):
        """Assumes e is an integer and insert e into self"""
        if not e in self.vals:
            self.vals.append(e)
    
    def __str__(self):
        """Returns a string representation of self"""
        self.vals.sort()
        return '{' + ','.join([str(e) for e in self.vals]) + '}'
    
    def member(self, e):
        """Assumes e is an integer,
        Returns True if e is in self, and False otherwise"""
        return e in self.vals
    
    def remove(self, e):
        """Assumes e is an integer and removes e from self
        Raises ValueError if e is not in self"""
        try:
            self.vals.remove(e)
        except:
            raise ValueError(str(e) + ' not found')
6. python class 中的special methods

special methods有时也叫magic methods,他们都是在python中原本内置过的函数,若在class中未特别定义,则会自动调用内置参数;若单独定义了,则调用class中的版本。

在这里插入图片描述

1. 打印用的函数__str__和__repr__

It’s common practice in Python to provide a string representation of your object for the consumer of your class (a bit like API documentation.) There are two ways to do this using dunder methods:

__repr__: The “official” string representation of an object. This is how you would make an object of the class. The goal of __repr__ is to be unambiguous.

__str__: The “informal” or nicely printable string representation of an object. This is for the enduser.

Let’s implement these two methods on the Account class:

class Account:
# … (see above)

def __repr__(self):
    return 'Account({!r}, {!r})'.format(self.owner, self.amount)

def __str__(self):
    return 'Account of {} with starting amount: {}'.format(
        self.owner, self.amount)

If you don’t want to hardcode “Account” as the name for the class you can also use self.class.name to access it programmatically.

If you wanted to implement just one of these to-string methods on a Python class, make sure it’s repr.

2. 其他的一些special method

  • 这个描述比较具体,但条理性一般
    https://dbader.org/blog/python-dunder-methods

  • 这个条理清晰,比较全
    https://rszalski.github.io/magicmethods/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值