Python面向對象(二)

1.成員

面向對象中的全部成員以下:html

  • 變量
    • 實例變量
    • 類變量
  • 方法
    • 綁定方法
    • 類方法
    • 靜態方法
  • 屬性

經過面向對象進行編程時,會遇到不少種狀況,也會使用不一樣的成員來實現,接下來咱們來逐一介紹成員特性和應用場景。java

1.1 變量

  • 實例變量,屬於對象,每一個對象中各自維護本身的數據。
  • 類變量,屬於類,能夠被全部對象共享,通常用於給對象提供公共數據(相似於全局變量)。
class Person(object):
    country = "中國"

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

    def show(self):
        # message = "{}-{}-{}".format(Person.country, self.name, self.age)
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)

print(Person.country) # 中國


p1 = Person("dean",20)
print(p1.name)
print(p1.age)
print(p1.country) # 中國

p1.show() # 中國-dean-20

提示:當把每一個對象中都存在的相同的示例變量時,能夠選擇把它放在類變量中,這樣就能夠避免對象中維護多個相同數據。python

易錯點

第一題:注意讀和寫的區別。面試

class Person(object):
    country = "中國"

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

    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)

print(Person.country) # 中國

p1 = Person("dean",20)
print(p1.name) # dean
print(p1.age) # 20
print(p1.country) # 中國
p1.show() # 中國-dean-20

p1.name = "root"     # 在對象p1中講name重置爲root
p1.num = 19          # 在對象p1中新增實例變量 num=19
p1.country = "china" # 在對象p1中新增實例變量 country="china"

print(p1.country)   # china
print(Person.country) # 中國
class Person(object):
    country = "中國"

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

    def show(self):
        message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)

print(Person.country) # 中國

Person.country = "美國"


p1 = Person("dean",20)
print(p1.name) # dean
print(p1.age) # 20
print(p1.country) # 美國

第二題:繼承關係中的讀寫數據庫

class Base(object):
    country = "中國"


class Person(Base):

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

    def show(self):
        message = "{}-{}-{}".format(Person.country, self.name, self.age)
        # message = "{}-{}-{}".format(self.country, self.name, self.age)
        print(message)


# 讀
print(Base.country) # 中國
print(Person.country) # 中國

obj = Person("dean",19)
print(obj.country) # 中國

# 寫
Base.country = "china"
Person.country = "泰國"
obj.country = "日本"

面試題編程

class Parent(object):
    x = 1


class Child1(Parent):
    pass


class Child2(Parent):
    pass


print(Parent.x, Child1.x, Child2.x) # 1 1 1

Child1.x = 2
print(Parent.x, Child1.x, Child2.x) # 1 2 1

Parent.x = 3
print(Parent.x, Child1.x, Child2.x) # 3 2 3

1.2 方法

  • 綁定方法,默認有一個self參數,由對象進行調用(此時self就等於調用方法的這個對象)【對象&類都可調用】
  • 類方法,默認有一個cls參數,用類或對象均可以調用(此時cls就等於調用方法的這個類)【對象&類都可調用】
  • 靜態方法,無默認參數,用類和對象均可以調用。【對象&類都可調用】
class Foo(object):

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

    def f1(self):
        print("綁定方法", self.name)

    @classmethod
    def f2(cls):
        print("類方法", cls)

    @staticmethod
    def f3():
        print("靜態方法")
        
# 綁定方法(對象)
obj = Foo("dean",20)
obj.f1() # Foo.f1(obj)


# 類方法
Foo.f2()  # cls就是當前調用這個方法的類。(類)
obj.f2()  # cls就是當前調用這個方法的對象的類。


# 靜態方法
Foo.f3()  # 類執行執行方法(類)
obj.f3()  # 對象執行執行方法

在Python中比較靈活,方法均可以經過對象和類進行調用;而在java、c#等語言中,綁定方法只能由對象調用;類方法或靜態方法只能由類調用。c#

import os
import requests


class Download(object):

    def __init__(self, folder_path):
        self.folder_path = folder_path

    @staticmethod
    def download_dou_yin():
        # 下載抖音
        res = requests.get('.....')

        with open("xxx.mp4", mode='wb') as f:
            f.write(res.content)

    def download_dou_yin_2(self):
        # 下載抖音
        res = requests.get('.....')
        path = os.path.join(self.folder_path, 'xxx.mp4')
        with open(path, mode='wb') as f:
            f.write(res.content)


obj = Download("video")
obj.download_dou_yin()

1.3 屬性

屬性實際上是由綁定方法 + 特殊裝飾器 組合創造出來的,讓咱們之後在調用方法時能夠不加括號,例如:app

class Foo(object):

    def __init__(self, name):
        self.name = name

    def f1(self):
        return 123

    @property
    def f2(self):
        return 123


obj = Foo("dean")

v1 = obj.f1()
print(v1)

v2 = obj.f2
print(v2)

示例:以以前開發的分頁的功能。ide

class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num
        
        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page
	
    def start(self):
        return (self.current_page - 1) * self.per_page_num
	
    def end(self):
        return self.current_page * self.per_page_num


user_list = ["用戶-{}".format(i) for i in range(1, 3000)]

# 分頁顯示,每頁顯示10條
while True:
    page = input("請輸入頁碼:")
	
    # page,當前訪問的頁碼
    # 10,每頁顯示10條數據
	# 內部執行Pagination類的init方法。
    pg_object = Pagination(page, 20)
    
    page_data_list = user_list[ pg_object.start() : pg_object.end() ]
    for item in page_data_list:
        print(item)
class Pagination:
    def __init__(self, current_page, per_page_num=10):
        self.per_page_num = per_page_num

        if not current_page.isdecimal():
            self.current_page = 1
            return
        current_page = int(current_page)
        if current_page < 1:
            self.current_page = 1
            return
        self.current_page = current_page

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num


user_list = ["用戶-{}".format(i) for i in range(1, 3000)]

# 分頁顯示,每頁顯示10條
while True:
    page = input("請輸入頁碼:")

    pg_object = Pagination(page, 20)
    page_data_list = user_list[ pg_object.start : pg_object.end ]
    
    for item in page_data_list:
        print(item)

關於屬性的編寫有兩種方式:函數

  • 方式一,基於裝飾器

    class C(object):
        
        @property
        def x(self):
            pass
        
        @x.setter
        def x(self, value):
            pass
        
        @x.deleter
        def x(self):
    		pass
            
    obj = C()
    
    obj.x
    obj.x = 123
    del obj.x
  • 方式二,基於定義變量

    class C(object):
        
        def getx(self): 
    		pass
        
        def setx(self, value): 
    		pass
            
        def delx(self): 
    		pass
            
        x = property(getx, setx, delx, "I'm the 'x' property.")
        
    obj = C()
    
    obj.x
    obj.x = 123
    del obj.x

因爲屬性和實例變量的調用方式相同,因此在編寫時須要注意:屬性名稱 不要 實例變量 重名。

class Foo(object):

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

    @property
    def func(self):
        return 123


obj = Foo("dean", 123)
print(obj.name)
print(obj.func)

一旦重名,可能就會有報錯。

class Foo(object):

    def __init__(self, name, age):
        self.name = name  # 報錯,錯認爲你想要調用 @name.setter 裝飾的方法。
        self.age = age

    @property
    def name(self):
        return "{}-{}".format(self.name, self.age)


obj = Foo("dean", 123)
class Foo(object):

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

    @property
    def name(self):
        return "{}-{}".format(self.name, self.age) # 報錯,循環調用本身(直到層級太深報錯)

    @name.setter
    def name(self, value):
        print(value)


obj = Foo("dean", 123)
print(obj.name)

若是真的想要在名稱上建立一些關係,可讓實例變量加上一個下劃線。

class Foo(object):

    def __init__(self, name, age):
        self._name = name
        self.age = age

    @property
    def name(self):
        return "{}-{}".format(self._name, self.age)


obj = Foo("dean", 123)
print(obj._name)
print(obj.name)

2.成員修飾符

Python中成員的修飾符就是指的是:公有、私有。

  • 公有,在任何地方均可以調用這個成員。
  • 私有,只有在類的內部才能夠調用改爲員(成員是以兩個下劃線開頭,則表示該成員爲私有)。

示例一:

class Foo(object):

    def __init__(self, name, age):
        self.__name = name
        self.age = age

    def get_data(self):
        return self.__name

    def get_age(self):
        return self.age


obj = Foo("dean", 123)


# 公有成員
print(obj.age)
v1 = self.get_age()
print(v1)

# 私有成員
# print(obj.__name) # 錯誤,因爲是私有成員,只能在類中進行使用。
v2 = obj.get_data()
print(v2)

示例2:

class Foo(object):

    def get_age(self):
        print("公有的get_age")

    def __get_data(self):
        print("私有的__get_data方法")

    def proxy(self):
        print("公有的proxy")
        self.__get_data()


obj = Foo()
obj.get_age()

obj.proxy()

示例3:

class Foo(object):

    @property
    def __name(self):
        print("公有的get_age")

    @property
    def proxy(self):
        print("公有的proxy")
        self.__name
        return 1


obj = Foo()
v1 = obj.proxy
print(v1)

特別提醒:父類中的私有成員,子類沒法繼承。

class Base(object):

    def __data(self):
        print("base.__data")

    def num(self):
        print("base.num")


class Foo(Base):

    def func(self):
        self.num()
        self.__data() # # 不容許執行父類中的私有方法


obj = Foo()
obj.func()
class Base(object):

    def __data(self):
        print("base.__data")

    def num(self):
        print("base.num")
        self.__data()  # 不容許執行父類中的私有方法


class Foo(Base):

    def func(self):
        self.num()


obj = Foo()
obj.func()

按理說私有成員是沒法被外部調用,但若是用一些特殊的語法也能夠(不推薦這樣寫)

class Foo(object):

    def __init__(self):
        self.__num = 123
        self.age = 19

    def __msg(self):
        print(1234)


obj = Foo()
print(obj.age)
print(obj._Foo__num)
obj._Foo__msg()

成員是否能夠做爲獨立的功能暴露給外部,讓外部調用並使用。

  • 能夠,公有。
  • 不能夠,內部其餘放的一個輔助,私有。

3.對象嵌套

在基於面向對象進行編程時,對象之間能夠存在各類各樣的關係,例如:組合、關聯、依賴等

下面咱們就用示例來學習常見的嵌套的情景:

情景一:

class Student(object):
    """ 學生類 """

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

    def message(self):
        data = "我是一名學生,我叫:{},我今年{}歲".format(self.name, self.age)
        print(data)

s1 = Student("dean", 19)
s2 = Student("sam", 19)
s3 = Student("gabral", 19)



class Classes(object):
    """ 班級類 """

    def __init__(self, title):
        self.title = title
        self.student_list = []

    def add_student(self, stu_object):
        self.student_list.append(stu_object)

    def add_students(self, stu_object_list):
        for stu in stu_object_list:
            self.add_student(stu)

    def show_members(self):
        for item in self.student_list:
            # print(item)
            item.message()

c1 = Classes("三年二班")
c1.add_student(s1)
c1.add_students([s2, s3])

print(c1.title)
print(c1.student_list)

情景二:

class Student(object):
    """ 學生類 """

    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object

    def message(self):
        data = "我是一名{}班的學生,我叫:{},我今年{}歲".format(self.class_object.title, self.name, self.age)
        print(data)


class Classes(object):
    """ 班級類 """

    def __init__(self, title):
        self.title = title


c1 = Classes("Python")
c2 = Classes("Linux")

user_object_list = [
    Student("dean", 19, c1),
    Student("sam", 19, c1),
    Student("gabral", 19, c2)
]

for obj in user_object_list:
    print(obj.name,obj.age, obj.class_object.title)

情景三:

class Student(object):
    """ 學生類 """

    def __init__(self, name, age, class_object):
        self.name = name
        self.age = age
        self.class_object = class_object

    def message(self):
        data = "我是一名{}班的學生,我叫:{},我今年{}歲".format(self.class_object.title, self.name, self.age)
        print(data)


class Classes(object):
    """ 班級類 """

    def __init__(self, title, school_object):
        self.title = title
        self.school_object = school_object


class School(object):
    """ 學校類 """

    def __init__(self, name):
        self.name = name


s1 = School("北京")
s2 = School("上海")

c1 = Classes("Python", s1)
c2 = Classes("Linux", s2)

user_object_list = [
    Student("dean", 19, c1),
    Student("sam", 19, c1),
    Student("gabral", 19, c2)
]
for obj in user_object_list:
    print(obj.name, obj.class_object.title ,  obj.class_object.school_object.name)

4.特殊成員

在Python的類中存在一些特殊的方法,這些方法都是 __方法__ 格式,這種方法在內部均有特殊的含義,接下來咱們來說一些常見的特殊成員:

  • __init__,初始化方法

    class Foo(object):
        def __init__(self, name):
            self.name = name
    
    
    obj = Foo("dean")
  • __new__,構造方法

    class Foo(object):
        def __init__(self, name):
            print("第二步:初始化對象,在空對象中建立數據")
            self.name = name
    
        def __new__(cls, *args, **kwargs):
            print("第一步:先建立空對象並返回")
            return object.__new__(cls)
    
    
    obj = Foo("dean")
  • __call__

    class Foo(object):
        def __call__(self, *args, **kwargs):
            print("執行call方法")
    
    
    obj = Foo()
    obj()
  • __str__

    class Foo(object):
    
        def __str__(self):
            return "哈哈哈哈"
    
    
    obj = Foo()
    data = str(obj)
    print(data)
  • __dict__

    class Foo(object):
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
    
    obj = Foo("dean",19)
    print(obj.__dict__)
  • __getitem____setitem____delitem__

    class Foo(object):
    
        def __getitem__(self, item):
            pass
    
        def __setitem__(self, key, value):
            pass
    
        def __delitem__(self, key):
            pass
    
    
    obj = Foo("dean", 19)
    
    obj["x1"]
    obj['x2'] = 123
    del obj['x3']
  • __enter____exit__

    class Foo(object):
    
        def __enter__(self):
            print("進入了")
            return 666
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            print("出去了")
    
    
    obj = Foo()
    with obj as data:
        print(data)
    超前知識:數據鏈接,每次對遠程的數據進行操做時候都必須經歷。
    1.鏈接 = 鏈接數據庫
    2.操做數據庫
    3.關閉鏈接
    class SqlHelper(object):
    
        def __enter__(self):
            self.鏈接 = 鏈接數據庫
            return 鏈接
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.鏈接.關閉
    
            
            
    with SqlHelper() as 鏈接:
        鏈接.操做..
        
        
    with SqlHelper() as 鏈接:
        鏈接.操做...
    # 面試題(補充代碼,實現以下功能)
    
    class Context:
        
        def do_something(self):
            print('內部執行')
    	def __enter__(self):
            self.do_something()
        def __exit__(self):
            
            
    
    with Context() as ctx:
        print('內部執行')
        ctx.do_something()

    上下文管理的語法。

  • __add__ 等。

    class Foo(object):
        def __init__(self, name):
            self.name = name
    
        def __add__(self, other):
            return "{}-{}".format(self.name, other.name)
    
    
    v1 = Foo("sam")
    v2 = Foo("sb")
    
    # 對象+值,內部會去執行 對象.__add__方法,並將+後面的值當作參數傳遞過去。
    v3 = v1 + v2
    print(v3)
  • __iter__

    • 迭代器

      # 迭代器類型的定義:
          1.當類中定義了 __iter__ 和 __next__ 兩個方法。
          2.__iter__ 方法須要返回對象自己,即:self
          3. __next__ 方法,返回下一個數據,若是沒有數據了,則須要拋出一個StopIteration的異常。
      	官方文檔:https://docs.python.org/3/library/stdtypes.html#iterator-types
              
      # 建立 迭代器類型 :
      	class IT(object):
              def __init__(self):
                  self.counter = 0
      
              def __iter__(self):
                  return self
      
              def __next__(self):
                  self.counter += 1
                  if self.counter == 3:
                      raise StopIteration()
                  return self.counter
      
      # 根據類實例化建立一個迭代器對象:
          obj1 = IT()
          
          # v1 = obj1.__next__()
          # v2 = obj1.__next__()
          # v3 = obj1.__next__() # 拋出異常
          
          v1 = next(obj1) # obj1.__next__()
          print(v1)
      
          v2 = next(obj1)
          print(v2)
      
          v3 = next(obj1)
          print(v3)
      
      
          obj2 = IT()
          for item in obj2:  # 首先會執行迭代器對象的__iter__方法並獲取返回值,一直去反覆的執行 next(對象) 
              print(item)
              
      迭代器對象支持經過next取值,若是取值結束則自動拋出StopIteration。
      for循環內部在循環時,先執行__iter__方法,獲取一個迭代器對象,而後不斷執行的next取值(有異常StopIteration則終止循環)。
    • 生成器

      # 建立生成器函數
          def func():
              yield 1
              yield 2
          
      # 建立生成器對象(內部是根據生成器類generator建立的對象),生成器類的內部也聲明瞭:__iter__、__next__ 方法。
          obj1 = func()
          
          v1 = next(obj1)
          print(v1)
      
          v2 = next(obj1)
          print(v2)
      
          v3 = next(obj1)
          print(v3)
      
      
          obj2 = func()
          for item in obj2:
              print(item)
      
      若是按照迭代器的規定來看,其實生成器類也是一種特殊的迭代器類(生成器也是一箇中特殊的迭代器)。
    • 可迭代對象

      # 若是一個類中有__iter__方法且返回一個迭代器對象 ;則咱們稱以這個類建立的對象爲可迭代對象。
      
      class Foo(object):
          
          def __iter__(self):
              return 迭代器對象(生成器對象)
          
      obj = Foo() # obj是 可迭代對象。
      
      # 可迭代對象是可使用for來進行循環,在循環的內部實際上是先執行 __iter__ 方法,獲取其迭代器對象,而後再在內部執行這個迭代器對象的next功能,逐步取值。
      for item in obj:
          pass
      class IT(object):
          def __init__(self):
              self.counter = 0
      
          def __iter__(self):
              return self
      
          def __next__(self):
              self.counter += 1
              if self.counter == 3:
                  raise StopIteration()
              return self.counter
      
      
      class Foo(object):
          def __iter__(self):
              return IT()
      
      
      obj = Foo() # 可迭代對象
      
      
      for item in obj: # 循環可迭代對象時,內部先執行obj.__iter__並獲取迭代器對象;不斷地執行迭代器對象的next方法。
          print(item)
      # 基於可迭代對象&迭代器實現:自定義range
      class IterRange(object):
          def __init__(self, num):
              self.num = num
              self.counter = -1
      
          def __iter__(self):
              return self
      
          def __next__(self):
              self.counter += 1
              if self.counter == self.num:
                  raise StopIteration()
              return self.counter
      
      
      class Xrange(object):
          def __init__(self, max_num):
              self.max_num = max_num
      
          def __iter__(self):
              return IterRange(self.max_num)
      
      
      obj = Xrange(100)
      
      for item in obj:
          print(item)
      class Foo(object):
          def __iter__(self):
              yield 1
              yield 2
      
      
      obj = Foo()
      for item in obj:
          print(item)
      # 基於可迭代對象&生成器 實現:自定義range
      
      class Xrange(object):
          def __init__(self, max_num):
              self.max_num = max_num
      
          def __iter__(self):
              counter = 0
              while counter < self.max_num:
                  yield counter
                  counter += 1
      
      
      obj = Xrange(100)
      for item in obj:
          print(item)

      常見的數據類型:

      v1 = list([11,22,33,44])
      
      v1是一個可迭代對象,由於在列表中聲明瞭一個 __iter__ 方法而且返回一個迭代器對象。
      from collections.abc import Iterator, Iterable
      
      v1 = [11, 22, 33]
      print( isinstance(v1, Iterator) )  # false,判斷是不是迭代器;判斷依據是__iter__ 和 __next__。
      v2 = v1.__iter__()
      print( isinstance(v2, Iterator) )  # True
      
      
      
      v1 = [11, 22, 33]
      print( isinstance(v1, Iterable) )  # True,判斷依據是是否有 __iter__且返回迭代器對象。
      
      v2 = v1.__iter__()
      print( isinstance(v2, Iterable) )  # True,判斷依據是是否有 __iter__且返回迭代器對象。
相關文章
相關標籤/搜索