Python中,类的特殊方法与内置函数的关联

Posted iSherryZhang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python中,类的特殊方法与内置函数的关联相关的知识,希望对你有一定的参考价值。

Python类

Python类的设计原则

  • 封装(Encapsulation):Python类被设计用来将相关数据和行为封装到一个独立的单元中。
  • 继承(Inheritance):Python支持继承,允许子类从父类继承属性和方法。有利于代码的复用和创建相关类的层次结构。
  • 多态(Polymorphism):Python支持多态,也就意味着不同类的对象可以被视为同一类型,这使得代码的设计具有更大的灵活性。
  • 组合(Composition):Python鼓励使用组合而不是继承,这意味着对象是由其他对象组成的,而不是由父类派生的。这可以使您的代码更加模块化,更易于维护。
  • Duck类型(Duck typing):Python使用Duck类型,这意味着对象的类型由其行为而非类决定,这样更容易编写可用于各种对象的通用代码。
  • 特殊方法(Special methods):Python提供了许多特殊方法,允许为内置操作自定义行为。例如__len__方法允许你定义len()函数如何处理类的对象。
  • 可读性(Readability):与Python的一般设计原则一样,类也应该优先考虑可读性和简单性,也就是说,对方法和属性使用清晰简洁的名称,避免不必要的复杂性。
特殊方法【Special methods】

Python中的特殊方法是一系列预定义的方法,允许你为对象上的内置操作定义自定义行为,使用双下划线前缀和后缀来识别,也成为"dunder"方法。这里讲述一些Python类中常用的特殊方法:

  1. __init__(self, ...): 这是构造方法,对象创建时调用,用于初始化对象的属性并设置其初始状态。
  2. __str__(self): 返回对象的字符串表示,用于创建一个人类可读的字符串表示。
  3. __repr__(self): 返回对象的字符串表示,用于创建可用于创建对象的字符串表示。
  4. __len__(self): 返回对象的长度,供len()函数使用。
  5. __getitem__(self, key): 这个方法允许你以括号的形式访问对象的元素,可以使用[]来访问元素。
  6. __setitem__(self, key, value): 这个方法允许你以括号的形式设置对象元素的值,可以使用[]来修改元素的值。
  7. __delitem__(self, key): 这个方法允许你以括号的形式删除对象的元素。
  8. __add__(self, other): 自定义对象的+操作方式。
  9. __eq__(self, other): 自定义对象的==操作方式。
  10. __lt__(self, other): 自定义对象的<操作方式。

这只是较为常用的一些,Python中还提供了很多其他的特殊方法。在你的自定义类中,通过定义这些方法,你可以自定义你对象的行为以更直观、更方便地使用它们。

示例一:

class Person:
    def __init__(self, name, age, items):
        self.name = name
        self.age = age
        self.items = items
    
    def __str__(self):
        return f"self.name (self.age)"
    
    def __repr__(self):
        return f"Person(name=\'self.name\', age=self.age)"
    
    
person = Person("Alice", 25)
print(person)       # output: Alice (25)
print(repr(person)) # output: Person(name=\'Alice\', age=25)

示例二:

class MyObject:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):
        return len(self.items)
    
    def __getitem__(self, index):
        return self.items[index]
    
    def __setitem__(self, index, value):
        self.items[index] = value
    
    def __delitem__(self, index):
        del self.items[index]
    
    def __add__(self, other):
        new_items = self.items + other.items
        return MyObject(new_items)
    
    def __eq__(self, other):
        if isinstance(other, MyObject):
            return self.items == other.items
        return False
    
    def __lt__(self, other):
        if isinstance(other, MyObject):
            return len(self.items) < len(other.items)
        return NotImplemented
    
obj = MyObject([1, 2, 3])
print(len(obj))  # output: 3
print(obj[1])    # output: 2
obj[1] = 4
print(obj.items) # output: [1, 4, 3]
del obj[1]
print(obj.items) # output: [1, 3]
obj1 = MyObject([1, 2])
obj2 = MyObject([3, 4])
obj3 = obj1 + obj2
print(obj3.items) # output: [1, 2, 3, 4]

obj4 = MyObject([1, 2, 3])
obj5 = MyObject([4, 5])
obj6 = MyObject([1, 2, 3])

print(obj1 == obj2) # output: False
print(obj1 == obj3) # output: True

print(obj1 < obj2) # output: False
print(obj2 < obj1) # output: True
  • 格式化字符串

详细解释下这句话,字符串文字前面的f用于创建格式化字符串(f-string, formatted string),格式化字符串是一种允许你使用大括号将表达式嵌入占位符中的字符串,这些表达式将在运行时被求值并替换为它们的值。

例如下面的代码中,嵌入的表达式有两个self.nameself.age,运行时,会将这两个表达式替换为其值并返回。

f"Person(name=\'self.name\', age=self.age)"
Duck typing

The term "duck typing" comes from the saying, "If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck."

Duck类型是Python等动态类型编程语言中使用的一种编程概念。在Duck类型中,一个对象的类型是由它的行为决定的,而不是它的class或者type决定的。Duck Typing一词来源于这样一句话“如果它看起来像鸭子,游泳像鸭子,嘎嘎叫像鸭子,那么它可能就是鸭子”。

Duck类型使得程序员可以编写适用于任何具有必要属性和方法的对象的代码,比如:

def print_size(obj):
    print(len(obj))

该函数接收一个参数obj并打印其size。由于Python使用duck类型,这个函数适用于任何包含len()方法的对象,比如字符串、列表、元组、字典等等(string, list, tuple, dictionaries and so on)。

使用Duck类型可以编写更加通用的代码,使得代码更加容易复用和维护。

但是使用Duck类型也极易出错,为了避免这些错误,可是使用类型检查来确保你的代码运行在你期望的对象类型上。

内置函数
  • 关于len(obj)中的len()

len()是Python内置函数,用于返回对象的长度。

len()可被用于多种类型的对象,包括字符串、列表、元组、字典、集合等,并返回对象中元素的数目。

在自定义的类中,通过实现特殊方法__len__()来使用len()函数来检索对象的长度,返回值要求是整数。

  • 关于内置函数的更多细节

    上面讲述的是其中一个内置函数,详细看下,Python中的一些其他内置函数:

    1. print(): 打印特定信息到控制台,对应__str__()
    2. type(): 返回对象类型,对应__class__()
    3. len(): 返回对象长度,对应__len__()
    4. range(): 生成数字序列,默认从0开始,步长为1,直到某个终止值[不包括]
    5. input(): 接收控制台输入
    6. int(), float(), str(): 将输入转换为某种特定类型,整数、浮点数或字符串。
    7. max(), min(): 在一个序列中找到最大值和最小值,适用于列表、元组、集合等,对应__gt____lt__()
    8. sum(): 取得序列值得和,适用于列表、元组、集合等
    9. sorted()以升序排序一个序列,适用于列表、元组、集合等
    10. zip(): 将两个或多个序列合并为一个元组序列

示例一:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Person(name=\'self.name\', age=self.age)"

    def __lt__(self, other):
        return self.age < other.age

    def __gt__(self, other):
        return self.age > other.age

p1 = Person("Alice", 25)
p2 = Person("Bob", 30)
p3 = Person("Charlie", 20)

people = [p1, p2, p3]

print(p1)        # Output: Person(name=\'Alice\', age=25)
print(min(people).name)  # Output: \'Charlie\'
print(max(people).name)  # Output: \'Bob\'

特殊方法与内置函数的对应:

特殊方法 内置函数 备注
__len__() len() 返回对象的长度
__getitem__(), __setitem__() [] 定义对象元素的访问和修改行为
__iter__(), __next__() for 定义对象的迭代行为
__contains__() in 判断对象是否包含某个特定元素
__add__(), __radd__() + 定义对象的加法行为
__sub__(), __rsub__() - 定义对象的减法行为
__mul__(), __rmul__() * 定义对象的乘法行为
__divmod__(), __rdivmod__() divmod() 定义对象的余数除法行为
__eq__(), __ne__() ==, != 定义对象的判等操作
__lt__(), __le__(),
__gt__(), __ge__()
<, <=, >, >= 定义对象间的比较操作
__hash__() hash() 定义对象的哈希值(hash value)

English Version

The key design principles for Python classes

  • Encapsulation:Python classes are designed to encapsulated related data and bahavior into a single unit.
  • Inheritance:Python supports inheritance, which allows classes to inherit attributes and methods from parent classes. This makes it easier to reuse code and create hierarchies of related classes.
  • Polymorphism:Python supports polymorphism, which means that objects of different classes can be treated as if they are the same type. This allows for greater flexibility in the design of your code.
  • Composition:Python encourages the use of composition over inheritance, which means that objects are made up of other objects rather than being derived from parent classes. This can make your code more modular and easier to maintain.
  • Duck typing: Python uses duck typing, which means that the type of an object is determined by its behavior rather than its class. This makes it easier to write generic code that works with a variety of objects.
  • Special methods: Python has a number of special methods that allow you to define custom behavior for built-in operations. For example, the __len__ method allows you to define how the len() function works with objects of your class.
  • Readability: As with the general design principles of Python, classes should also prioritize readability and simplicity. This means using clear and concise names for methods and attributes, avoiding unnecessary complexity, and following PEP 8 guidelines for formatting.
Special methods

Special methods in Python are a set of predefined methods that allow you to define custom behavior for built-in operations on your objects. They are identified by their double underscore prefix and suffix, also known as "dunder" methods.

Here are some of the most commonly used special methods in Python:

  1. __init__(self, ...): This is the constructor method that is called when an object is called. It initializes the object\'s attributes and sets its initial state.
  2. __str__(self): This methods returns a string representation of the object. It\'s called by the str() function and by the print() statement.
  3. __repr__(self): This method returns a string representation of the object that can be used to recreate the object. It is called by the repr() function and by the interactive Python shell. The difference between __str__ and __repr__ is that __repr__ is used to create an unambiguous string representation of an object that can be used to recreate the object, while __str__ is used to create a human-readable string representation of an object.
  4. __len__(self): This method returns the length of the object. It is called by the len() function.
  5. __getitem__(self, key): This method allows you to access an item in the object using bracket notation. It is called when you use the bracket operation([]) on the object.
  6. __setitem__(self, key, value): This method allows you to set the value of an item in the object using bracket notation. It is called when you use the bracket operation([]) on the object with an assignment.
  7. __delitem__(self, key): This method allows you to delete an item from the object using bracket notation. It is called when you use the del statement on the object with bracket notation.
  8. __add__(self, other): This method allows you to define how the + operator works with your object. It is called when you use the + operator on the object.
  9. __eq__(self, other): This method allows you to define how the == operator works with your object. It is called when you use the == operator on the object.
  10. __lt__(self, other): This method allows you to define how the < operator works with your object. It is called when you use the < operator on the object.

There are many other special methods available in Python, but these are some of the most commonly used ones. By defining these methods in your classes, you can customize the behavior of your objects and make them more intuitive and convenient to use.

Example1:

class Person:
    def __init__(self, name, age, items):
        self.name = name
        self.age = age
        self.items = items
    
    def __str__(self):
        return f"self.name (self.age)"
    
    def __repr__(self):
        return f"Person(name=\'self.name\', age=self.age)"
    
    
person = Person("Alice", 25)
print(person)       # output: Alice (25)
print(repr(person)) # output: Person(name=\'Alice\', age=25)

Example2:

class MyObject:
    def __init__(self, items):
        self.items = items
    
    def __len__(self):
        return len(self.items)
    
    def __getitem__(self, index):
        return self.items[index]
    
    def __setitem__(self, index, value):
        self.items[index] = value
    
    def __delitem__(self, index):
        del self.items[index]
    
    def __add__(self, other):
        new_items = self.items + other.items
        return MyObject(new_items)
    
    def __eq__(self, other):
        if isinstance(other, MyObject):
            return self.items == other.items
        return False
    
    def __lt__(self, other):
        if isinstance(other, MyObject):
            return len(self.items) < len(other.items)
        return NotImplemented
    
obj = MyObject([1, 2, 3])
print(len(obj))  # output: 3
print(obj[1])    # output: 2
obj[1] = 4
print(obj.items) # output: [1, 4, 3]
del obj[1]
print(obj.items) # output: [1, 3]
obj1 = MyObject([1, 2])
obj2 = MyObject([3, 4])
obj3 = obj1 + obj2
print(obj3.items) # output: [1, 2, 3, 4]

obj4 = MyObject([1, 2, 3])
obj5 = MyObject([4, 5])
obj6 = MyObject([1, 2, 3])

print(obj1 == obj2) # output: False
print(obj1 == obj3) # output: True

print(obj1 < obj2) # output: False
print(obj2 < obj1) # output: True
built-in functions
  • what\'s len() in len(obj) ?

In the context of len(obj), len() is a built-in Python function that returns the length of an object.

The len() function can be applied to different types of objects in Python, such as strings, lists, tuples, dictionaries, and sets, and it returns the number of elements in the object.

For example, len("Hello") returns 5 because there are 5 characters in the string "Hello", and len([1, 2, 3]) returns 3 because there are 3 elements in the list [1, 2, 3].

In custom classes, the len() function can be used to retrieve the length of objects by implementing the __len__() special method, which should return an integer representing the length of the object.

  • more details about built-in Python functions
  1. print(): This function is used to print the specified message or object to the console. It can take multiple arguments, separated by commas, and can also use formatting to display variables and values.
  2. type(): This function returns the type of an object. It takes one argument and returns the type of that object.
  3. len(): This function returns the length of an object. It can be used with objects such as strings, lists, tuples, dictionaries, and sets.
  4. range(): This function generates a sequence of numbers, starting from a specified start value (by default 0), and incrementing by a specified step value (by default 1), up to but not including a specified stop value.
  5. input(): This function is used to get input from the user via the console. It takes one optional argument, which is the prompt to display to the user, and returns a string containing the user\'s input.
  6. int(), float(), str(): These functions are used to convert values from one type to another. int() converts a value to an integer, float() converts a value to a floating-point number, and str() converts a value to a string.
  7. max(), min(): These functions are used to find the maximum or minimum value in a sequence. They can be used with objects such as lists, tuples, and sets.
  8. sum(): This function is used to find the sum of all the values in a sequence. It can be used with objects such as lists, tuples, and sets.
  9. sorted(): This function is used to sort a sequence in ascending order. It can be used with objects such as lists, tuples, and sets.
  10. zip(): This function is used to combine two or more sequences into a single sequence of tuples. It takes two or more arguments and returns a zip object containing tuples of elements from the input sequences.

These are just a few examples of the built-in Python functions. Python has many more built-in functions that can be used to perform a variety of tasks, such as manipulating strings, performing mathematical calculations, working with files and directories, and more.

python 面向对象专题:元类type反射函数与类的区别特殊的双下方法

 

1. 元类type

  • type:获取对象从属的类

    Python中一切皆对象,类在某种意义上也是一个对象

    Python中自己定义的类,以及大部分内置类,都是由type元类(构建类)实例化得来的

    # type 获取对象从属于的类
    print(type(A))
    print(type(str))
    print(type(dict))
  • type与object的关系:

    object类是type类的一个实例 print(type(object))
    object类是type类的父类 print(issubclass(type,object))

2. 反射

  • 定义:通过字符串操作对象的方式,程序对自己内部代码的一种自省方式

  • 内置函数:hasattr getattr setattr delattr (attr 是属性的意思)

  • 反射可以作用的对象:实例对象,类,本模块,其他模块

    从对象角度应用反射

    class A:
        country = \'中国\'
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def func(self):
            print(\'in A func\')
    obj = A(\'张三\',66)
    
    # hasattr: 判断有无属性
    print(hasattr(obj,\'name\'))
    print(hasattr(obj,\'country\'))   # 报错
    print(hasattr(obj,\'func\'))   # 报错
    
    # getattr: 获取属性
    if hasattr(obj,\'name\'):
        getattr(obj,\'name\')
        
    # setattr: 设置属性/delattr: 删除属性
    setattr(obj,\'sex\',\'\')
    delattr(obj,\'name\')

     

    从类的角度应用反射

    class A:
        country = \'中国\'
        def __init__(self,name,age):
            self.name = name
            self.age = age
        def func(self):
            print(self)
            print(\'in A func\')
    
    if hasattr(A,\'func\'):
        obj = A(\'张三\', 26)
        getattr(obj,\'func\')()
        getattr(A,\'func\')(obj)

     

    从其他模块应用反射

    import tbjx
    
    # 1. 找到tbjx对象的C类,实例化一个对象.
    obj = getattr(tbjx,\'C\')(\'123\')
    
    # 2. 找到tbjx对象的C类,通过对C类这个对象使用反射取到area.
    print(getattr(tbjx.C,\'area\'))
    
    # 3. 找到tbjx对象的C类,实例化一个对象,对对象进行反射取值.
    obj = getattr(tbjx,\'C\')(\'张三\')
    print(obj.name)
    print(getattr(obj,\'name\'))

     

    从当前模块应用反射

    def func1():
        print(\'in func1\')
    
    def func2():
        print(\'in func2\')
    
    def func3():
        print(\'in func3\')
    
    def func4():
        print(\'in func4\')
    
    
    import sys
    print(sys.modules[__name__])
    getattr(sys.modules[__name__],\'func1\')()
    getattr(sys.modules[__name__],\'func2\')()
    getattr(sys.modules[__name__],\'func3\')()
    
    # 本模块的模块名:sys.modules[__name__]

     

  • 反射应用示例:

    class User:
        def login(self):
            print(\'欢迎来到登录页面\')
    
        def register(self):
            print(\'欢迎来到注册页面\')
    
        def save(self):
            print(\'欢迎来到存储页面\')
    
    choose_dic = {
        1: User.login,
        2: User.register,
        3: User.save,
    }
    
    while 1:
        choose = input(\'请输入序号: \\n1: 登录\\n2: 注册\\n3: 存储\').strip()
        obj = User()
        choose_dic[int(choose)](obj)

     

3. 函数与类的区别

  • 函数都是显性传参,方法都是隐形传参

    class A:
        @classmethod
        def func(cls,a):
            pass
        @staticmethod
        def func1():
            pass
    
    A.func(666)
    A.func()

     

  • 通过打印函数名的方式,区别什么是方法,什么是函数

    def func1():
        pass
    class A:
        def func(self):
            pass
    print(func1)
    print(A.func)
    obj = A()
    print(obj.func)
    
    # 结果:
    <function func1 at 0x000000A9C59C1EA0>
    <function A.func at 0x000000A9C75DE268>
    <bound method A.func of <__main__.A object at 0x000000A9C744D4A8>>

     

  • 可以借助模块判断类中的是方法还是函数

           

from types import FunctionType
from types import MethodType
def func():
    pass
class A:
    def func(self):
        pass
obj = A()
print(isinstance(func,FunctionType))  # True
print(isinstance(A.func,FunctionType))  # True
print(isinstance(obj.func,FunctionType))  # False
print(isinstance(obj.func,MethodType))  # True

 

4. 特殊的双下方法

  • 特殊的双下方法: 原本是开发python这个语言的程序员用的.源码中使用的,双下方法: 你不知道你干了什么就触发某个双下方法

    # 1.__len__   len(b)执行b类从属父类的__len__方法,必须要有return int(返回值)
    class B:
        def __init__(self,name,age):
            self.name = name
            self.age =age
        def __len__(self):
            return len(self.__dict__)  # 2
    b = B(\'张三\',28)
    print(len(b))
    
    
    # 2.__hash__  hash()触发__hash__双下方法
    class A(object):
        def __hash__(self):
            return 123456
    obj = A()
    print(hash(obj))
    
    
    # 3.__str__ 里边必须有return "字符串"类型  (优先级高于__repr__)
    #   -  打印对象的时候,会触发__str__方法
    #   -  str转化也可以触发
    class A:
        def __init__(self,name,age):
            self.name = name
            self.age =age
        def __str__(self):
            print(\'触发str方法\')
            return f\'姓名: {self.name} 年龄: {self.age}\'
    a = A(\'张三\',35)
    
    # 打印对象触发__str__方法
    print(f\'{a.name}  {a.age}\')
    print(a)
    
    # 直接str转化也可以触发.
    print(str(a))
    
    
    
    # 4.__repr__  里边必须有return "字符串"类型
    #   -  打印对象的时候,会触发__repr__方法
    class A:
        def __init__(self,name,age):
            self.name = name
            self.age =age
        def __repr__(self):
            print(666)
            return f\'姓名: {self.name} 年龄: {self.age}\'
    
    a = A(\'张三\',35)
    print(a)
    print(repr(a))
    
    
    # 5.__call__  对象()触发对象从属类(父类)的__call__方法
    class Foo:
        def __init__(self):
            pass
        def __call__(self, *args, **kwargs):
            print(\'__call__\')
    obj = Foo()
    obj()
    
    
    # 6.__eq__   两对象==时触发,return True/false(可以返回数字,字符串 一般返回布尔值)
    class A(object):
        def __init__(self):
            self.a = 1
            self.b = 2
    
        def __eq__(self,obj):
            print(\'__eq__\')
            return True
    x = A()
    y = A()
    print(x == y)
    
    
    # 7.__del__ 析构方法 回收对象时触发__del__方法
    class A:
        def __del__(self):
            print(\'__del__\')
    obj = A()
    del obj
    
    
    # 8.__new__  new一个对象(构造方法),实例化对象的时候会触发,对象是object类的__new__方法,产生了一个对象
    class A(object):
        def __init__(self):
            print(\'in init function\')
    
        def __new__(cls, *args, **kwargs):
            print(\'in new function\')
            return object.__new__(A)
    
    # 对象是object类的__new__方法 产生了一个对象.
    a = A()
    
    # 类名()
    # 1. 先触发 object的__new__方法,此方法在内存中开辟一个对象空间.
    # 2. 执行__init__方法,给对象封装属性.
    
    # def __init__(self):(不能写返回值,因为__new__已经有返回值了,不能同时接收两个返回值,只能接收__new__的返回值)
        
    
    
    # 9.__item__系列(4个)
    # __getitem__ __setitem___ __delitem__ 对对象做类似于字典的(增删改查)触发__item__系列
    class Foo:
        def __init__(self,name):
            self.name=name
    def __getitem__(self, item):
        # print(item)
        # print(666)
        return self.__dict__[item]
    
    def __setitem__(self, key, value):
        # self.__dict__[key]=value
        print(key)
        print(value)
    
    def __delitem__(self, key):
        print(\'del obj[key]时,我执行\')
    
    f1=Foo(\'zhangsan\')
    f1[\'age\']
    f1[1] = 2
    del f1[1]
    
    
    # 10.__enter__ __exit__  with 上下文管理(2个)
    class A:
    
        def __init__(self, text):
            self.text = text
    
        def __enter__(self):  # 开启上下文管理器对象时触发此方法
            self.text = self.text + \'您来啦\'  # 第一步
            print(11111)
            return self  # 必须!!!将实例化的对象返回f1
    
        def __exit__(self, exc_type, exc_val, exc_tb):  # 执行完上下文管理器对象f1时触发此方法
            print(333)  # 第三步
            self.text = self.text + \',这就走啦\'
    
    with A(\'大爷\') as f1:
        print(2222)
        print(f1.text)  # 第二步
    print(f1.text)  # 第四步
    
    
    
    # 11.__iter__  for循环会触发此方法
    class A:
        def __init__(self,name):
            self.name = name
    
        def __iter__(self):
            for i in range(10):
                yield i
    
    obj = A(\'张三\')
    for i in obj:
        print(i)
    
    # 12.__getattr__(self,item),__setattr__(self,key,value),__delattr__ 
    #   obj.属性会触发__getattr__(self,item)方法
    #   obj.属性=123 会触发__setattr__(self,key,value)   
    #   del obj.属性 就会触发__delattr__ 此方法

     

  • def func1():
        pass
    class A:
        def func(self):
            pass
    print(func1)
    print(A.func)
    obj = A()
    print(obj.func)
    
    # 结果:
    <function func1 at 0x000000A9C59C1EA0>
    <function A.func at 0x000000A9C75DE268>
    <bound method A.func of <__main__.A object at 0x000000A9C744D4A8>>
    

以上是关于Python中,类的特殊方法与内置函数的关联的主要内容,如果未能解决你的问题,请参考以下文章

python 面向对象专题:元类type反射函数与类的区别特殊的双下方法

python基础类的特殊成员(类的特殊内置属性和方法)

面向对象结构与成员(特殊成员)及相关内置函数

Python Qt GUI设计入门自建信号与槽函数关联

python类和函数拾遗——继承bif(内置函数)魔法方法

4.1.7 特殊方法与运算符重载